// https://github.com/vinniefalco/LuaBridge // Copyright 2021, Stefan Frings // Copyright 2019, Dmitry Tarakanov // Copyright 2012, Vinnie Falco // Copyright 2007, Nathan Reed // SPDX-License-Identifier: MIT #pragma once #include #include #include namespace luabridge { namespace detail { //============================================================================== /** Support for our RefCountedPtr. */ struct RefCountedPtrBase { // Declaration of container for the refcounts typedef std::unordered_map RefCountsType; protected: RefCountsType& getRefCounts() const { static RefCountsType refcounts; return refcounts; } }; } // namespace detail //============================================================================== /** A reference counted smart pointer. The api is compatible with boost::RefCountedPtr and std::RefCountedPtr, in the sense that it implements a strict subset of the functionality. This implementation uses a hash table to look up the reference count associated with a particular pointer. @tparam T The class type. @todo Decompose RefCountedPtr using a policy. At a minimum, the underlying reference count should be policy based (to support atomic operations) and the delete behavior should be policy based (to support custom disposal methods). @todo Provide an intrusive version of RefCountedPtr. */ template class RefCountedPtr : private detail::RefCountedPtrBase { public: template struct rebind { typedef RefCountedPtr other; }; /** Construct as nullptr or from existing pointer to T. @param p The optional, existing pointer to assign from. */ RefCountedPtr(T* const p = nullptr) : m_p(p) { if (m_p) { ++getRefCounts()[m_p]; } } /** Construct from another RefCountedPtr. @param rhs The RefCountedPtr to assign from. */ RefCountedPtr(RefCountedPtr const& rhs) : RefCountedPtr(rhs.get()) {} /** Construct from a RefCountedPtr of a different type. @invariant A pointer to U must be convertible to a pointer to T. @tparam U The other object type. @param rhs The RefCountedPtr to assign from. */ template RefCountedPtr(RefCountedPtr const& rhs) : RefCountedPtr(rhs.get()) { } /** Release the object. If there are no more references then the object is deleted. */ ~RefCountedPtr() { reset(); } /** Assign from another RefCountedPtr. @param rhs The RefCountedPtr to assign from. @returns A reference to the RefCountedPtr. */ RefCountedPtr& operator=(RefCountedPtr const& rhs) { // NOTE Self assignment is handled gracefully *this = rhs.get(); return *this; } /** Assign from another RefCountedPtr of a different type. @note A pointer to U must be convertible to a pointer to T. @tparam U The other object type. @param rhs The other RefCountedPtr to assign from. @returns A reference to the RefCountedPtr. */ template RefCountedPtr& operator=(RefCountedPtr const& rhs) { // NOTE Self assignment is handled gracefully *this = rhs.get(); return *this; } RefCountedPtr& operator=(T* const p) { if (p != m_p) { RefCountedPtr tmp(p); std::swap(m_p, tmp.m_p); } return *this; } /** Retrieve the raw pointer. @returns A pointer to the object. */ T* get() const { return m_p; } /** Retrieve the raw pointer by conversion. @returns A pointer to the object. */ operator T*() const { return m_p; } /** Retrieve the raw pointer. @returns A pointer to the object. */ T* operator*() const { return m_p; } /** Retrieve the raw pointer. @returns A pointer to the object. */ T* operator->() const { return m_p; } /** Determine the number of references. @note This is not thread-safe. @returns The number of active references. */ RefCountsType::mapped_type use_count() const { if (!m_p) { return 0; } const auto itCounter = getRefCounts().find(m_p); assert(itCounter != getRefCounts().end()); assert(itCounter->second > 0); return itCounter->second; } /** Release the pointer. The reference count is decremented. If the reference count reaches zero, the object is deleted. */ void reset() { if (m_p) { const auto itCounter = getRefCounts().find(m_p); assert(itCounter != getRefCounts().end()); assert(itCounter->second > 0); if (--itCounter->second == 0) { delete m_p; getRefCounts().erase(itCounter); } m_p = nullptr; } } private: T* m_p; }; //============================================================================== // forward declaration template struct ContainerTraits; template struct ContainerTraits> { typedef T Type; static T* get(RefCountedPtr const& c) { return c.get(); } }; } // namespace luabridge