FastLED 3.9.15
Loading...
Searching...
No Matches
ptr.h
Go to the documentation of this file.
1
2#pragma once
3
4#include <stddef.h>
5
6// FastLED smart pointer.
7//
8// * Make your subclasses inherit from fl::Referent.
9// * `class Foo: public fl::Referent {};`
10// * Use a macro to declare your smart pointer.
11// * For regular, non-template classes:
12// * `FASTLED_SMART_PTR(Foo)` -> `FooPtr` is now available.
13// * For templates use `FASTLED_SMART_PTR_NO_FWD(Foo)`
14// * `template <typename T> class Foo {}; using FooInt = Foo<int>;`
15// * `FASTLED_SAMRT_PTR_NO_FWD(FooInt)`
16// * `FooIntPtr` is now available.
17// * Instantiate from heap
18// * `FooPtr foo = NewPtr<Foo>(a, b, ...args);`
19// * Use `foo->method()` to call methods.
20// * Instantiate from stack object and disable tracking
21// * `Foo foo; FooPtr fooPtr = FooPtr::NoTracking(foo);`
23
24#include "fl/namespace.h"
25#include "fl/scoped_ptr.h"
26#include "fl/template_magic.h"
27
28// Declares a smart pointer. FASTLED_SMART_PTR(Foo) will declare a class FooPtr
29// which will be a typedef of Ptr<Foo>. After this FooPtr::New(...args) can be
30// used to create a new instance of Ptr<Foo>.
31#define FASTLED_SMART_PTR(type) \
32 class type; \
33 using type##Ptr = fl::Ptr<type>;
34
35#define FASTLED_SMART_PTR_STRUCT(type) \
36 class type; \
37 using type##Ptr = fl::Ptr<type>;
38
39#define FASTLED_SMART_PTR_NO_FWD(type) using type##Ptr = fl::Ptr<type>;
40
41// If you have an interface class that you want to create a smart pointer for,
42// then you need to use this to bind it to a constructor.
43#define FASTLED_SMART_PTR_CONSTRUCTOR(type, constructor) \
44 template <> class PtrTraits<type> { \
45 public: \
46 template <typename... Args> static Ptr<type> New(Args... args) { \
47 fl::Ptr<type> ptr = constructor(args...); \
48 return ptr; \
49 } \
50 };
51
52namespace fl {
53
54class Referent; // Inherit this if you want your object to be able to go into a
55 // Ptr, or WeakPtr.
56template <typename T> class Ptr; // Reference counted smart pointer base class.
57template <typename T> class WeakPtr; // Weak reference smart pointer base class.
58
59template <typename T, typename... Args> Ptr<T> NewPtr(Args... args);
60
61template <typename T, typename... Args> Ptr<T> NewPtrNoTracking(Args... args);
62
63template <typename T> class PtrTraits {
64 public:
65 using element_type = T;
67
68 template <typename... Args> static Ptr<T> New(Args... args) {
69 T *ptr = new T(args...);
70 return Ptr<T>::TakeOwnership(ptr);
71 }
72
73 static Ptr<T> New() {
74 T *ptr = new T();
75 return Ptr<T>::TakeOwnership(ptr);
76 }
77};
78
79// Ptr is a reference-counted smart pointer that manages the lifetime of an
80// object.
81//
82// It will work with any class implementing ref(), unref() and destroy().
83//
84// Please note that this Ptr class is "sticky" to it's referent, that is, no
85// automatic conversion from raw pointers to Ptr or vice versa is allowed and
86// must be done explicitly, see the Ptr::TakeOwnership() and Ptr::NoTracking()
87// methods.
88//
89// To create a Ptr to a concrete object, it's best to use FASTLED_SMART_PTR(Foo)
90// and then use FooPtr::New(...) to create a new instance of Ptr<Foo>.
91//
92// To create a Ptr of an interface bound to a subclass (common for driver code
93// or when hiding implementation) use the Ptr<InterfaceClass>::TakeOwnership(new
94// Subclass()) method.
95//
96// For objects created statically, use Ptr<Referent>::NoTracking(referent) to
97// create a Ptr, as this will disable reference tracking but still allow it to
98// be used as a Ptr.
99//
100// Example:
101// FASTLED_SMART_PTR(Foo);
102// class Foo: public fl::Referent {};
103// FooPtr foo = FooPtr::New();
104//
105// Example 2: (Manual binding to constructor)
106// class FooSubclass: public Foo {};
107// Ptr<Foo> bar = Ptr<FooSubclass>::TakeOwnership(new FooSubclass());
108//
109// Example 3: (Provide your own constructor so that FooPtr::New() works to
110// create a FooSubclass)
111// class FooSubclass: public Foo { // Foo is an interface, FooSubclass is an
112// implementation.
113// public:
114// static FooPtr New(int a, int b);
115// };
116// FASTLED_SMART_PTR_CONSTRUCTOR(Foo, FooSubclass::New);
117// FooPtr foo = FooPtr::New(1, 2); // this will now work.
118template <typename T> class Ptr : public PtrTraits<T> {
119 public:
120 friend class PtrTraits<T>;
121
122 template <typename... Args> static Ptr<T> New(Args... args) {
123 return PtrTraits<T>::New(args...);
124 }
125 // Used for low level allocations, typically for pointer to an
126 // implementation where it needs to convert to a Ptr of a base class.
127 static Ptr TakeOwnership(T *ptr) { return Ptr(ptr, true); }
128
129 // Used for low level allocations, typically to handle memory that is
130 // statically allocated where the destructor should not be called when
131 // the refcount reaches 0.
132 static Ptr NoTracking(T &referent) { return Ptr(&referent, false); }
133
134 static Ptr Null() { return Ptr<T>(); }
135
136 // Allow upcasting of Refs.
137 template <typename U, typename = fl::is_derived<T, U>>
138 Ptr(const Ptr<U> &refptr) : referent_(refptr.get()) {
139 if (referent_ && isOwned()) {
140 referent_->ref();
141 }
142 }
143
144 Ptr() : referent_(nullptr) {}
145
146 // Forbidden to convert a raw pointer to a Referent into a Ptr, because
147 // it's possible that the raw pointer comes from the stack or static memory.
148 Ptr(T *referent) = delete;
149 Ptr &operator=(T *referent) = delete;
150
151 Ptr(const Ptr &other) : referent_(other.referent_) {
152 if (referent_ && isOwned()) {
153 referent_->ref();
154 }
155 }
156
157 Ptr(Ptr &&other) noexcept : referent_(other.referent_) {
158 other.referent_ = nullptr;
159 }
160
162 if (referent_ && isOwned()) {
163 referent_->unref();
164 }
165 }
166
167 Ptr &operator=(const Ptr &other) {
168 if (this != &other) {
169 if (referent_ && isOwned()) {
170 referent_->unref();
171 }
172 referent_ = other.referent_;
173 if (referent_ && isOwned()) {
174 referent_->ref();
175 }
176 }
177 return *this;
178 }
179
180 // Either returns the weakptr if it exists, or an empty weakptr.
182 WeakPtr<T> weakPtr() const { return WeakPtr<T>(*this); }
183
184 bool operator==(const T *other) const { return referent_ == other; }
185
186 bool operator!=(const T *other) const { return referent_ != other; }
187
188 bool operator==(const Ptr &other) const {
189 return referent_ == other.referent_;
190 }
191 bool operator!=(const Ptr &other) const {
192 return referent_ != other.referent_;
193 }
194
195 bool operator<(const Ptr &other) const {
196 return referent_ < other.referent_;
197 }
198
199 Ptr &operator=(Ptr &&other) noexcept {
200 if (this != &other) {
201 if (referent_ && isOwned()) {
202 referent_->unref();
203 }
204 referent_ = other.referent_;
205 other.referent_ = nullptr;
206 }
207 return *this;
208 }
209
210 T *get() const { return referent_; }
211
212 T *operator->() const { return referent_; }
213
214 T &operator*() const { return *referent_; }
215
216 explicit operator bool() const noexcept { return referent_ != nullptr; }
217
218 void reset() {
219 if (referent_ && isOwned()) {
220 referent_->unref();
221 }
222 referent_ = nullptr;
223 }
224
225 void reset(Ptr<T> &refptr) {
226 if (refptr.referent_ != referent_) {
227 if (refptr.referent_ && refptr.isOwned()) {
228 refptr.referent_->ref();
229 }
230 if (referent_ && isOwned()) {
231 referent_->unref();
232 }
233 referent_ = refptr.referent_;
234 }
235 }
236
237 // Releases the pointer from reference counting from this Ptr.
238 T *release() {
239 T *temp = referent_;
240 referent_ = nullptr;
241 return temp;
242 }
243
244 void swap(Ptr &other) noexcept {
245 T *temp = referent_;
246 referent_ = other.referent_;
247 other.referent_ = temp;
248 }
249
250 bool isOwned() const { return referent_ && referent_->ref_count() > 0; }
251
252 private:
253 Ptr(T *referent, bool from_heap) : referent_(referent) {
254 if (referent_ && from_heap) {
255 referent_->ref();
256 }
257 }
259};
260
261// Don't inherit from this, this is an internal object.
263 public:
264 WeakReferent() : mRefCount(0), mReferent(nullptr) {}
266
267 void ref() { mRefCount++; }
268 int ref_count() const { return mRefCount; }
269 void unref() {
270 if (--mRefCount == 0) {
271 destroy();
272 }
273 }
274 void destroy() { delete this; }
275 void setReferent(Referent *referent) { mReferent = referent; }
276 Referent *getReferent() const { return mReferent; }
277
278 protected:
279 WeakReferent(const WeakReferent &) = default;
283
284 private:
285 mutable int mRefCount;
287};
288
289template <typename T> class WeakPtr {
290 public:
292
293 WeakPtr(const Ptr<T> &ptr) {
294 if (ptr) {
295 WeakPtr weakRefNoCreate = ptr.weakRefNoCreate();
296 bool expired = weakRefNoCreate.expired();
297 if (expired) {
298 Ptr<WeakReferent> weakRefNoCreate = Ptr<WeakReferent>::New();
299 ptr->setWeakPtr(weakRefNoCreate);
300 weakRefNoCreate->setReferent(ptr.get());
301 }
302 mWeakPtr = ptr->mWeakPtr;
303 }
304 }
305
306 template <typename U> WeakPtr(const Ptr<U> &ptr) : mWeakPtr(ptr->mWeakPtr) {
307 if (ptr) {
308 WeakPtr weakRefNoCreate = ptr.weakRefNoCreate();
309 bool expired = weakRefNoCreate.expired();
310 if (expired) {
311 Ptr<WeakReferent> weakRefNoCreate = Ptr<WeakReferent>::New();
312 ptr->setWeakPtr(weakRefNoCreate);
313 weakRefNoCreate->setReferent(ptr.get());
314 }
315 mWeakPtr = ptr->mWeakPtr;
316 }
317 }
318
319 WeakPtr(const WeakPtr &other) : mWeakPtr(other.mWeakPtr) {}
320
321 template <typename U>
322 WeakPtr(const WeakPtr<U> &other) : mWeakPtr(other.mWeakPtr) {}
323
324 WeakPtr(WeakPtr &&other) noexcept : mWeakPtr(other.mWeakPtr) {}
325
327
328 operator bool() const { return mWeakPtr && mWeakPtr->getReferent(); }
329
330 bool operator!() const {
331 bool ok = *this;
332 return !ok;
333 }
334
335 bool operator==(const WeakPtr &other) const {
336 return mWeakPtr == other.mWeakPtr;
337 }
338
339 bool operator!=(const WeakPtr &other) const {
340 return !(mWeakPtr != other.mWeakPtr);
341 }
342
343 bool operator==(const T *other) const { return lock().get() == other; }
344
345 bool operator==(T *other) const {
346 if (!mWeakPtr) {
347 return other == nullptr;
348 }
349 return mWeakPtr->getReferent() == other;
350 }
351
352 bool operator==(const Ptr<T> &other) const {
353 if (!mWeakPtr) {
354 return !other;
355 }
356 return mWeakPtr->getReferent() == other.get();
357 }
358
359 bool operator!=(const T *other) const {
360 bool equal = *this == other;
361 return !equal;
362 }
363
364 WeakPtr &operator=(const WeakPtr &other) {
365 this->mWeakPtr = other.mWeakPtr;
366 return *this;
367 }
368
369 Ptr<T> lock() const {
370 if (!mWeakPtr) {
371 return Ptr<T>();
372 }
373 T *out = static_cast<T *>(mWeakPtr->getReferent());
374 if (out->ref_count() == 0) {
375 // This is a static object, so the refcount is 0.
376 return Ptr<T>::NoTracking(*out);
377 }
378 // This is a heap object, so we need to ref it.
379 return Ptr<T>::TakeOwnership(static_cast<T *>(out));
380 }
381
382 bool expired() const {
383 if (!mWeakPtr) {
384 return true;
385 }
386 if (!mWeakPtr->getReferent()) {
387 return true;
388 }
389 return false;
390 }
391
392 void reset() {
393 if (mWeakPtr) {
394 mWeakPtr.reset();
395 }
396 }
398};
399
400// Objects that inherit this class can be reference counted and put into
401// a Ptr object. They can also be put into a WeakPtr object.
402class Referent {
403 public:
404 virtual int ref_count() const;
405
406 protected:
407 Referent();
408 virtual ~Referent();
413
414 // Lifetime management has to be marked const.
415 virtual void ref() const;
416 virtual void unref() const;
417 virtual void destroy() const;
418
419 private:
420 friend class WeakReferent;
421 template <typename T> friend class Ptr;
422 template <typename T> friend class WeakPtr;
423 void setWeakPtr(Ptr<WeakReferent> weakRefNoCreate) {
424 mWeakPtr = weakRefNoCreate;
425 }
426 mutable int mRefCount;
427 mutable Ptr<WeakReferent>
428 mWeakPtr; // Optional weak reference to this object.
429};
430
431template <typename T> inline WeakPtr<T> Ptr<T>::weakRefNoCreate() const {
432 if (!referent_) {
433 return WeakPtr<T>();
434 }
435 WeakReferent *tmp = get()->mWeakPtr.get();
436 if (!tmp) {
437 return WeakPtr<T>();
438 }
439 T *referent = static_cast<T *>(tmp->getReferent());
440 if (!referent) {
441 return WeakPtr<T>();
442 }
443 // At this point, we know that our weak referent is valid.
444 // However, the template parameter ensures that either we have
445 // an exact type, or are at least down-castable of it.
446 WeakPtr<T> out;
447 out.mWeakPtr = get()->mWeakPtr;
448 return out;
449}
450
451template <typename T, typename... Args> Ptr<T> NewPtr(Args... args) {
452 return Ptr<T>::New(args...);
453}
454
455template <typename T> Ptr<T> NewPtrNoTracking(T &obj) {
456 return Ptr<T>::NoTracking(obj);
457}
458
459} // namespace fl
corkscrew_args args
void reset()
Definition ptr.h:218
Ptr()
Definition ptr.h:144
bool operator<(const Ptr &other) const
Definition ptr.h:195
void reset(Ptr< T > &refptr)
Definition ptr.h:225
T * referent_
Definition ptr.h:258
Ptr(T *referent)=delete
static Ptr TakeOwnership(T *ptr)
Definition ptr.h:127
void swap(Ptr &other) noexcept
Definition ptr.h:244
Ptr(T *referent, bool from_heap)
Definition ptr.h:253
Ptr & operator=(Ptr &&other) noexcept
Definition ptr.h:199
static Ptr< T > New(Args... args)
Definition ptr.h:122
Ptr(Ptr &&other) noexcept
Definition ptr.h:157
WeakPtr< T > weakRefNoCreate() const
Definition ptr.h:431
Ptr(const Ptr< U > &refptr)
Definition ptr.h:138
bool operator==(const Ptr &other) const
Definition ptr.h:188
static Ptr NoTracking(T &referent)
Definition ptr.h:132
bool operator!=(const Ptr &other) const
Definition ptr.h:191
Ptr(const Ptr &other)
Definition ptr.h:151
T * release()
Definition ptr.h:238
static Ptr Null()
Definition ptr.h:134
Ptr & operator=(T *referent)=delete
Ptr & operator=(const Ptr &other)
Definition ptr.h:167
T * get() const
Definition ptr.h:210
bool isOwned() const
Definition ptr.h:250
WeakPtr< T > weakPtr() const
Definition ptr.h:182
~Ptr()
Definition ptr.h:161
bool operator==(const T *other) const
Definition ptr.h:184
bool operator!=(const T *other) const
Definition ptr.h:186
T & operator*() const
Definition ptr.h:214
T * operator->() const
Definition ptr.h:212
Definition ptr.h:118
T element_type
Definition ptr.h:65
Ptr< T > ptr_type
Definition ptr.h:66
static Ptr< T > New()
Definition ptr.h:73
static Ptr< T > New(Args... args)
Definition ptr.h:68
virtual int ref_count() const
Definition ptr.cpp:11
Referent & operator=(const Referent &)
Ptr< WeakReferent > mWeakPtr
Definition ptr.h:428
friend class WeakPtr
Definition ptr.h:422
Referent & operator=(Referent &&)
int mRefCount
Definition ptr.h:426
virtual ~Referent()
void setWeakPtr(Ptr< WeakReferent > weakRefNoCreate)
Definition ptr.h:423
Referent(const Referent &)
virtual void destroy() const
Definition ptr.cpp:23
Referent()
Definition ptr.cpp:7
virtual void ref() const
Definition ptr.cpp:9
friend class Ptr
Definition ptr.h:421
virtual void unref() const
Definition ptr.cpp:13
friend class WeakReferent
Definition ptr.h:420
Referent(Referent &&)
WeakPtr & operator=(const WeakPtr &other)
Definition ptr.h:364
bool operator==(const T *other) const
Definition ptr.h:343
bool operator==(const Ptr< T > &other) const
Definition ptr.h:352
bool expired() const
Definition ptr.h:382
bool operator!() const
Definition ptr.h:330
bool operator==(T *other) const
Definition ptr.h:345
bool operator==(const WeakPtr &other) const
Definition ptr.h:335
WeakPtr(const Ptr< U > &ptr)
Definition ptr.h:306
WeakPtr(const WeakPtr< U > &other)
Definition ptr.h:322
bool operator!=(const WeakPtr &other) const
Definition ptr.h:339
~WeakPtr()
Definition ptr.h:326
void reset()
Definition ptr.h:392
bool operator!=(const T *other) const
Definition ptr.h:359
WeakPtr()
Definition ptr.h:291
Ptr< T > lock() const
Definition ptr.h:369
WeakPtr(const WeakPtr &other)
Definition ptr.h:319
WeakPtr(const Ptr< T > &ptr)
Definition ptr.h:293
WeakPtr(WeakPtr &&other) noexcept
Definition ptr.h:324
Ptr< WeakReferent > mWeakPtr
Definition ptr.h:397
void destroy()
Definition ptr.h:274
WeakReferent & operator=(WeakReferent &&)=default
int mRefCount
Definition ptr.h:285
void setReferent(Referent *referent)
Definition ptr.h:275
int ref_count() const
Definition ptr.h:268
WeakReferent(const WeakReferent &)=default
Referent * mReferent
Definition ptr.h:286
void unref()
Definition ptr.h:269
WeakReferent & operator=(const WeakReferent &)=default
void ref()
Definition ptr.h:267
Referent * getReferent() const
Definition ptr.h:276
WeakReferent(WeakReferent &&)=default
Implements the FastLED namespace macros.
Ptr< T > NewPtr(Args... args)
Definition ptr.h:451
Ptr< T > NewPtrNoTracking(Args... args)
Implements a simple red square effect for 2D LED grids.
Definition crgb.h:16