//////////////////////////////////////////////////////////////////////////////// // The Loki Library // Copyright (c) 2001 by Andrei Alexandrescu // This code accompanies the book: // Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design // Patterns Applied". Copyright (c) 2001. Addison-Wesley. // Permission to use, copy, modify, distribute and sell this software for any // purpose is hereby granted without fee, provided that the above copyright // notice appear in all copies and that both that copyright notice and this // permission notice appear in supporting documentation. // The author or Addison-Wesley Longman make no representations about the // suitability of this software for any purpose. It is provided "as is" // without express or implied warranty. //////////////////////////////////////////////////////////////////////////////// // Last update: June 20, 2001 #ifndef SMARTPTR_INC_ #define SMARTPTR_INC_ //////////////////////////////////////////////////////////////////////////////// // IMPORTANT NOTE // Due to threading issues, the OwnershipPolicy has been changed as follows: // Release() returns a boolean saying if that was the last release // so the pointer can be deleted by the StoragePolicy // IsUnique() was removed //////////////////////////////////////////////////////////////////////////////// #include "SmallObj.h" #include "TypeManip.h" #include "static_check.h" #include #include #include namespace Loki { //////////////////////////////////////////////////////////////////////////////// // class template DefaultSPStorage // Implementation of the StoragePolicy used by SmartPtr //////////////////////////////////////////////////////////////////////////////// template class DefaultSPStorage { protected: typedef T* StoredType; // the type of the pointee_ object typedef T* PointerType; // type returned by operator-> typedef T& ReferenceType; // type returned by operator* public: DefaultSPStorage() : pointee_(Default()) {} // The storage policy doesn't initialize the stored pointer // which will be initialized by the OwnershipPolicy's Clone fn DefaultSPStorage(const DefaultSPStorage&) {} template DefaultSPStorage(const DefaultSPStorage&) {} DefaultSPStorage(const StoredType& p) : pointee_(p) {} PointerType operator->() const { return pointee_; } ReferenceType operator*() const { return *pointee_; } void Swap(DefaultSPStorage& rhs) { std::swap(pointee_, rhs.pointee_); } // Accessors friend inline PointerType GetImpl(const DefaultSPStorage& sp) { return sp.pointee_; } friend inline const StoredType& GetImplRef(const DefaultSPStorage& sp) { return sp.pointee_; } friend inline StoredType& GetImplRef(DefaultSPStorage& sp) { return sp.pointee_; } protected: // Destroys the data stored // (Destruction might be taken over by the OwnershipPolicy) void Destroy() { delete pointee_; } // Default value to initialize the pointer static StoredType Default() { return 0; } private: // Data StoredType pointee_; }; //////////////////////////////////////////////////////////////////////////////// // class template RefCounted // Implementation of the OwnershipPolicy used by SmartPtr // Provides a classic external reference counting implementation //////////////////////////////////////////////////////////////////////////////// template class RefCounted { public: RefCounted() { pCount_ = static_cast( SmallObject<>::operator new(sizeof(unsigned int))); assert(pCount_); *pCount_ = 1; } RefCounted(const RefCounted& rhs) : pCount_(rhs.pCount_) {} // MWCW lacks template friends, hence the following kludge template RefCounted(const RefCounted& rhs) : pCount_(reinterpret_cast(rhs).pCount_) {} P Clone(const P& val) { ++*pCount_; return val; } bool Release(const P&) { if (!--*pCount_) { SmallObject<>::operator delete(pCount_, sizeof(unsigned int)); return true; } return false; } void Swap(RefCounted& rhs) { std::swap(pCount_, rhs.pCount_); } enum { destructiveCopy = false }; private: // Data unsigned int* pCount_; }; //////////////////////////////////////////////////////////////////////////////// // class template RefCountedMT // Implementation of the OwnershipPolicy used by SmartPtr // Implements external reference counting for multithreaded programs //////////////////////////////////////////////////////////////////////////////// template class ThreadingModel> class RefCountedMT : public ThreadingModel< RefCountedMT > { public: RefCountedMT() { pCount_ = static_cast( SmallObject::operator new( sizeof(unsigned int))); assert(pCount_); *pCount_ = 1; } RefCountedMT(const RefCountedMT& rhs) : pCount_(rhs.pCount_) {} // MWCW lacks template friends, hence the following kludge template RefCountedMT(const RefCountedMT& rhs) : pCount_(reinterpret_cast&>(rhs).pCount_) {} P Clone(const P& val) { ThreadingModel::AtomicIncrement(*pCount_); return val; } bool Release(const P&) { if (!ThreadingModel::AtomicDecrement(*pCount_)) { SmallObject::operator delete(pCount_, sizeof(unsigned int)); return true; } return false; } void Swap(RefCountedMT& rhs) { std::swap(pCount_, rhs.pCount_); } enum { destructiveCopy = false }; private: // Data volatile unsigned int* pCount_; }; //////////////////////////////////////////////////////////////////////////////// // class template COMRefCounted // Implementation of the OwnershipPolicy used by SmartPtr // Adapts COM intrusive reference counting to OwnershipPolicy-specific syntax //////////////////////////////////////////////////////////////////////////////// template class COMRefCounted { public: COMRefCounted() {} template COMRefCounted(const COMRefCounted&) {} static P Clone(const P& val) { val->AddRef(); return val; } static bool Release(const P& val) { val->Release(); return false; } enum { destructiveCopy = false }; static void Swap(COMRefCounted&) {} }; //////////////////////////////////////////////////////////////////////////////// // class template DeepCopy // Implementation of the OwnershipPolicy used by SmartPtr // Implements deep copy semantics, assumes existence of a Clone() member // function of the pointee type //////////////////////////////////////////////////////////////////////////////// template struct DeepCopy { DeepCopy() {} template DeepCopy(const DeepCopy&) {} static P Clone(const P& val) { return val->Clone(); } static bool Release(const P& val) { return true; } static void Swap(DeepCopy&) {} enum { destructiveCopy = false }; }; //////////////////////////////////////////////////////////////////////////////// // class template RefLinked // Implementation of the OwnershipPolicy used by SmartPtr // Implements reference linking //////////////////////////////////////////////////////////////////////////////// namespace Private { class RefLinkedBase { public: RefLinkedBase() { prev_ = next_ = this; } RefLinkedBase(const RefLinkedBase& rhs) { prev_ = &rhs; next_ = rhs.next_; prev_->next_ = this; next_->prev_ = this; } bool Release() { if (next_ == this) { assert(prev_ == this); return true; } prev_->next_ = next_; next_->prev_ = prev_; return false; } void Swap(RefLinkedBase& rhs) { if (next_ == this) { assert(prev_ == this); if (rhs.next_ == &rhs) { assert(rhs.prev_ == &rhs); // both lists are empty, nothing 2 do return; } prev_ = rhs.prev_; next_ = rhs.next_; prev_->next_ = next_->prev_ = this; rhs.next_ = rhs.prev_ = &rhs; return; } if (rhs.next_ == &rhs) { rhs.Swap(*this); return; } std::swap(prev_, rhs.prev_); std::swap(next_, rhs.next_); std::swap(prev_->next_, rhs.prev_->next_); std::swap(next_->prev_, rhs.next_->prev_); } enum { destructiveCopy = false }; private: mutable const RefLinkedBase* prev_; mutable const RefLinkedBase* next_; }; } template class RefLinked : public Private::RefLinkedBase { public: RefLinked() {} template RefLinked(const RefLinked& rhs) : Private::RefLinkedBase(rhs) {} static P Clone(const P& val) { return val; } bool Release(const P&) { return Private::RefLinkedBase::Release(); } }; //////////////////////////////////////////////////////////////////////////////// // class template DestructiveCopy // Implementation of the OwnershipPolicy used by SmartPtr // Implements destructive copy semantics (a la std::auto_ptr) //////////////////////////////////////////////////////////////////////////////// template class DestructiveCopy { public: DestructiveCopy() {} template DestructiveCopy(const DestructiveCopy&) {} template static P Clone(P1& val) { P result(val); val = P1(); return result; } static bool Release(const P&) { return true; } static void Swap(DestructiveCopy&) {} enum { destructiveCopy = true }; }; //////////////////////////////////////////////////////////////////////////////// // class template NoCopy // Implementation of the OwnershipPolicy used by SmartPtr // Implements a policy that doesn't allow copying objects //////////////////////////////////////////////////////////////////////////////// template class NoCopy { public: NoCopy() {} template NoCopy(const NoCopy&) {} static P Clone(const P&) { CT_ASSERT(false, This_Policy_Disallows_Value_Copying); } static bool Release(const P&) { return true; } static void Swap(NoCopy&) {} enum { destructiveCopy = false }; }; //////////////////////////////////////////////////////////////////////////////// // class template AllowConversion // Implementation of the ConversionPolicy used by SmartPtr // Allows implicit conversion from SmartPtr to the pointee type //////////////////////////////////////////////////////////////////////////////// struct AllowConversion { enum { allow = true }; void Swap(AllowConversion&) {} }; //////////////////////////////////////////////////////////////////////////////// // class template DisallowConversion // Implementation of the ConversionPolicy used by SmartPtr // Does not allow implicit conversion from SmartPtr to the pointee type // You can initialize a DisallowConversion with an AllowConversion //////////////////////////////////////////////////////////////////////////////// struct DisallowConversion { DisallowConversion() {} DisallowConversion(const AllowConversion&) {} enum { allow = false }; void Swap(DisallowConversion&) {} }; //////////////////////////////////////////////////////////////////////////////// // class template NoCheck // Implementation of the CheckingPolicy used by SmartPtr // Well, it's clear what it does :o) //////////////////////////////////////////////////////////////////////////////// template struct NoCheck { NoCheck() {} template NoCheck(const NoCheck&) {} static void OnDefault(const P&) {} static void OnInit(const P&) {} static void OnDereference(const P&) {} static void Swap(NoCheck&) {} }; //////////////////////////////////////////////////////////////////////////////// // class template AssertCheck // Implementation of the CheckingPolicy used by SmartPtr // Checks the pointer before dereference //////////////////////////////////////////////////////////////////////////////// template struct AssertCheck { AssertCheck() {} template AssertCheck(const AssertCheck&) {} template AssertCheck(const NoCheck&) {} static void OnDefault(const P&) {} static void OnInit(const P&) {} static void OnDereference(P val) { assert(val); } static void Swap(AssertCheck&) {} }; //////////////////////////////////////////////////////////////////////////////// // class template AssertCheckStrict // Implementation of the CheckingPolicy used by SmartPtr // Checks the pointer against zero upon initialization and before dereference // You can initialize an AssertCheckStrict with an AssertCheck //////////////////////////////////////////////////////////////////////////////// template struct AssertCheckStrict { AssertCheckStrict() {} template AssertCheckStrict(const AssertCheckStrict&) {} template AssertCheckStrict(const AssertCheck&) {} template AssertCheckStrict(const NoCheck&) {} static void OnDefault(P val) { assert(val); } static void OnInit(P val) { assert(val); } static void OnDereference(P val) { assert(val); } static void Swap(AssertCheckStrict&) {} }; //////////////////////////////////////////////////////////////////////////////// // class NullPointerException // Used by some implementations of the CheckingPolicy used by SmartPtr //////////////////////////////////////////////////////////////////////////////// struct NullPointerException : public std::runtime_error { NullPointerException() : std::runtime_error("") { } const char* what() const throw() { return "Null Pointer Exception"; } }; //////////////////////////////////////////////////////////////////////////////// // class template RejectNullStatic // Implementation of the CheckingPolicy used by SmartPtr // Checks the pointer upon initialization and before dereference //////////////////////////////////////////////////////////////////////////////// template struct RejectNullStatic { RejectNullStatic() {} template RejectNullStatic(const RejectNullStatic&) {} template RejectNullStatic(const NoCheck&) {} template RejectNullStatic(const AssertCheck&) {} template RejectNullStatic(const AssertCheckStrict&) {} static void OnDefault(const P&) { CompileTimeError ERROR_This_Policy_Does_Not_Allow_Default_Initialization; } static void OnInit(const P& val) { if (!val) throw NullPointerException(); } static void OnDereference(const P& val) { if (!val) throw NullPointerException(); } static void Swap(RejectNullStatic&) {} }; //////////////////////////////////////////////////////////////////////////////// // class template RejectNull // Implementation of the CheckingPolicy used by SmartPtr // Checks the pointer before dereference //////////////////////////////////////////////////////////////////////////////// template struct RejectNull { RejectNull() {} template RejectNull(const RejectNull&) {} static void OnInit(P val) { if (!val) throw NullPointerException(); } static void OnDefault(P val) { OnInit(val); } void OnDereference(P val) { OnInit(val); } void Swap(RejectNull&) {} }; //////////////////////////////////////////////////////////////////////////////// // class template RejectNullStrict // Implementation of the CheckingPolicy used by SmartPtr // Checks the pointer upon initialization and before dereference //////////////////////////////////////////////////////////////////////////////// template struct RejectNullStrict { RejectNullStrict() {} template RejectNullStrict(const RejectNullStrict&) {} template RejectNullStrict(const RejectNull&) {} static void OnInit(P val) { if (!val) throw NullPointerException(); } void OnDereference(P val) { OnInit(val); } void Swap(RejectNullStrict&) {} }; //////////////////////////////////////////////////////////////////////////////// // class template ByRef // Transports a reference as a value // Serves to implement the Colvin/Gibbons trick for SmartPtr //////////////////////////////////////////////////////////////////////////////// template class ByRef { public: ByRef(T& v) : value_(v) {} operator T&() { return value_; } // gcc doesn't like this: // operator const T&() const { return value_; } private: T& value_; }; //////////////////////////////////////////////////////////////////////////////// // class template SmartPtr (declaration) // The reason for all the fuss above //////////////////////////////////////////////////////////////////////////////// template < typename T, template class OwnershipPolicy = RefCounted, class ConversionPolicy = DisallowConversion, template class CheckingPolicy = AssertCheck, template class StoragePolicy = DefaultSPStorage > class SmartPtr; //////////////////////////////////////////////////////////////////////////////// // class template SmartPtr (definition) //////////////////////////////////////////////////////////////////////////////// template < typename T, template class OwnershipPolicy, class ConversionPolicy, template class CheckingPolicy, template class StoragePolicy > class SmartPtr : public StoragePolicy , public OwnershipPolicy::PointerType> , public CheckingPolicy::StoredType> , public ConversionPolicy { typedef StoragePolicy SP; typedef OwnershipPolicy::PointerType> OP; typedef CheckingPolicy::StoredType> KP; typedef ConversionPolicy CP; public: typedef typename SP::PointerType PointerType; typedef typename SP::StoredType StoredType; typedef typename SP::ReferenceType ReferenceType; typedef typename Select::Result CopyArg; SmartPtr() { KP::OnDefault(GetImpl(*this)); } SmartPtr(const StoredType& p) : SP(p) { KP::OnInit(GetImpl(*this)); } SmartPtr(CopyArg& rhs) : SP(rhs), OP(rhs), KP(rhs), CP(rhs) { GetImplRef(*this) = OP::Clone(GetImplRef(rhs)); } template < typename T1, template class OP1, class CP1, template class KP1, template class SP1 > SmartPtr(const SmartPtr& rhs) : SP(rhs), OP(rhs), KP(rhs), CP(rhs) { GetImplRef(*this) = OP::Clone(GetImplRef(rhs)); } template < typename T1, template class OP1, class CP1, template class KP1, template class SP1 > SmartPtr(SmartPtr& rhs) : SP(rhs), OP(rhs), KP(rhs), CP(rhs) { GetImplRef(*this) = OP::Clone(GetImplRef(rhs)); } SmartPtr(ByRef rhs) : SP(rhs), OP(rhs), KP(rhs), CP(rhs) {} operator ByRef() { return ByRef(*this); } SmartPtr& operator=(CopyArg& rhs) { SmartPtr temp(rhs); temp.Swap(*this); return *this; } template < typename T1, template class OP1, class CP1, template class KP1, template class SP1 > SmartPtr& operator=(const SmartPtr& rhs) { SmartPtr temp(rhs); temp.Swap(*this); return *this; } template < typename T1, template class OP1, class CP1, template class KP1, template class SP1 > SmartPtr& operator=(SmartPtr& rhs) { SmartPtr temp(rhs); temp.Swap(*this); return *this; } void Swap(SmartPtr& rhs) { OP::Swap(rhs); CP::Swap(rhs); KP::Swap(rhs); SP::Swap(rhs); } ~SmartPtr() { if (OP::Release(GetImpl(*static_cast(this)))) { SP::Destroy(); } } friend inline void Release(SmartPtr& sp, typename SP::StoredType& p) { p = GetImplRef(sp); GetImplRef(sp) = SP::Default(); } friend inline void Reset(SmartPtr& sp, typename SP::StoredType p) { SmartPtr(p).Swap(sp); } PointerType operator->() { KP::OnDereference(GetImplRef(*this)); return SP::operator->(); } PointerType operator->() const { KP::OnDereference(GetImplRef(*this)); return SP::operator->(); } ReferenceType operator*() { KP::OnDereference(GetImplRef(*this)); return SP::operator*(); } ReferenceType operator*() const { KP::OnDereference(GetImplRef(*this)); return SP::operator*(); } bool operator!() const // Enables "if (!sp) ..." { return GetImpl(*this) == 0; } inline friend bool operator==(const SmartPtr& lhs, const T* rhs) { return GetImpl(lhs) == rhs; } inline friend bool operator==(const T* lhs, const SmartPtr& rhs) { return rhs == lhs; } inline friend bool operator!=(const SmartPtr& lhs, const T* rhs) { return !(lhs == rhs); } inline friend bool operator!=(const T* lhs, const SmartPtr& rhs) { return rhs != lhs; } // Ambiguity buster template < typename T1, template class OP1, class CP1, template class KP1, template class SP1 > bool operator==(const SmartPtr& rhs) const { return *this == GetImpl(rhs); } // Ambiguity buster template < typename T1, template class OP1, class CP1, template class KP1, template class SP1 > bool operator!=(const SmartPtr& rhs) const { return !(*this == rhs); } // Ambiguity buster template < typename T1, template class OP1, class CP1, template class KP1, template class SP1 > bool operator<(const SmartPtr& rhs) const { return *this < GetImpl(rhs); } private: // Helper for enabling 'if (sp)' struct Tester { Tester() {} private: void operator delete(void*); }; public: // enable 'if (sp)' operator Tester*() const { if (!*this) return 0; static Tester t; return &t; } private: // Helper for disallowing automatic conversion struct Insipid { Insipid(PointerType) {} }; typedef typename Select::Result AutomaticConversionResult; public: operator AutomaticConversionResult() const { return GetImpl(*this); } }; //////////////////////////////////////////////////////////////////////////////// // free comparison operators for class template SmartPtr //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // operator== for lhs = SmartPtr, rhs = raw pointer //////////////////////////////////////////////////////////////////////////////// template < typename T, template class OP, class CP, template class KP, template class SP, typename U > inline bool operator==(const SmartPtr& lhs, const U* rhs) { return GetImpl(lhs) == rhs; } //////////////////////////////////////////////////////////////////////////////// // operator== for lhs = raw pointer, rhs = SmartPtr //////////////////////////////////////////////////////////////////////////////// template < typename T, template class OP, class CP, template class KP, template class SP, typename U > inline bool operator==(const U* lhs, const SmartPtr& rhs) { return rhs == lhs; } //////////////////////////////////////////////////////////////////////////////// // operator!= for lhs = SmartPtr, rhs = raw pointer //////////////////////////////////////////////////////////////////////////////// template < typename T, template class OP, class CP, template class KP, template class SP, typename U > inline bool operator!=(const SmartPtr& lhs, const U* rhs) { return !(lhs == rhs); } //////////////////////////////////////////////////////////////////////////////// // operator!= for lhs = raw pointer, rhs = SmartPtr //////////////////////////////////////////////////////////////////////////////// template < typename T, template class OP, class CP, template class KP, template class SP, typename U > inline bool operator!=(const U* lhs, const SmartPtr& rhs) { return rhs != lhs; } //////////////////////////////////////////////////////////////////////////////// // operator< for lhs = SmartPtr, rhs = raw pointer -- NOT DEFINED //////////////////////////////////////////////////////////////////////////////// template < typename T, template class OP, class CP, template class KP, template class SP, typename U > inline bool operator<(const SmartPtr& lhs, const U* rhs); //////////////////////////////////////////////////////////////////////////////// // operator< for lhs = raw pointer, rhs = SmartPtr -- NOT DEFINED //////////////////////////////////////////////////////////////////////////////// template < typename T, template class OP, class CP, template class KP, template class SP, typename U > inline bool operator<(const U* lhs, const SmartPtr& rhs); //////////////////////////////////////////////////////////////////////////////// // operator> for lhs = SmartPtr, rhs = raw pointer -- NOT DEFINED //////////////////////////////////////////////////////////////////////////////// template < typename T, template class OP, class CP, template class KP, template class SP, typename U > inline bool operator>(const SmartPtr& lhs, const U* rhs) { return rhs < lhs; } //////////////////////////////////////////////////////////////////////////////// // operator> for lhs = raw pointer, rhs = SmartPtr //////////////////////////////////////////////////////////////////////////////// template < typename T, template class OP, class CP, template class KP, template class SP, typename U > inline bool operator>(const U* lhs, const SmartPtr& rhs) { return rhs < lhs; } //////////////////////////////////////////////////////////////////////////////// // operator<= for lhs = SmartPtr, rhs = raw pointer //////////////////////////////////////////////////////////////////////////////// template < typename T, template class OP, class CP, template class KP, template class SP, typename U > inline bool operator<=(const SmartPtr& lhs, const U* rhs) { return !(rhs < lhs); } //////////////////////////////////////////////////////////////////////////////// // operator<= for lhs = raw pointer, rhs = SmartPtr //////////////////////////////////////////////////////////////////////////////// template < typename T, template class OP, class CP, template class KP, template class SP, typename U > inline bool operator<=(const U* lhs, const SmartPtr& rhs) { return !(rhs < lhs); } //////////////////////////////////////////////////////////////////////////////// // operator>= for lhs = SmartPtr, rhs = raw pointer //////////////////////////////////////////////////////////////////////////////// template < typename T, template class OP, class CP, template class KP, template class SP, typename U > inline bool operator>=(const SmartPtr& lhs, const U* rhs) { return !(lhs < rhs); } //////////////////////////////////////////////////////////////////////////////// // operator>= for lhs = raw pointer, rhs = SmartPtr //////////////////////////////////////////////////////////////////////////////// template < typename T, template class OP, class CP, template class KP, template class SP, typename U > inline bool operator>=(const U* lhs, const SmartPtr& rhs) { return !(lhs < rhs); } } // namespace Loki //////////////////////////////////////////////////////////////////////////////// // specialization of std::less for SmartPtr //////////////////////////////////////////////////////////////////////////////// namespace std { template < typename T, template class OP, class CP, template class KP, template class SP > struct less< Loki::SmartPtr > : public binary_function, Loki::SmartPtr, bool> { bool operator()(const Loki::SmartPtr& lhs, const Loki::SmartPtr& rhs) const { return less()(GetImpl(lhs), GetImpl(rhs)); } }; } //////////////////////////////////////////////////////////////////////////////// // Change log: // June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!! // December 09, 2001: Included //////////////////////////////////////////////////////////////////////////////// #endif // SMARTPTR_INC_