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