Files
klubhaus-doorbell/libraries/FastLED/src/fl/shared_ptr.h
2026-02-12 00:45:31 -08:00

470 lines
14 KiB
C++

#pragma once
#include "fl/namespace.h"
#include "fl/type_traits.h"
#include "fl/utility.h"
#include "fl/stdint.h"
#include "fl/cstddef.h"
#include "fl/bit_cast.h"
#include "fl/atomic.h"
namespace fl {
// Forward declarations
template<typename T> class shared_ptr;
template<typename T> class weak_ptr;
namespace detail {
// Tag type for make_shared constructor
struct make_shared_tag {};
// No-tracking tag for make_shared_no_tracking
struct no_tracking_tag {};
// Enhanced control block structure with no-tracking support using special value
struct ControlBlockBase {
fl::atomic_u32 shared_count;
fl::atomic_u32 weak_count;
// Special value indicating no-tracking mode
static constexpr fl::u32 NO_TRACKING_VALUE = 0xffffffff;
ControlBlockBase(bool track = true)
: shared_count(track ? 1 : NO_TRACKING_VALUE), weak_count(1) {}
virtual ~ControlBlockBase() = default;
virtual void destroy_object() = 0;
virtual void destroy_control_block() = 0;
// NEW: No-tracking aware increment/decrement
void add_shared_ref() {
if (shared_count != NO_TRACKING_VALUE) {
++shared_count;
}
}
bool remove_shared_ref() {
//FASTLED_WARN("ControlBlockBase::remove_shared_ref() called: this=" << this);
if (shared_count == NO_TRACKING_VALUE) {
//FASTLED_WARN("In no-tracking mode, returning false");
return false; // Never destroy in no-tracking mode
}
bool result = (--shared_count == 0);
//FASTLED_WARN("After decrement, returning: " << result);
return result;
}
// Check if this control block is in no-tracking mode
bool is_no_tracking() const {
return shared_count == NO_TRACKING_VALUE;
}
};
// Default deleter implementation
template<typename T>
struct default_delete {
void operator()(T* ptr) const {
delete ptr;
}
};
// Deleter that does nothing (for stack/static objects)
template<typename T>
struct no_op_deleter {
void operator()(T*) const {
// Intentionally do nothing - object lifetime managed externally
}
};
// Enhanced control block for external objects with no-tracking support
template<typename T, typename Deleter = default_delete<T>>
struct ControlBlock : public ControlBlockBase {
T* ptr;
Deleter deleter;
ControlBlock(T* p, Deleter d = Deleter(), bool track = true)
: ControlBlockBase(track), ptr(p), deleter(d) {}
void destroy_object() override {
if (ptr && !is_no_tracking()) { // Only delete if tracking
deleter(ptr);
ptr = nullptr;
}
}
void destroy_control_block() override {
delete this;
}
};
} // namespace detail
// std::shared_ptr compatible implementation
template<typename T>
class shared_ptr {
private:
T* ptr_;
detail::ControlBlockBase* control_block_;
// Internal constructor for make_shared and weak_ptr conversion
shared_ptr(T* ptr, detail::ControlBlockBase* control_block, detail::make_shared_tag)
: ptr_(ptr), control_block_(control_block) {
// Control block was created with reference count 1, no need to increment
}
// Internal constructor for no-tracking
shared_ptr(T* ptr, detail::ControlBlockBase* control_block, detail::no_tracking_tag)
: ptr_(ptr), control_block_(control_block) {
// Control block created with no_tracking=true, no reference increment needed
}
// void release() {
// if (control_block_) {
// if (control_block_->remove_shared_ref()) {
// control_block_->destroy_object();
// if (--control_block_->weak_count == 0) {
// control_block_->destroy_control_block();
// }
// }
// }
// }
void acquire() {
if (control_block_) {
control_block_->add_shared_ref();
}
}
public:
using element_type = T;
using weak_type = weak_ptr<T>;
// Default constructor
shared_ptr() noexcept : ptr_(nullptr), control_block_(nullptr) {}
shared_ptr(fl::nullptr_t) noexcept : ptr_(nullptr), control_block_(nullptr) {}
// Copy constructor
shared_ptr(const shared_ptr& other) : ptr_(other.ptr_), control_block_(other.control_block_) {
acquire();
}
// Converting copy constructor
template<typename Y, typename = typename fl::enable_if<fl::is_base_of<T, Y>::value || fl::is_base_of<Y, T>::value>::type>
shared_ptr(const shared_ptr<Y>& other) : ptr_(static_cast<T*>(other.ptr_)), control_block_(other.control_block_) {
acquire();
}
// Move constructor
shared_ptr(shared_ptr&& other) noexcept : ptr_(other.ptr_), control_block_(other.control_block_) {
other.ptr_ = nullptr;
other.control_block_ = nullptr;
}
// Converting move constructor
template<typename Y, typename = typename fl::enable_if<fl::is_base_of<T, Y>::value || fl::is_base_of<Y, T>::value>::type>
shared_ptr(shared_ptr<Y>&& other) noexcept : ptr_(static_cast<T*>(other.ptr_)), control_block_(other.control_block_) {
other.ptr_ = nullptr;
other.control_block_ = nullptr;
}
// Constructor from weak_ptr
template<typename Y>
explicit shared_ptr(const weak_ptr<Y>& weak);
// Destructor
~shared_ptr() {
//FASTLED_WARN("shared_ptr destructor called, ptr_=" << ptr_
// << ", control_block_=" << control_block_);
reset();
}
// Assignment operators
shared_ptr& operator=(const shared_ptr& other) {
if (this != &other) {
reset();
ptr_ = other.ptr_;
control_block_ = other.control_block_;
acquire();
}
return *this;
}
template<typename Y>
shared_ptr& operator=(const shared_ptr<Y>& other) {
reset();
ptr_ = other.ptr_;
control_block_ = other.control_block_;
acquire();
return *this;
}
shared_ptr& operator=(shared_ptr&& other) noexcept {
if (this != &other) {
this->swap(other);
other.reset();
}
return *this;
}
template<typename Y>
shared_ptr& operator=(shared_ptr<Y>&& other) noexcept {
if (static_cast<void*>(this) != static_cast<void*>(&other)) {
this->swap(other);
other.reset();
}
return *this;
}
// Modifiers
void reset() noexcept {
//FASTLED_WARN("shared_ptr::reset() called: ptr_=" << ptr_
// << ", control_block_=" << control_block_);
if (control_block_) {
//FASTLED_WARN("control_block exists, calling remove_shared_ref()");
if (control_block_->remove_shared_ref()) {
//FASTLED_WARN("control_block_->remove_shared_ref() returned true, destroying object");
control_block_->destroy_object();
if (--control_block_->weak_count == 0) {
//FASTLED_WARN("weak_count reached 0, destroying control block");
control_block_->destroy_control_block();
}
}
}
ptr_ = nullptr;
control_block_ = nullptr;
}
void reset(shared_ptr&& other) noexcept {
this->swap(other);
other.reset();
}
void swap(shared_ptr& other) noexcept {
fl::swap(ptr_, other.ptr_);
fl::swap(control_block_, other.control_block_);
}
void swap(shared_ptr&& other) noexcept {
fl::swap(ptr_, other.ptr_);
fl::swap(control_block_, other.control_block_);
}
// template<typename Y>
// void reset(Y* ptr) {
// shared_ptr(ptr).swap(*this);
// }
// template<typename Y, typename Deleter>
// void reset(Y* ptr, Deleter d) {
// shared_ptr(ptr, d).swap(*this);
// }
// Observers
T* get() const noexcept { return ptr_; }
T& operator*() const noexcept { return *ptr_; }
T* operator->() const noexcept { return ptr_; }
T& operator[](ptrdiff_t idx) const { return ptr_[idx]; }
// NEW: use_count returns 0 for no-tracking shared_ptrs
long use_count() const noexcept {
if (!control_block_) return 0;
if (control_block_->shared_count == detail::ControlBlockBase::NO_TRACKING_VALUE) {
return 0;
}
return static_cast<long>(control_block_->shared_count);
}
bool unique() const noexcept { return use_count() == 1; }
explicit operator bool() const noexcept { return ptr_ != nullptr; }
// NEW: Check if this is a no-tracking shared_ptr
bool is_no_tracking() const noexcept {
return control_block_ && control_block_->is_no_tracking();
}
// Comparison operators for nullptr only (to avoid ambiguity with non-member operators)
bool operator==(fl::nullptr_t) const noexcept {
return ptr_ == nullptr;
}
bool operator!=(fl::nullptr_t) const noexcept {
return ptr_ != nullptr;
}
private:
// Constructor from raw pointer with default deleter
template<typename Y>
explicit shared_ptr(Y* ptr) : ptr_(ptr) {
if (ptr_) {
control_block_ = new detail::ControlBlock<Y>(ptr, detail::default_delete<Y>{});
} else {
control_block_ = nullptr;
}
}
// Constructor from raw pointer with custom deleter
template<typename Y, typename Deleter>
shared_ptr(Y* ptr, Deleter d) : ptr_(ptr) {
if (ptr_) {
control_block_ = new detail::ControlBlock<Y, Deleter>(ptr_, d);
} else {
control_block_ = nullptr;
}
}
template<typename Y> friend class shared_ptr;
template<typename Y> friend class weak_ptr;
template<typename Y, typename... Args>
friend shared_ptr<Y> make_shared(Args&&... args);
template<typename Y, typename Deleter, typename... Args>
friend shared_ptr<Y> make_shared_with_deleter(Deleter d, Args&&... args);
template<typename Y, typename A, typename... Args>
friend shared_ptr<Y> allocate_shared(const A& alloc, Args&&... args);
template<typename Y>
friend shared_ptr<Y> make_shared_no_tracking(Y& obj);
};
// Factory functions
// make_shared with optimized inlined storage
template<typename T, typename... Args>
shared_ptr<T> make_shared(Args&&... args) {
T* obj = new T(fl::forward<Args>(args)...);
auto* control = new detail::ControlBlock<T>(obj);
//FASTLED_WARN("make_shared created object at " << obj
// << " with control block at " << control);
//new(control->get_object()) T(fl::forward<Args>(args)...);
//control->object_constructed = true;
return shared_ptr<T>(obj, control, detail::make_shared_tag{});
}
template<typename T, typename Deleter, typename... Args>
shared_ptr<T> make_shared_with_deleter(Deleter d, Args&&... args) {
T* obj = new T(fl::forward<Args>(args)...);
auto* control = new detail::ControlBlock<T, Deleter>(obj, d);
//new(control->get_object()) T(fl::forward<Args>(args)...);
//control->object_constructed = true;
return shared_ptr<T>(obj, control, detail::make_shared_tag{});
}
namespace detail {
template<typename T>
struct NoDeleter {
void operator()(T*) const {
// Intentionally do nothing - object lifetime managed externally
}
};
}
// NEW: Creates a shared_ptr that does not modify the reference count
// The shared_ptr and any copies will not affect object lifetime
template<typename T>
shared_ptr<T> make_shared_no_tracking(T& obj) {
auto* control = new detail::ControlBlock<T, detail::NoDeleter<T>>(&obj, detail::NoDeleter<T>{}, false); // track = false (enables no-tracking mode)
return shared_ptr<T>(&obj, control, detail::no_tracking_tag{});
}
// allocate_shared (simplified version without full allocator support for now)
template<typename T, typename A, typename... Args>
shared_ptr<T> allocate_shared(const A& /* alloc */, Args&&... args) {
// For now, just delegate to make_shared
// Full allocator support would require more complex control block management
return make_shared<T>(fl::forward<Args>(args)...);
}
// Non-member comparison operators
template<typename T, typename Y>
bool operator==(const shared_ptr<T>& lhs, const shared_ptr<Y>& rhs) noexcept {
return lhs.get() == rhs.get();
}
template<typename T, typename Y>
bool operator!=(const shared_ptr<T>& lhs, const shared_ptr<Y>& rhs) noexcept {
return lhs.get() != rhs.get();
}
template<typename T, typename Y>
bool operator<(const shared_ptr<T>& lhs, const shared_ptr<Y>& rhs) noexcept {
return lhs.get() < rhs.get();
}
template<typename T, typename Y>
bool operator<=(const shared_ptr<T>& lhs, const shared_ptr<Y>& rhs) noexcept {
return lhs.get() <= rhs.get();
}
template<typename T, typename Y>
bool operator>(const shared_ptr<T>& lhs, const shared_ptr<Y>& rhs) noexcept {
return lhs.get() > rhs.get();
}
template<typename T, typename Y>
bool operator>=(const shared_ptr<T>& lhs, const shared_ptr<Y>& rhs) noexcept {
return lhs.get() >= rhs.get();
}
template<typename T>
bool operator==(const shared_ptr<T>& lhs, fl::nullptr_t) noexcept {
return lhs.get() == nullptr;
}
template<typename T>
bool operator==(fl::nullptr_t, const shared_ptr<T>& rhs) noexcept {
return nullptr == rhs.get();
}
template<typename T>
bool operator!=(const shared_ptr<T>& lhs, fl::nullptr_t) noexcept {
return lhs.get() != nullptr;
}
template<typename T>
bool operator!=(fl::nullptr_t, const shared_ptr<T>& rhs) noexcept {
return nullptr != rhs.get();
}
// Utility functions
template<typename T>
void swap(shared_ptr<T>& lhs, shared_ptr<T>& rhs) noexcept {
lhs.swap(rhs);
}
// Casts
template<typename T, typename Y>
shared_ptr<T> static_pointer_cast(const shared_ptr<Y>& other) noexcept {
auto ptr = static_cast<T*>(other.get());
return shared_ptr<T>(ptr, other.control_block_, detail::make_shared_tag{});
}
template<typename T, typename Y>
shared_ptr<T> const_pointer_cast(const shared_ptr<Y>& other) noexcept {
auto ptr = const_cast<T*>(other.get());
return shared_ptr<T>(ptr, other.control_block_, detail::make_shared_tag{});
}
template<typename T, typename Y>
shared_ptr<T> reinterpret_pointer_cast(const shared_ptr<Y>& other) noexcept {
auto ptr = fl::bit_cast<T*>(other.get());
return shared_ptr<T>(ptr, other.control_block_, detail::make_shared_tag{});
}
} // namespace fl