/* SPDX-License-Identifier: MIT */ /** @file ajarefptr.h @copyright (C) 2013-2021 AJA Video Systems, Inc. All rights reserved. @brief Defines the AJARefPtr template class. **/ #if !defined (__AJAREFPTR__) #define __AJAREFPTR__ #include "../system/atomic.h" /** @brief I am the referent object that maintains the reference count and the pointer to the underlying object whose lifespan I manage. @note I am not designed to be used as a superclass, therefore, none of my methods are virtual. **/ template class Referent { // Instance Methods public: // Constructor Referent (TRef * ptr); // Reference Count Management void AddRef () throw (); void RemoveRef () throw (); // Access To Underlying Object TRef * get () const throw(); // Instance Data private: uint32_t m_nCount; // Reference count TRef * m_pointer; // Pointer to underlying object I refer to }; // Referent template Referent ::Referent (TRef * ptr) : m_nCount (1), m_pointer (ptr) { } template void Referent ::AddRef (void) throw () { AJAAtomic::Increment(&m_nCount); } template void Referent ::RemoveRef (void) throw () { if (m_nCount > 0) { if (AJAAtomic::Decrement(&m_nCount) == 0) { delete m_pointer; m_pointer = 0; delete this; } } } template TRef * Referent ::get (void) const throw () { return m_pointer; } /** @brief I am a reference-counted pointer template class. I am intended to be a proxy for an underlying object, whose lifespan is automatically managed by the Referent template class that I work with. @note Be sure not to create more than one of me using the same object pointer or else a double-free will ensue. **/ template class AJARefPtr { public: typedef TRef element_type; // Construction & Destruction explicit AJARefPtr (TRef * ptr = NULL) throw (); AJARefPtr (const AJARefPtr& obToCopy ) throw (); ~AJARefPtr () throw (); // Assignment AJARefPtr& operator = (const AJARefPtr& inRHS) throw (); AJARefPtr& operator = (TRef * pobRHS) throw (); // Comparison bool operator == (const AJARefPtr< TRef > & inRHS) const throw (); bool operator != (const AJARefPtr< TRef > & inRHS) const throw (); bool operator < (const AJARefPtr< TRef > & inRHS) const throw (); // Dereferencing TRef & operator * () const throw (); TRef * operator -> () const throw (); TRef * get () const throw (); // Testing operator bool () const throw (); private: Referent * m_pRef; // My referent }; // AJARefPtr template AJARefPtr ::AJARefPtr (TRef * ptr) throw () : m_pRef (new Referent (ptr)) { } template AJARefPtr ::AJARefPtr (const AJARefPtr & obToCopy) throw () : m_pRef (obToCopy.m_pRef) { m_pRef->AddRef (); } template AJARefPtr & AJARefPtr ::operator = (const AJARefPtr & inRHS) throw () { if (*this != inRHS) { if (m_pRef) m_pRef->RemoveRef (); m_pRef = inRHS.m_pRef; m_pRef->AddRef (); } return *this; } template AJARefPtr & AJARefPtr ::operator = (TRef * pobRHS) throw () { if (pobRHS != get ()) { if (m_pRef) m_pRef->RemoveRef (); m_pRef = new Referent (pobRHS); } return *this; } template AJARefPtr ::~AJARefPtr () throw () { m_pRef->RemoveRef (); } template bool AJARefPtr ::operator == (const AJARefPtr & inRHS) const throw () { return get() == inRHS.get(); } template bool AJARefPtr ::operator != (const AJARefPtr & inRHS) const throw () { return get() != inRHS.get (); } template bool AJARefPtr ::operator < (const AJARefPtr & inRHS) const throw () { return get() < inRHS.get (); } template TRef & AJARefPtr ::operator * () const throw () { return *(m_pRef->get()); } template TRef * AJARefPtr ::operator -> () const throw () { return m_pRef ? m_pRef->get () : NULL; } template TRef * AJARefPtr ::get () const throw () { return m_pRef ? m_pRef->get () : NULL; } template AJARefPtr ::operator bool () const throw () { return m_pRef && m_pRef->get () != 0; } #endif // __AJAREFPTR__