//////////////////////////////////////////////////////////////////////////////// // 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. //////////////////////////////////////////////////////////////////////////////// // ported RefCountedMT // To create a SmartPtr with RefCountedMT as ownership policy // use code like this: // SmartPtr > pointer; // // replaced all template template parameters with 'normal' parameters // For each Policy there is now a wrapper-class (non template class) // containing a nested template class called In which // provides a typedef (type) to the real Policy-class // // VC special: The MSVC 6.0 introduces an order-dependency for template ctor // resp. template assignemt operators. // If you need both a copy-ctor and a template copy ctor (same for copy-assignment), then // you *must* write the templated version first. // So instead of // template // struct Foo // { // Foo(const Foo&) // {} // template // Foo(const Foo& r) // {} // }; // you *need* to write: // template // struct Foo // { // template // Foo(const Foo& r) // {} // // Foo(const Foo& r) // {} // }; // // Many thanks to Nelson Elói for pointing that out and for providing me // with this solution #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 "MSVC6Helpers.h" #include "static_check.h" #include "NullType.h" #include #include #include namespace Loki { //////////////////////////////////////////////////////////////////////////////// // class template DefaultSPStorage // Implementation of the StoragePolicy used by SmartPtr //////////////////////////////////////////////////////////////////////////////// template class DefaultSPStorage { public: 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 // do not alter the order of the following two constructors // otherwise the MSVC 6.0 will not compile the class. template DefaultSPStorage(const DefaultSPStorage&) {} 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_; }; struct DefaultSPStorageWrapper { template struct In { typedef DefaultSPStorage type; }; }; //////////////////////////////////////////////////////////////////////////////// // 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; } // do not alter the order of the following two constructors // otherwise the MSVC 6.0 will fail to compile the class. // MWCW lacks template friends, hence the following kludge template RefCounted(const RefCounted& rhs) : pCount_(reinterpret_cast(rhs).pCount_) {} RefCounted(const RefCounted& rhs) : pCount_(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_; }; struct RefCountedWrapper { template struct In { typedef RefCounted type; }; }; //////////////////////////////////////////////////////////////////////////////// // class template RefCountedMT // Implementation of the OwnershipPolicy used by SmartPtr // Implements external reference counting for multithreaded programs //////////////////////////////////////////////////////////////////////////////// // template class RefCountedMT : public Apply1 > { public: typedef Apply1 > base_type; typedef typename base_type::IntType CountType; typedef volatile CountType *CountPtrType; RefCountedMT() { pCount_ = static_cast( SmallObject::operator new( sizeof(unsigned int))); assert(pCount_); *pCount_ = 1; } // MWCW lacks template friends, hence the following kludge // BK: Without the dummy-Parameter, the VC 6.0 won't compile the // copy ctor (error C2535: 'member function already defined or declared') // Adding the dummy-Parameter results in two things: // 1. The VC doesn't complain about the copy-ctor // 2. The VC *always* calls the template-copy-ctor, whether *this and rhs // have the same type or not. template RefCountedMT(const RefCountedMT& rhs, int dummy=0) : pCount_(reinterpret_cast&>(rhs).pCount_) {} RefCountedMT(const RefCountedMT& rhs) : pCount_(rhs.pCount_) {} P Clone(const P& val) { ThreadingModel::template In::AtomicIncrement(*pCount_); return val; } bool Release(const P&) { if (!ThreadingModel::template In::AtomicDecrement(*pCount_)) { SmallObject::operator delete( const_cast(pCount_), sizeof(*pCount_)); return true; } return false; } void Swap(RefCountedMT& rhs) { std::swap(pCount_, rhs.pCount_); } enum { destructiveCopy = false }; private: // Data //volatile unsigned int* pCount_; CountPtrType pCount_; }; template struct RefCountedMTWrapper { template struct In { typedef RefCountedMT type; }; }; //////////////////////////////////////////////////////////////////////////////// // 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&) {} }; struct COMRefCountedWrapper { template struct In { typedef COMRefCounted type; }; }; //////////////////////////////////////////////////////////////////////////////// // 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 }; }; struct DeepCopyWrapper { template struct In { typedef DeepCopy type; }; }; //////////////////////////////////////////////////////////////////////////////// // 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&) { typedef Private::RefLinkedBase MyBase; return this->MyBase::Release(); } }; struct RefLinkedWrapper { template struct In { typedef RefLinked type; }; }; //////////////////////////////////////////////////////////////////////////////// // 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 }; }; struct DestructiveCopyWrapper { template struct In { typedef DestructiveCopy type; }; }; //////////////////////////////////////////////////////////////////////////////// // 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&) { STATIC_CHECK(false, This_Policy_Disallows_Value_Copying); } static bool Release(const P&) { return true; } static void Swap(NoCopy&) {} enum { destructiveCopy = false }; }; struct NoCopyWrapper { template struct In { typedef NoCopy type; }; }; //////////////////////////////////////////////////////////////////////////////// // 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&) {} }; struct NoCheckWrapper { template struct In { typedef NoCheck type; }; }; //////////////////////////////////////////////////////////////////////////////// // 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&) {} }; struct AssertCheckWrapper { template struct In {typedef AssertCheck type;}; }; //////////////////////////////////////////////////////////////////////////////// // 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&) {} }; struct AssertCheckStrictWrapper { template struct In { typedef AssertCheckStrict type; }; }; //////////////////////////////////////////////////////////////////////////////// // 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&) {} }; struct RejectNullStaticWrapper { template struct In { typedef RejectNullStatic type; }; }; //////////////////////////////////////////////////////////////////////////////// // 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&) {} }; struct RejectNullWrapper { template struct In { typedef RejectNull type; }; }; //////////////////////////////////////////////////////////////////////////////// // 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&) {} }; struct RejectNullStrictWrapper { template struct In { typedef RejectNullStrict type; }; }; //////////////////////////////////////////////////////////////////////////////// // 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, class OwnershipPolicy = RefCountedWrapper, class ConversionPolicy = DisallowConversion, class CheckingPolicy = AssertCheckWrapper, class StoragePolicy = DefaultSPStorageWrapper > class SmartPtr; //////////////////////////////////////////////////////////////////////////////// // class template SmartPtr (definition) //////////////////////////////////////////////////////////////////////////////// namespace Private { template struct SmartPtrImpl { struct Dummy{}; typedef typename ApplyInnerType::type TempType; typedef VC_Base_Workaround sttype; // VC 6.0 will emit an "Error C2516. : is not a legal base class" // if one tries to use TempType as base class for SmartPtr. // Don't know why the compiler is happy with this workaround typedef sttype::LeftBase Storage; typedef Storage::PointerType PointerType; typedef Storage::StoredType StoredType; typedef Storage::ReferenceType ReferenceType; typedef typename ApplyInnerType::type Temp2Type; typedef typename ApplyInnerType::type Temp3Type; typedef VC_Base_Workaround owtype; typedef owtype::LeftBase Owner; typedef VC_Base_Workaround chtype; typedef chtype::LeftBase Checking; typedef Con Conversion; }; } template < typename T, class OwnershipPolicy, class ConversionPolicy, class CheckingPolicy, class StoragePolicy > class SmartPtr : public Private::SmartPtrImpl::Storage , public Private::SmartPtrImpl::Owner , public Private::SmartPtrImpl::Checking , public Private::SmartPtrImpl::Conversion { public: typedef typename Private::SmartPtrImpl < T, OwnershipPolicy, ConversionPolicy, CheckingPolicy, StoragePolicy >::Storage SP; typedef SP::PointerType PointerType; typedef SP::StoredType StoredType; typedef SP::ReferenceType ReferenceType; typedef typename Private::SmartPtrImpl < T, OwnershipPolicy, ConversionPolicy, CheckingPolicy, StoragePolicy >::Owner OP; typedef typename Private::SmartPtrImpl < T, OwnershipPolicy, ConversionPolicy, CheckingPolicy, StoragePolicy >::Checking KP; typedef ConversionPolicy CP; typedef typename Select < OP::destructiveCopy, SmartPtr, const SmartPtr >::Result CopyArg; typedef typename Select < OP::destructiveCopy, NullType, StoredType >::Result WorkaroundType; // i think the following two ctors have an exception-safety problem // in the original version. If KP throws one can't release the resources // which were possibly allocated by SP and/or OP. // don't know if my solution works. SmartPtr() { try { KP::OnDefault(GetImpl(*this)); } catch(...) { if (OP::Release(GetImpl(*static_cast(this)))) { SP::Destroy(); } throw; } } SmartPtr(const StoredType& p) : SP(p) { try { KP::OnInit(GetImpl(*this)); } catch(...) { if (OP::Release(GetImpl(*static_cast(this)))) { SP::Destroy(); } throw; } } SmartPtr(ByRef rhs) : SP(rhs), OP(rhs), KP(rhs), CP(rhs) {} // do not alter the order of the following three constructors // otherwise the MSVC 6.0 will fail to compile the class. template < typename T1, class OP1, class CP1, class KP1, class SP1 > SmartPtr(const SmartPtr& rhs) : SP(rhs), OP(rhs), KP(rhs), CP(rhs) { GetImplRef(*this) = OP::Clone(GetImplRef(rhs)); } template < typename T1, class OP1, class CP1, class KP1, class SP1 > SmartPtr(SmartPtr& rhs) : SP(rhs), OP(rhs), KP(rhs), CP(rhs) { GetImplRef(*this) = OP::Clone(GetImplRef(rhs)); } SmartPtr(CopyArg& rhs) : SP(rhs), OP(rhs), KP(rhs), CP(rhs) { GetImplRef(*this) = OP::Clone(GetImplRef(rhs)); } operator ByRef() { return ByRef(*this); } // do not alter the order of the following three copy-assignment operators // otherwise the MSVC 6.0 will fail to compile the class. template < typename T1, class OP1, class CP1, class KP1, class SP1 > SmartPtr& operator=(const SmartPtr& rhs) { SmartPtr temp(rhs); temp.Swap(*this); return *this; } template < typename T1, class OP1, class CP1, class KP1, class SP1 > SmartPtr& operator=(SmartPtr& rhs) { SmartPtr temp(rhs); temp.Swap(*this); return *this; } SmartPtr& operator=(CopyArg& rhs) { SmartPtr temp(rhs); temp.Swap(*this); return *this; } SmartPtr& operator=(const WorkaroundType& arg) { SmartPtr temp(arg); //return *this = const_cast(temp); return *this = temp; } 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, StoredType& p) { p = GetImplRef(sp); GetImplRef(sp) = SP::Default(); } friend inline void Reset(SmartPtr& 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, class OP1, class CP1, class KP1, class SP1 > bool operator==(const SmartPtr& rhs) const { return *this == GetImpl(rhs); } // Ambiguity buster template < typename T1, class OP1, class CP1, class KP1, class SP1 > bool operator!=(const SmartPtr& rhs) const { return !(*this == rhs); } // Ambiguity buster template < typename T1, class OP1, class CP1, class KP1, 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, class OP, class CP, class KP, 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, class OP, class CP, class KP, 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, class OP, class CP, class KP, 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, class OP, class CP, class KP, 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, class OP, class CP, class KP, 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, class OP, class CP, class KP, 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, class OP, class CP, class KP, 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, class OP, class CP, class KP, 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, class OP, class CP, class KP, 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, class OP, class CP, class KP, 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, class OP, class CP, class KP, 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, class OP, class CP, class KP, class SP, typename U > inline bool operator>=(const U* lhs, const SmartPtr& rhs) { return !(lhs < rhs); } } // namespace Loki //////////////////////////////////////////////////////////////////////////////// // specialization of std::less for SmartPtr //////////////////////////////////////////////////////////////////////////////// // MSVC 6.0 does not support partial template specialization :-( #if !defined(_MSC_VER) namespace std { template < typename T, class OP, class CP, class KP, 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)); } }; } #else // macros that help to specialize std::less for smarptrs. #define SMARTPTR_SPECIALIZE_LESS_5(T, OP, CP, KP, SP) \ namespace std \ { \ struct less< Loki::SmartPtr > \ : public binary_function, \ Loki::SmartPtr, bool> \ { \ bool operator()(const Loki::SmartPtr& lhs, \ const Loki::SmartPtr& rhs) const \ { \ typedef ApplyInnerType::type TempType; \ const TempType& rlhs = lhs; \ const TempType& rrhs = rhs; \ return less()(GetImpl(rlhs), GetImpl(rrhs)); \ } \ }; \ } #define SMARTPTR_SPECIALIZE_LESS_4(T, OP, CP, KP) \ SMARTPTR_SPECIALIZE_LESS_5(T, OP, CP, KP, DefaultSPStorageWrapper) #define SMARTPTR_SPECIALIZE_LESS_3(T, OP, CP) \ SMARTPTR_SPECIALIZE_LESS_5(T, OP, CP, AssertCheckWrapper, DefaultSPStorageWrapper) #define SMARTPTR_SPECIALIZE_LESS_2(T, OP) \ SMARTPTR_SPECIALIZE_LESS_5(T, OP, DisallowConversion, AssertCheckWrapper, DefaultSPStorageWrapper) #define SMARTPTR_SPECIALIZE_LESS(T) \ SMARTPTR_SPECIALIZE_LESS_5(T, RefCountedWrapper, DisallowConversion, AssertCheckWrapper, DefaultSPStorageWrapper) #endif //////////////////////////////////////////////////////////////////////////////// // Change log: // June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!! // December 09, 2001: Included // Oct 26, 2002: ported by Benjamin Kaufmann to MSVC 6.0 // Feb 24, 2003: ported RefCountedMT. In NoCopy replaced CT_ASSERT with // STATIC_CHECK. B.K. // Mar 06, 2003: added helper-macros for specializing std::less for // Smart-Pointers. //////////////////////////////////////////////////////////////////////////////// #endif // SMARTPTR_INC_