Flutter Engine
The Flutter Engine
SkTLazy.h
Go to the documentation of this file.
1/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef SkTLazy_DEFINED
9#define SkTLazy_DEFINED
10
12
13#include <optional>
14#include <utility>
15
16/**
17 * Efficient way to defer allocating/initializing a class until it is needed
18 * (if ever).
19 */
20template <typename T> class SkTLazy {
21public:
22 SkTLazy() = default;
23 explicit SkTLazy(const T* src) : fValue(src ? std::optional<T>(*src) : std::nullopt) {}
24 SkTLazy(const SkTLazy& that) : fValue(that.fValue) {}
25 SkTLazy(SkTLazy&& that) : fValue(std::move(that.fValue)) {}
26
27 ~SkTLazy() = default;
28
29 SkTLazy& operator=(const SkTLazy& that) {
30 fValue = that.fValue;
31 return *this;
32 }
33
35 fValue = std::move(that.fValue);
36 return *this;
37 }
38
39 /**
40 * Return a pointer to an instance of the class initialized with 'args'.
41 * If a previous instance had been initialized (either from init() or
42 * set()) it will first be destroyed, so that a freshly initialized
43 * instance is always returned.
44 */
45 template <typename... Args> T* init(Args&&... args) {
46 fValue.emplace(std::forward<Args>(args)...);
47 return this->get();
48 }
49
50 /**
51 * Copy src into this, and return a pointer to a copy of it. Note this
52 * will always return the same pointer, so if it is called on a lazy that
53 * has already been initialized, then this will copy over the previous
54 * contents.
55 */
56 T* set(const T& src) {
57 fValue = src;
58 return this->get();
59 }
60
61 T* set(T&& src) {
62 fValue = std::move(src);
63 return this->get();
64 }
65
66 /**
67 * Destroy the lazy object (if it was created via init() or set())
68 */
69 void reset() {
70 fValue.reset();
71 }
72
73 /**
74 * Returns true if a valid object has been initialized in the SkTLazy,
75 * false otherwise.
76 */
77 bool isValid() const { return fValue.has_value(); }
78
79 /**
80 * Returns the object. This version should only be called when the caller
81 * knows that the object has been initialized.
82 */
83 T* get() {
84 SkASSERT(fValue.has_value());
85 return &fValue.value();
86 }
87 const T* get() const {
88 SkASSERT(fValue.has_value());
89 return &fValue.value();
90 }
91
92 T* operator->() { return this->get(); }
93 const T* operator->() const { return this->get(); }
94
96 SkASSERT(fValue.has_value());
97 return *fValue;
98 }
99 const T& operator*() const {
100 SkASSERT(fValue.has_value());
101 return *fValue;
102 }
103
104 /**
105 * Like above but doesn't assert if object isn't initialized (in which case
106 * nullptr is returned).
107 */
108 const T* getMaybeNull() const { return fValue.has_value() ? this->get() : nullptr; }
109 T* getMaybeNull() { return fValue.has_value() ? this->get() : nullptr; }
110
111private:
112 std::optional<T> fValue;
113};
114
115/**
116 * A helper built on top of std::optional to do copy-on-first-write. The object is initialized
117 * with a const pointer but provides a non-const pointer accessor. The first time the
118 * accessor is called (if ever) the object is cloned.
119 *
120 * In the following example at most one copy of constThing is made:
121 *
122 * SkTCopyOnFirstWrite<Thing> thing(&constThing);
123 * ...
124 * function_that_takes_a_const_thing_ptr(thing); // constThing is passed
125 * ...
126 * if (need_to_modify_thing()) {
127 * thing.writable()->modifyMe(); // makes a copy of constThing
128 * }
129 * ...
130 * x = thing->readSomething();
131 * ...
132 * if (need_to_modify_thing_now()) {
133 * thing.writable()->changeMe(); // makes a copy of constThing if we didn't call modifyMe()
134 * }
135 *
136 * consume_a_thing(thing); // could be constThing or a modified copy.
137 */
138template <typename T>
140public:
141 explicit SkTCopyOnFirstWrite(const T& initial) : fObj(&initial) {}
142
143 explicit SkTCopyOnFirstWrite(const T* initial) : fObj(initial) {}
144
145 // Constructor for delayed initialization.
146 SkTCopyOnFirstWrite() : fObj(nullptr) {}
147
148 SkTCopyOnFirstWrite(const SkTCopyOnFirstWrite& that) { *this = that; }
149 SkTCopyOnFirstWrite( SkTCopyOnFirstWrite&& that) { *this = std::move(that); }
150
152 fLazy = that.fLazy;
153 fObj = fLazy.has_value() ? &fLazy.value() : that.fObj;
154 return *this;
155 }
156
158 fLazy = std::move(that.fLazy);
159 fObj = fLazy.has_value() ? &fLazy.value() : that.fObj;
160 return *this;
161 }
162
163 // Should only be called once, and only if the default constructor was used.
164 void init(const T& initial) {
165 SkASSERT(!fObj);
166 SkASSERT(!fLazy.has_value());
167 fObj = &initial;
168 }
169
170 // If not already initialized, in-place instantiates the writable object
171 template <typename... Args>
172 void initIfNeeded(Args&&... args) {
173 if (!fObj) {
174 SkASSERT(!fLazy.has_value());
175 fObj = &fLazy.emplace(std::forward<Args>(args)...);
176 }
177 }
178
179 /**
180 * Returns a writable T*. The first time this is called the initial object is cloned.
181 */
183 SkASSERT(fObj);
184 if (!fLazy.has_value()) {
185 fLazy = *fObj;
186 fObj = &fLazy.value();
187 }
188 return &fLazy.value();
189 }
190
191 const T* get() const { return fObj; }
192
193 /**
194 * Operators for treating this as though it were a const pointer.
195 */
196
197 const T *operator->() const { return fObj; }
198
199 operator const T*() const { return fObj; }
200
201 const T& operator *() const { return *fObj; }
202
203private:
204 const T* fObj;
205 std::optional<T> fLazy;
206};
207
208#endif
#define SkASSERT(cond)
Definition: SkAssert.h:116
SkTCopyOnFirstWrite & operator=(SkTCopyOnFirstWrite &&that)
Definition: SkTLazy.h:157
void initIfNeeded(Args &&... args)
Definition: SkTLazy.h:172
const T * get() const
Definition: SkTLazy.h:191
SkTCopyOnFirstWrite & operator=(const SkTCopyOnFirstWrite &that)
Definition: SkTLazy.h:151
SkTCopyOnFirstWrite(const SkTCopyOnFirstWrite &that)
Definition: SkTLazy.h:148
const T * operator->() const
Definition: SkTLazy.h:197
SkTCopyOnFirstWrite(SkTCopyOnFirstWrite &&that)
Definition: SkTLazy.h:149
SkTCopyOnFirstWrite(const T *initial)
Definition: SkTLazy.h:143
const T & operator*() const
Definition: SkTLazy.h:201
SkTCopyOnFirstWrite(const T &initial)
Definition: SkTLazy.h:141
void init(const T &initial)
Definition: SkTLazy.h:164
const T * operator->() const
Definition: SkTLazy.h:93
SkTLazy(SkTLazy &&that)
Definition: SkTLazy.h:25
const T * get() const
Definition: SkTLazy.h:87
T * init(Args &&... args)
Definition: SkTLazy.h:45
T * set(T &&src)
Definition: SkTLazy.h:61
SkTLazy(const SkTLazy &that)
Definition: SkTLazy.h:24
T * operator->()
Definition: SkTLazy.h:92
T & operator*()
Definition: SkTLazy.h:95
const T & operator*() const
Definition: SkTLazy.h:99
SkTLazy & operator=(const SkTLazy &that)
Definition: SkTLazy.h:29
SkTLazy & operator=(SkTLazy &&that)
Definition: SkTLazy.h:34
T * get()
Definition: SkTLazy.h:83
SkTLazy()=default
~SkTLazy()=default
void reset()
Definition: SkTLazy.h:69
SkTLazy(const T *src)
Definition: SkTLazy.h:23
T * getMaybeNull()
Definition: SkTLazy.h:109
bool isValid() const
Definition: SkTLazy.h:77
const T * getMaybeNull() const
Definition: SkTLazy.h:108
T * set(const T &src)
Definition: SkTLazy.h:56
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
Definition: ref_ptr.h:256
#define T
Definition: precompiler.cc:65