123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #ifndef CRYINCLUDE_CRYCOMMON_SMARTPTR_H
- #define CRYINCLUDE_CRYCOMMON_SMARTPTR_H
- #pragma once
- #include <platform.h>
- #include <type_traits>
- void CryFatalError(const char*, ...) PRINTF_PARAMS(1, 2);
- #if defined(APPLE)
- #include <cstddef>
- #endif
- #include <AzCore/std/parallel/atomic.h>
- //////////////////////////////////////////////////////////////////
- // SMART POINTER
- //////////////////////////////////////////////////////////////////
- template <class _I>
- class _smart_ptr
- {
- private:
- _I* p;
- public:
- _smart_ptr()
- : p(NULL) {}
- _smart_ptr(_I* p_)
- {
- p = p_;
- if (p)
- {
- p->AddRef();
- }
- }
- _smart_ptr(const _smart_ptr& p_)
- {
- p = p_.p;
- if (p)
- {
- p->AddRef();
- }
- }
- template <typename _Y>
- _smart_ptr(const _smart_ptr<_Y>& p_)
- {
- p = p_.get();
- if (p)
- {
- p->AddRef();
- }
- }
- ~_smart_ptr()
- {
- if (p)
- {
- p->Release();
- }
- }
- operator _I*() const {
- return p;
- }
- _I& operator*() const { return *p; }
- _I* operator->(void) const { return p; }
- _I* get() const { return p; }
- _smart_ptr& operator=(_I* newp)
- {
- if (newp)
- {
- newp->AddRef();
- }
- if (p)
- {
- p->Release();
- }
- p = newp;
- return *this;
- }
- void reset()
- {
- _smart_ptr<_I>().swap(*this);
- }
- void reset(_I* ptr)
- {
- _smart_ptr<_I>(ptr).swap(*this);
- }
- void attach(_I* p_)
- {
- p = p_;
- }
- _smart_ptr& operator=(const _smart_ptr& newp)
- {
- if (newp.p)
- {
- newp.p->AddRef();
- }
- if (p)
- {
- p->Release();
- }
- p = newp.p;
- return *this;
- }
- template <typename _Y>
- _smart_ptr& operator=(const _smart_ptr<_Y>& newp)
- {
- _I* const p2 = newp.get();
- if (p2)
- {
- p2->AddRef();
- }
- if (p)
- {
- p->Release();
- }
- p = p2;
- return *this;
- }
- // set our contained pointer to null, but don't call Release()
- // useful for when we want to do that ourselves, or when we know that
- // the contained pointer is invalid
- friend _I* ReleaseOwnership(_smart_ptr<_I>& ptr)
- {
- _I* ret = ptr.p;
- ptr.p = 0;
- return ret;
- }
- void swap(_smart_ptr<_I>& other)
- {
- std::swap(p, other.p);
- }
- };
- template <typename T>
- ILINE void swap(_smart_ptr<T>& a, _smart_ptr<T>& b)
- {
- a.swap(b);
- }
- // reference target without vtable for smart pointer
- // implements AddRef() and Release() strategy using reference counter of the specified type
- template <typename TDerived, typename Counter = int>
- class _reference_target_no_vtable
- {
- public:
- _reference_target_no_vtable()
- : m_nRefCounter (0)
- {
- }
- ~_reference_target_no_vtable()
- {
- //assert (!m_nRefCounter);
- }
- void AddRef()
- {
- AZ_Assert(m_nRefCounter >= 0, "Invalid ref count");
- ++m_nRefCounter;
- }
- void Release()
- {
- AZ_Assert(m_nRefCounter > 0, "Invalid ref count");
- if (--m_nRefCounter == 0)
- {
- delete static_cast<TDerived*>(this);
- }
- else if (m_nRefCounter < 0)
- {
- assert(0);
- CryFatalError("Deleting Reference Counted Object Twice");
- }
- }
- // Warning: use for debugging/statistics purposes only!
- Counter NumRefs()
- {
- return m_nRefCounter;
- }
- protected:
- Counter m_nRefCounter;
- };
- // reference target with vtable for smart pointer
- // implements AddRef() and Release() strategy using reference counter of the specified type
- template <typename Counter>
- class _reference_target
- {
- public:
- _reference_target()
- : m_nRefCounter (0)
- {
- }
- virtual ~_reference_target()
- {
- //assert (!m_nRefCounter);
- }
- void AddRef()
- {
- AZ_Assert(m_nRefCounter >= 0, "Invalid ref count");
- ++m_nRefCounter;
- }
- void Release()
- {
- AZ_Assert(m_nRefCounter > 0, "Invalid ref count");
- if (--m_nRefCounter == 0)
- {
- delete this;
- }
- else if (m_nRefCounter < 0)
- {
- assert(0);
- CryFatalError("Deleting Reference Counted Object Twice");
- }
- }
- // Warning: use for debugging/statistics purposes only!
- Counter NumRefs()
- {
- return m_nRefCounter;
- }
- protected:
- Counter m_nRefCounter;
- };
- // default implementation is int counter - for better alignment
- typedef _reference_target<int> _reference_target_t;
- // reference target for smart pointer with configurable destruct function
- // implements AddRef() and Release() strategy using reference counter of the specified type
- template <typename T, typename Counter = int>
- class _cfg_reference_target
- {
- public:
- typedef void (* DeleteFncPtr)(void*);
- _cfg_reference_target()
- : m_nRefCounter (0)
- , m_pDeleteFnc(operator delete)
- {
- }
- explicit _cfg_reference_target(DeleteFncPtr pDeleteFnc)
- : m_nRefCounter (0)
- , m_pDeleteFnc(pDeleteFnc)
- {
- }
- virtual ~_cfg_reference_target()
- {
- }
- void AddRef()
- {
- AZ_Assert(m_nRefCounter >= 0, "Invalid ref count");
- ++m_nRefCounter;
- }
- void Release()
- {
- AZ_Assert(m_nRefCounter > 0, "Invalid ref count");
- if (--m_nRefCounter == 0)
- {
- assert(m_pDeleteFnc);
- static_cast<T*>(this)->~T();
- m_pDeleteFnc(this);
- }
- else if (m_nRefCounter < 0)
- {
- assert(0);
- CryFatalError("Deleting Reference Counted Object Twice");
- }
- }
- // Sets the delete function with which this object is supposed to be deleted
- void SetDeleteFnc(DeleteFncPtr pDeleteFnc) { m_pDeleteFnc = pDeleteFnc; }
- // Warning: use for debugging/statistics purposes only!
- Counter NumRefs()
- {
- return m_nRefCounter;
- }
- protected:
- Counter m_nRefCounter;
- DeleteFncPtr m_pDeleteFnc;
- };
- // base class for interfaces implementing reference counting
- // derive your interface from this class and the descendants won't have to implement
- // the reference counting logic
- template <typename Counter>
- class _i_reference_target
- {
- public:
- _i_reference_target()
- : m_nRefCounter (0)
- {
- }
- virtual ~_i_reference_target()
- {
- }
- virtual void AddRef()
- {
- ++m_nRefCounter;
- }
- virtual void Release()
- {
- if (--m_nRefCounter == 0)
- {
- delete this;
- }
- else if (m_nRefCounter < 0)
- {
- assert(0);
- CryFatalError("Deleting Reference Counted Object Twice");
- }
- }
- // Warning: use for debugging/statistics purposes only!
- Counter NumRefs() const
- {
- return m_nRefCounter;
- }
- protected:
- Counter m_nRefCounter;
- };
- class CMultiThreadRefCount
- {
- public:
- CMultiThreadRefCount() {}
- virtual ~CMultiThreadRefCount() {}
- inline int AddRef()
- {
- return m_count.fetch_add(1, AZStd::memory_order_acq_rel) + 1; // because we get the original value back
- }
- inline int Release()
- {
- const int nCount = m_count.fetch_sub(1, AZStd::memory_order_acq_rel) - 1; // because we get the original value back
- AZ_Assert(nCount >= 0, "Deleting Reference Counted Object Twice");
- if (nCount == 0)
- {
- delete this;
- }
- return nCount;
- }
- inline int GetRefCount() const { return m_count.load(AZStd::memory_order_acquire); }
- protected:
- // Allows the memory for the object to be deallocated in the dynamic module where it was originally constructed, as it may use different memory manager (Debug/Release configurations)
- virtual void DeleteThis() { delete this; }
- private:
- AZStd::atomic_int m_count{ 0 };
- };
- // base class for interfaces implementing reference counting that needs to be thread-safe
- // derive your interface from this class and the descendants won't have to implement
- // the reference counting logic
- template <typename Counter>
- class _i_multithread_reference_target
- {
- public:
- _i_multithread_reference_target()
- : m_nRefCounter(0)
- {
- }
- virtual ~_i_multithread_reference_target()
- {
- }
- virtual void AddRef()
- {
- m_nRefCounter.fetch_add(1, AZStd::memory_order_acq_rel);
- }
- virtual void Release()
- {
- const int nCount = m_nRefCounter.fetch_sub(1, AZStd::memory_order_acq_rel) - 1; // because we get the original value back
- AZ_Assert(nCount >= 0, "Deleting Reference Counted Object Twice");
- if (nCount == 0)
- {
- delete this;
- }
- }
- Counter NumRefs() const { return m_nRefCounter.load(AZStd::memory_order_acquire); }
- protected:
- AZStd::atomic<Counter> m_nRefCounter{ 0 };
- };
- typedef _i_reference_target<int> _i_reference_target_t;
- typedef _i_multithread_reference_target<int> _i_multithread_reference_target_t;
- // TYPEDEF_AUTOPTR macro, declares Class_AutoPtr, which is the smart pointer to the given class,
- // and Class_AutoArray, which is the array(STL vector) of autopointers
- #ifdef ENABLE_NAIIVE_AUTOPTR
- // naiive autopointer makes it easier for Visual Assist to parse the declaration and sometimes is easier for debug
- #define TYPEDEF_AUTOPTR(T) typedef T* T##_AutoPtr; typedef std::vector<T##_AutoPtr> T##_AutoArray;
- #else
- #define TYPEDEF_AUTOPTR(T) typedef _smart_ptr<T> T##_AutoPtr; typedef std::vector<T##_AutoPtr> T##_AutoArray;
- #endif
- #endif // CRYINCLUDE_CRYCOMMON_SMARTPTR_H
|