FastLED 3.9.15
Loading...
Searching...
No Matches
shared_ptr.h
Go to the documentation of this file.
1#pragma once
2
3#include "fl/namespace.h"
4#include "fl/type_traits.h"
5#include "fl/utility.h"
6#include "fl/stdint.h"
7#include "fl/cstddef.h"
8#include "fl/bit_cast.h"
9#include "fl/atomic.h"
10
11
12namespace fl {
13
14// Forward declarations
15template<typename T> class shared_ptr;
16template<typename T> class weak_ptr;
17
18namespace detail {
19
20// Tag type for make_shared constructor
22
23// No-tracking tag for make_shared_no_tracking
25
26// Enhanced control block structure with no-tracking support using special value
30
31 // Special value indicating no-tracking mode
32 static constexpr fl::u32 NO_TRACKING_VALUE = 0xffffffff;
33
34 ControlBlockBase(bool track = true)
35 : shared_count(track ? 1 : NO_TRACKING_VALUE), weak_count(1) {}
36 virtual ~ControlBlockBase() = default;
37 virtual void destroy_object() = 0;
38 virtual void destroy_control_block() = 0;
39
40 // NEW: No-tracking aware increment/decrement
44 }
45 }
46
48 //FASTLED_WARN("ControlBlockBase::remove_shared_ref() called: this=" << this);
50 //FASTLED_WARN("In no-tracking mode, returning false");
51 return false; // Never destroy in no-tracking mode
52 }
53 bool result = (--shared_count == 0);
54 //FASTLED_WARN("After decrement, returning: " << result);
55 return result;
56 }
57
58 // Check if this control block is in no-tracking mode
59 bool is_no_tracking() const {
61 }
62};
63
64// Default deleter implementation
65template<typename T>
67 void operator()(T* ptr) const {
68 delete ptr;
69 }
70};
71
72// Deleter that does nothing (for stack/static objects)
73template<typename T>
75 void operator()(T*) const {
76 // Intentionally do nothing - object lifetime managed externally
77 }
78};
79
80// Enhanced control block for external objects with no-tracking support
81template<typename T, typename Deleter = default_delete<T>>
83 T* ptr;
84 Deleter deleter;
85
86 ControlBlock(T* p, Deleter d = Deleter(), bool track = true)
87 : ControlBlockBase(track), ptr(p), deleter(d) {}
88
89 void destroy_object() override {
90 if (ptr && !is_no_tracking()) { // Only delete if tracking
91 deleter(ptr);
92 ptr = nullptr;
93 }
94 }
95
96 void destroy_control_block() override {
97 delete this;
98 }
99};
100
101
102} // namespace detail
103
104// std::shared_ptr compatible implementation
105template<typename T>
107private:
110
111 // Internal constructor for make_shared and weak_ptr conversion
113 : ptr_(ptr), control_block_(control_block) {
114 // Control block was created with reference count 1, no need to increment
115 }
116
117 // Internal constructor for no-tracking
119 : ptr_(ptr), control_block_(control_block) {
120 // Control block created with no_tracking=true, no reference increment needed
121 }
122
123 // void release() {
124 // if (control_block_) {
125 // if (control_block_->remove_shared_ref()) {
126 // control_block_->destroy_object();
127 // if (--control_block_->weak_count == 0) {
128 // control_block_->destroy_control_block();
129 // }
130 // }
131 // }
132 // }
133
134 void acquire() {
135 if (control_block_) {
136 control_block_->add_shared_ref();
137 }
138 }
139
140public:
141 using element_type = T;
143
144 // Default constructor
145 shared_ptr() noexcept : ptr_(nullptr), control_block_(nullptr) {}
146 shared_ptr(fl::nullptr_t) noexcept : ptr_(nullptr), control_block_(nullptr) {}
147
148
149
150 // Copy constructor
152 acquire();
153 }
154
155 // Converting copy constructor
156 template<typename Y>
158 acquire();
159 }
160
161 // Move constructor
162 shared_ptr(shared_ptr&& other) noexcept : ptr_(other.ptr_), control_block_(other.control_block_) {
163 other.ptr_ = nullptr;
164 other.control_block_ = nullptr;
165 }
166
167 // Converting move constructor
168 template<typename Y>
169 shared_ptr(shared_ptr<Y>&& other) noexcept : ptr_(other.ptr_), control_block_(other.control_block_) {
170 other.ptr_ = nullptr;
171 other.control_block_ = nullptr;
172 }
173
174 // Constructor from weak_ptr
175 template<typename Y>
176 explicit shared_ptr(const weak_ptr<Y>& weak);
177
178 // Destructor
180 //FASTLED_WARN("shared_ptr destructor called, ptr_=" << ptr_
181 // << ", control_block_=" << control_block_);
182 reset();
183 }
184
185 // Assignment operators
187 if (this != &other) {
188 reset();
189 ptr_ = other.ptr_;
191 acquire();
192 }
193 return *this;
194 }
195
196 template<typename Y>
198 reset();
199 ptr_ = other.ptr_;
201 acquire();
202 return *this;
203 }
204
205 shared_ptr& operator=(shared_ptr&& other) noexcept {
206 if (this != &other) {
207 this->swap(other);
208 other.reset();
209 }
210 return *this;
211 }
212
213 template<typename Y>
214 shared_ptr& operator=(shared_ptr<Y>&& other) noexcept {
215 if (static_cast<void*>(this) != static_cast<void*>(&other)) {
216 this->swap(other);
217 other.reset();
218 }
219 return *this;
220 }
221
222 // Modifiers
223 void reset() noexcept {
224 //FASTLED_WARN("shared_ptr::reset() called: ptr_=" << ptr_
225 // << ", control_block_=" << control_block_);
226 if (control_block_) {
227 //FASTLED_WARN("control_block exists, calling remove_shared_ref()");
228 if (control_block_->remove_shared_ref()) {
229 //FASTLED_WARN("control_block_->remove_shared_ref() returned true, destroying object");
230 control_block_->destroy_object();
231 if (--control_block_->weak_count == 0) {
232 //FASTLED_WARN("weak_count reached 0, destroying control block");
233 control_block_->destroy_control_block();
234 }
235 }
236 }
237 ptr_ = nullptr;
238 control_block_ = nullptr;
239 }
240
241 void reset(shared_ptr&& other) noexcept {
242 this->swap(other);
243 other.reset();
244 }
245
246 void swap(shared_ptr& other) noexcept {
247 fl::swap(ptr_, other.ptr_);
248 fl::swap(control_block_, other.control_block_);
249 }
250
251 void swap(shared_ptr&& other) noexcept {
252 fl::swap(ptr_, other.ptr_);
253 fl::swap(control_block_, other.control_block_);
254 }
255
256
257
258 // template<typename Y>
259 // void reset(Y* ptr) {
260 // shared_ptr(ptr).swap(*this);
261 // }
262
263 // template<typename Y, typename Deleter>
264 // void reset(Y* ptr, Deleter d) {
265 // shared_ptr(ptr, d).swap(*this);
266 // }
267
268
269
270 // Observers
271 T* get() const noexcept { return ptr_; }
272
273 T& operator*() const noexcept { return *ptr_; }
274 T* operator->() const noexcept { return ptr_; }
275
276 T& operator[](ptrdiff_t idx) const { return ptr_[idx]; }
277
278 // NEW: use_count returns 0 for no-tracking shared_ptrs
279 long use_count() const noexcept {
280 if (!control_block_) return 0;
282 return 0;
283 }
284 return static_cast<long>(control_block_->shared_count);
285 }
286
287 bool unique() const noexcept { return use_count() == 1; }
288
289 explicit operator bool() const noexcept { return ptr_ != nullptr; }
290
291 // NEW: Check if this is a no-tracking shared_ptr
292 bool is_no_tracking() const noexcept {
293 return control_block_ && control_block_->is_no_tracking();
294 }
295
296 // Comparison operators for nullptr only (to avoid ambiguity with non-member operators)
297
298 bool operator==(fl::nullptr_t) const noexcept {
299 return ptr_ == nullptr;
300 }
301
302 bool operator!=(fl::nullptr_t) const noexcept {
303 return ptr_ != nullptr;
304 }
305
306private:
307
308 // Constructor from raw pointer with default deleter
309 template<typename Y>
310 explicit shared_ptr(Y* ptr) : ptr_(ptr) {
311 if (ptr_) {
313 } else {
314 control_block_ = nullptr;
315 }
316 }
317
318 // Constructor from raw pointer with custom deleter
319 template<typename Y, typename Deleter>
320 shared_ptr(Y* ptr, Deleter d) : ptr_(ptr) {
321 if (ptr_) {
323 } else {
324 control_block_ = nullptr;
325 }
326 }
327
328 template<typename Y> friend class shared_ptr;
329 template<typename Y> friend class weak_ptr;
330
331 template<typename Y, typename... Args>
332 friend shared_ptr<Y> make_shared(Args&&... args);
333
334 template<typename Y, typename Deleter, typename... Args>
335 friend shared_ptr<Y> make_shared_with_deleter(Deleter d, Args&&... args);
336
337 template<typename Y, typename A, typename... Args>
338 friend shared_ptr<Y> allocate_shared(const A& alloc, Args&&... args);
339
340 template<typename Y>
342};
343
344// Factory functions
345
346// make_shared with optimized inlined storage
347template<typename T, typename... Args>
349 T* obj = new T(fl::forward<Args>(args)...);
350 auto* control = new detail::ControlBlock<T>(obj);
351 //FASTLED_WARN("make_shared created object at " << obj
352 // << " with control block at " << control);
353 //new(control->get_object()) T(fl::forward<Args>(args)...);
354 //control->object_constructed = true;
355 return shared_ptr<T>(obj, control, detail::make_shared_tag{});
356}
357
358template<typename T, typename Deleter, typename... Args>
360 T* obj = new T(fl::forward<Args>(args)...);
361 auto* control = new detail::ControlBlock<T, Deleter>(obj, d);
362 //new(control->get_object()) T(fl::forward<Args>(args)...);
363 //control->object_constructed = true;
364 return shared_ptr<T>(obj, control, detail::make_shared_tag{});
365}
366
367namespace detail {
368 template<typename T>
369 struct NoDeleter {
370 void operator()(T*) const {
371 // Intentionally do nothing - object lifetime managed externally
372 }
373 };
374}
375
376// NEW: Creates a shared_ptr that does not modify the reference count
377// The shared_ptr and any copies will not affect object lifetime
378template<typename T>
380 auto* control = new detail::ControlBlock<T, detail::NoDeleter<T>>(&obj, detail::NoDeleter<T>{}, false); // track = false (enables no-tracking mode)
381 return shared_ptr<T>(&obj, control, detail::no_tracking_tag{});
382}
383
384// allocate_shared (simplified version without full allocator support for now)
385template<typename T, typename A, typename... Args>
386shared_ptr<T> allocate_shared(const A& /* alloc */, Args&&... args) {
387 // For now, just delegate to make_shared
388 // Full allocator support would require more complex control block management
390}
391
392// Non-member comparison operators
393template<typename T, typename Y>
394bool operator==(const shared_ptr<T>& lhs, const shared_ptr<Y>& rhs) noexcept {
395 return lhs.get() == rhs.get();
396}
397
398template<typename T, typename Y>
399bool operator!=(const shared_ptr<T>& lhs, const shared_ptr<Y>& rhs) noexcept {
400 return lhs.get() != rhs.get();
401}
402
403template<typename T, typename Y>
404bool operator<(const shared_ptr<T>& lhs, const shared_ptr<Y>& rhs) noexcept {
405 return lhs.get() < rhs.get();
406}
407
408template<typename T, typename Y>
409bool operator<=(const shared_ptr<T>& lhs, const shared_ptr<Y>& rhs) noexcept {
410 return lhs.get() <= rhs.get();
411}
412
413template<typename T, typename Y>
414bool operator>(const shared_ptr<T>& lhs, const shared_ptr<Y>& rhs) noexcept {
415 return lhs.get() > rhs.get();
416}
417
418template<typename T, typename Y>
419bool operator>=(const shared_ptr<T>& lhs, const shared_ptr<Y>& rhs) noexcept {
420 return lhs.get() >= rhs.get();
421}
422
423template<typename T>
424bool operator==(const shared_ptr<T>& lhs, fl::nullptr_t) noexcept {
425 return lhs.get() == nullptr;
426}
427
428template<typename T>
429bool operator==(fl::nullptr_t, const shared_ptr<T>& rhs) noexcept {
430 return nullptr == rhs.get();
431}
432
433template<typename T>
434bool operator!=(const shared_ptr<T>& lhs, fl::nullptr_t) noexcept {
435 return lhs.get() != nullptr;
436}
437
438template<typename T>
439bool operator!=(fl::nullptr_t, const shared_ptr<T>& rhs) noexcept {
440 return nullptr != rhs.get();
441}
442
443// Utility functions
444template<typename T>
445void swap(shared_ptr<T>& lhs, shared_ptr<T>& rhs) noexcept {
446 lhs.swap(rhs);
447}
448
449// Casts
450template<typename T, typename Y>
452 auto ptr = static_cast<T*>(other.get());
453 return shared_ptr<T>(ptr, other.control_block_, detail::make_shared_tag{});
454}
455
456
457template<typename T, typename Y>
459 auto ptr = const_cast<T*>(other.get());
460 return shared_ptr<T>(ptr, other.control_block_, detail::make_shared_tag{});
461}
462
463template<typename T, typename Y>
465 auto ptr = fl::bit_cast<T*>(other.get());
466 return shared_ptr<T>(ptr, other.control_block_, detail::make_shared_tag{});
467}
468
469} // namespace fl
Result type for promise operations.
T & operator*() const noexcept
Definition shared_ptr.h:273
long use_count() const noexcept
Definition shared_ptr.h:279
friend class weak_ptr
Definition shared_ptr.h:329
weak_ptr< T > weak_type
Definition shared_ptr.h:142
shared_ptr(T *ptr, detail::ControlBlockBase *control_block, detail::make_shared_tag)
Definition shared_ptr.h:112
shared_ptr(T *ptr, detail::ControlBlockBase *control_block, detail::no_tracking_tag)
Definition shared_ptr.h:118
T & operator[](ptrdiff_t idx) const
Definition shared_ptr.h:276
bool operator==(fl::nullptr_t) const noexcept
Definition shared_ptr.h:298
friend shared_ptr< Y > allocate_shared(const A &alloc, Args &&... args)
Definition shared_ptr.h:386
friend shared_ptr< Y > make_shared_with_deleter(Deleter d, Args &&... args)
Definition shared_ptr.h:359
shared_ptr & operator=(shared_ptr< Y > &&other) noexcept
Definition shared_ptr.h:214
friend shared_ptr< Y > make_shared(Args &&... args)
Definition shared_ptr.h:348
friend shared_ptr< Y > make_shared_no_tracking(Y &obj)
bool operator!=(fl::nullptr_t) const noexcept
Definition shared_ptr.h:302
void swap(shared_ptr &&other) noexcept
Definition shared_ptr.h:251
T * get() const noexcept
Definition shared_ptr.h:271
void reset() noexcept
Definition shared_ptr.h:223
detail::ControlBlockBase * control_block_
Definition shared_ptr.h:109
void reset(shared_ptr &&other) noexcept
Definition shared_ptr.h:241
shared_ptr(Y *ptr, Deleter d)
Definition shared_ptr.h:320
shared_ptr(shared_ptr< Y > &&other) noexcept
Definition shared_ptr.h:169
shared_ptr & operator=(shared_ptr &&other) noexcept
Definition shared_ptr.h:205
shared_ptr(shared_ptr &&other) noexcept
Definition shared_ptr.h:162
T * operator->() const noexcept
Definition shared_ptr.h:274
bool unique() const noexcept
Definition shared_ptr.h:287
friend class shared_ptr
Definition shared_ptr.h:328
shared_ptr(const shared_ptr &other)
Definition shared_ptr.h:151
shared_ptr(fl::nullptr_t) noexcept
Definition shared_ptr.h:146
shared_ptr & operator=(const shared_ptr< Y > &other)
Definition shared_ptr.h:197
shared_ptr(const shared_ptr< Y > &other)
Definition shared_ptr.h:157
bool is_no_tracking() const noexcept
Definition shared_ptr.h:292
shared_ptr(Y *ptr)
Definition shared_ptr.h:310
shared_ptr & operator=(const shared_ptr &other)
Definition shared_ptr.h:186
void swap(shared_ptr &other) noexcept
Definition shared_ptr.h:246
shared_ptr() noexcept
Definition shared_ptr.h:145
Implements the FastLED namespace macros.
shared_ptr< T > const_pointer_cast(const shared_ptr< Y > &other) noexcept
Definition shared_ptr.h:458
void swap(array< T, N > &lhs, array< T, N > &rhs) noexcept(noexcept(lhs.swap(rhs)))
Definition array.h:156
To bit_cast(const From &from) noexcept
Definition bit_cast.h:39
shared_ptr< T > make_shared_no_tracking(T &obj)
Definition shared_ptr.h:379
bool operator!=(const array< T, N > &lhs, const array< T, N > &rhs)
Definition array.h:151
__PTRDIFF_TYPE__ ptrdiff_t
Definition cstddef.h:22
shared_ptr< T > static_pointer_cast(const shared_ptr< Y > &other) noexcept
Definition shared_ptr.h:451
bool operator>=(const pair< T1, T2 > &lhs, const pair< U1, U2 > &rhs)
Definition pair.h:81
atomic< fl::u32 > atomic_u32
Definition atomic.h:27
decltype(nullptr) nullptr_t
Definition cstddef.h:11
shared_ptr< T > reinterpret_pointer_cast(const shared_ptr< Y > &other) noexcept
Definition shared_ptr.h:464
shared_ptr< T > make_shared(Args &&... args)
Definition shared_ptr.h:348
shared_ptr< T > allocate_shared(const A &, Args &&... args)
Definition shared_ptr.h:386
bool operator<(const pair< T1, T2 > &lhs, const pair< U1, U2 > &rhs)
Definition pair.h:66
bool operator==(const array< T, N > &lhs, const array< T, N > &rhs)
Definition array.h:141
bool operator<=(const pair< T1, T2 > &lhs, const pair< U1, U2 > &rhs)
Definition pair.h:71
constexpr T && forward(typename remove_reference< T >::type &t) noexcept
bool operator>(const pair< T1, T2 > &lhs, const pair< U1, U2 > &rhs)
Definition pair.h:76
shared_ptr< T > make_shared_with_deleter(Deleter d, Args &&... args)
Definition shared_ptr.h:359
IMPORTANT!
Definition crgb.h:20
corkscrew_args args
Definition old.h:150
void destroy_object() override
Definition shared_ptr.h:89
void destroy_control_block() override
Definition shared_ptr.h:96
ControlBlock(T *p, Deleter d=Deleter(), bool track=true)
Definition shared_ptr.h:86
ControlBlockBase(bool track=true)
Definition shared_ptr.h:34
static constexpr fl::u32 NO_TRACKING_VALUE
Definition shared_ptr.h:32
virtual ~ControlBlockBase()=default
fl::atomic_u32 shared_count
Definition shared_ptr.h:28
virtual void destroy_object()=0
virtual void destroy_control_block()=0
void operator()(T *) const
Definition shared_ptr.h:370
void operator()(T *ptr) const
Definition shared_ptr.h:67
void operator()(T *) const
Definition shared_ptr.h:75