#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 class shared_ptr; template 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 struct default_delete { void operator()(T* ptr) const { delete ptr; } }; // Deleter that does nothing (for stack/static objects) template 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> 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 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; // 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::value || fl::is_base_of::value>::type> shared_ptr(const shared_ptr& other) : ptr_(static_cast(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::value || fl::is_base_of::value>::type> shared_ptr(shared_ptr&& other) noexcept : ptr_(static_cast(other.ptr_)), control_block_(other.control_block_) { other.ptr_ = nullptr; other.control_block_ = nullptr; } // Constructor from weak_ptr template explicit shared_ptr(const weak_ptr& 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 shared_ptr& operator=(const shared_ptr& 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 shared_ptr& operator=(shared_ptr&& other) noexcept { if (static_cast(this) != static_cast(&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 // void reset(Y* ptr) { // shared_ptr(ptr).swap(*this); // } // template // 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(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 explicit shared_ptr(Y* ptr) : ptr_(ptr) { if (ptr_) { control_block_ = new detail::ControlBlock(ptr, detail::default_delete{}); } else { control_block_ = nullptr; } } // Constructor from raw pointer with custom deleter template shared_ptr(Y* ptr, Deleter d) : ptr_(ptr) { if (ptr_) { control_block_ = new detail::ControlBlock(ptr_, d); } else { control_block_ = nullptr; } } template friend class shared_ptr; template friend class weak_ptr; template friend shared_ptr make_shared(Args&&... args); template friend shared_ptr make_shared_with_deleter(Deleter d, Args&&... args); template friend shared_ptr allocate_shared(const A& alloc, Args&&... args); template friend shared_ptr make_shared_no_tracking(Y& obj); }; // Factory functions // make_shared with optimized inlined storage template shared_ptr make_shared(Args&&... args) { T* obj = new T(fl::forward(args)...); auto* control = new detail::ControlBlock(obj); //FASTLED_WARN("make_shared created object at " << obj // << " with control block at " << control); //new(control->get_object()) T(fl::forward(args)...); //control->object_constructed = true; return shared_ptr(obj, control, detail::make_shared_tag{}); } template shared_ptr make_shared_with_deleter(Deleter d, Args&&... args) { T* obj = new T(fl::forward(args)...); auto* control = new detail::ControlBlock(obj, d); //new(control->get_object()) T(fl::forward(args)...); //control->object_constructed = true; return shared_ptr(obj, control, detail::make_shared_tag{}); } namespace detail { template 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 shared_ptr make_shared_no_tracking(T& obj) { auto* control = new detail::ControlBlock>(&obj, detail::NoDeleter{}, false); // track = false (enables no-tracking mode) return shared_ptr(&obj, control, detail::no_tracking_tag{}); } // allocate_shared (simplified version without full allocator support for now) template shared_ptr 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(fl::forward(args)...); } // Non-member comparison operators template bool operator==(const shared_ptr& lhs, const shared_ptr& rhs) noexcept { return lhs.get() == rhs.get(); } template bool operator!=(const shared_ptr& lhs, const shared_ptr& rhs) noexcept { return lhs.get() != rhs.get(); } template bool operator<(const shared_ptr& lhs, const shared_ptr& rhs) noexcept { return lhs.get() < rhs.get(); } template bool operator<=(const shared_ptr& lhs, const shared_ptr& rhs) noexcept { return lhs.get() <= rhs.get(); } template bool operator>(const shared_ptr& lhs, const shared_ptr& rhs) noexcept { return lhs.get() > rhs.get(); } template bool operator>=(const shared_ptr& lhs, const shared_ptr& rhs) noexcept { return lhs.get() >= rhs.get(); } template bool operator==(const shared_ptr& lhs, fl::nullptr_t) noexcept { return lhs.get() == nullptr; } template bool operator==(fl::nullptr_t, const shared_ptr& rhs) noexcept { return nullptr == rhs.get(); } template bool operator!=(const shared_ptr& lhs, fl::nullptr_t) noexcept { return lhs.get() != nullptr; } template bool operator!=(fl::nullptr_t, const shared_ptr& rhs) noexcept { return nullptr != rhs.get(); } // Utility functions template void swap(shared_ptr& lhs, shared_ptr& rhs) noexcept { lhs.swap(rhs); } // Casts template shared_ptr static_pointer_cast(const shared_ptr& other) noexcept { auto ptr = static_cast(other.get()); return shared_ptr(ptr, other.control_block_, detail::make_shared_tag{}); } template shared_ptr const_pointer_cast(const shared_ptr& other) noexcept { auto ptr = const_cast(other.get()); return shared_ptr(ptr, other.control_block_, detail::make_shared_tag{}); } template shared_ptr reinterpret_pointer_cast(const shared_ptr& other) noexcept { auto ptr = fl::bit_cast(other.get()); return shared_ptr(ptr, other.control_block_, detail::make_shared_tag{}); } } // namespace fl