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