/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ // Original file Copyright Crytek GMBH or its affiliates, used under license. // Description : smart pointer using the own allocator, parts are copied and changed from LOKI #ifndef CRYINCLUDE_TOOLS_PRT_SMARTPTRALLOCATOR_H #define CRYINCLUDE_TOOLS_PRT_SMARTPTRALLOCATOR_H #pragma once #include "SHAllocator.h" #include #include namespace NSH { template struct CompileTimeError; template<> struct CompileTimeError {}; //! class template SSelect //! Selects one of two types based upon a boolean constant //! Invocation: SSelect::Result //! where: //! flag is a compile-time boolean constant //! T and U are types //! Result evaluates to T if flag is true, and to U otherwise. template struct SSelect { typedef T Result; }; template struct SSelect { typedef U Result; }; //! default new and delete operator encapsulation to meet interface required by CRefCounted class CDefaultAllocator { public: void* new_mem(size_t Mem) { return ::operator new(Mem); } void delete_mem(void *pMem, size_t Mem) { ::operator delete(pMem); } }; //! class template CDefaultSPStorage //! Implementation of the StoragePolicy used by CSmartPtr template class CDefaultSPStorage { public: typedef T* StoredType; //! the type of the pointee_ object typedef T* PointerType; //! type returned by operator-> typedef T& ReferenceType; //! type returned by operator* CDefaultSPStorage() : pointee_(Default()) {} //! The storage policy doesn't initialize the stored pointer //! which will be initialized by the OwnershipPolicy's Clone fn CDefaultSPStorage(const CDefaultSPStorage&) {} template CDefaultSPStorage(const CDefaultSPStorage&) {} CDefaultSPStorage(const StoredType& p) : pointee_(p) {} PointerType operator->() const { return pointee_; } ReferenceType operator*() const { return *pointee_; } void Swap(CDefaultSPStorage& rhs) { std::swap(pointee_, rhs.pointee_); } //! Accessors friend inline PointerType GetImpl(const CDefaultSPStorage& sp) { return sp.pointee_; } friend inline const StoredType& GetImplRef(const CDefaultSPStorage& sp) { return sp.pointee_; } friend inline StoredType& GetImplRef(CDefaultSPStorage& 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: StoredType pointee_; //! Data }; //! class template CRefCounted //! Implementation of the OwnershipPolicy used by CSmartPtr //! Provides a classic external reference counting implementation // template //uses normal allocator // template //uses own allocator // class CRefCounted; template class CRefCounted { public: CRefCounted() { static A sAllocator; pCount_ = static_cast(sAllocator.new_mem(sizeof(unsigned int))); assert(pCount_); *pCount_ = 1; } CRefCounted(const CRefCounted& rhs) : pCount_(rhs.pCount_) {} template CRefCounted(const CRefCounted& rhs) : pCount_(reinterpret_cast(rhs).pCount_) {} P Clone(const P& val) { ++*pCount_; return val; } bool Release(const P&) { if (!--*pCount_) { static A sAllocator; sAllocator.delete_mem(pCount_, sizeof(unsigned int)); return true; } return false; } void Swap(CRefCounted& rhs) { std::swap(pCount_, rhs.pCount_); } enum { destructiveCopy = false }; private: unsigned int* pCount_; //! Data }; //! class template CCOMRefCounted //! Implementation of the OwnershipPolicy used by CSmartPtr //! Adapts COM intrusive reference counting to OwnershipPolicy-specific syntax // template // class CCOMRefCounted; template class CCOMRefCounted { public: CCOMRefCounted() {} template CCOMRefCounted(const CCOMRefCounted&) {} 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(CCOMRefCounted&) {} }; //! class template SDeepCopy //! Implementation of the OwnershipPolicy used by CSmartPtr //! Implements deep copy semantics, assumes existence of a Clone() member function of the pointee type template struct SDeepCopy { SDeepCopy() {} template SDeepCopy(const SDeepCopy&) {} static P Clone(const P& val) { return val->Clone(); } static bool Release(const P& val) { return true; } static void Swap(SDeepCopy&) {} enum { destructiveCopy = false }; }; //! class template CRefLinked //! Implementation of the OwnershipPolicy used by CSmartPtr //! Implements reference linking namespace NPrivate { class CRefLinkedBase { public: CRefLinkedBase() { prev_ = next_ = this; } CRefLinkedBase(const CRefLinkedBase& 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(CRefLinkedBase& 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 CRefLinkedBase* prev_; mutable const CRefLinkedBase* next_; }; } template class CRefLinked : public NPrivate::CRefLinkedBase { public: CRefLinked() {} template CRefLinked(const CRefLinked& rhs) : NPrivate::CRefLinkedBase(rhs) {} static P Clone(const P& val) { return val; } bool Release(const P&) { return NPrivate::CRefLinkedBase::Release(); } }; //! class template CDestructiveCopy //! Implementation of the OwnershipPolicy used by CSmartPtr //! Implements destructive copy semantics (a la std::auto_ptr) template class CDestructiveCopy { public: CDestructiveCopy() {} template CDestructiveCopy(const CDestructiveCopy&) {} template static P Clone(P1& val) { P result(val); val = P1(); return result; } static bool Release(const P&) { return true; } static void Swap(CDestructiveCopy&) {} enum { destructiveCopy = true }; }; //! class template SAllowConversion //! Implementation of the ConversionPolicy used by CSmartPtr //! Allows implicit conversion from CSmartPtr to the pointee type struct SAllowConversion { enum { allow = true }; void Swap(SAllowConversion&) {} }; //! class template SDisallowConversion //! Implementation of the ConversionPolicy used by CSmartPtr //! Does not allow implicit conversion from CSmartPtr to the pointee type //! You can initialize a SDisallowConversion with an SAllowConversion struct SDisallowConversion { SDisallowConversion() {} SDisallowConversion(const SAllowConversion&) {} enum { allow = false }; void Swap(SDisallowConversion&) {} }; //! class template SNoCheck //! Implementation of the CheckingPolicy used by CSmartPtr //! Well, it's clear what it does :o) template struct SNoCheck { SNoCheck() {} template SNoCheck(const SNoCheck&) {} static void OnDefault(const P&) {} static void OnInit(const P&) {} static void OnDereference(const P&) {} static void Swap(SNoCheck&) {} }; //! class template SAssertCheck //! Implementation of the CheckingPolicy used by CSmartPtr //! Checks the pointer before dereference template struct SAssertCheck { SAssertCheck() {} template SAssertCheck(const SAssertCheck&) {} template SAssertCheck(const SNoCheck&) {} static void OnDefault(const P&) {} static void OnInit(const P&) {} static void OnDereference(P val) { assert(val); } static void Swap(SAssertCheck&) {} }; //! class template SAssertCheckStrict //! Implementation of the CheckingPolicy used by CSmartPtr //! Checks the pointer against zero upon initialization and before dereference //! You can initialize an SAssertCheckStrict with an SAssertCheck template struct SAssertCheckStrict { SAssertCheckStrict() {} template SAssertCheckStrict(const SAssertCheckStrict&) {} template SAssertCheckStrict(const SAssertCheck&) {} template SAssertCheckStrict(const SNoCheck&) {} static void OnDefault(P val) { assert(val); } static void OnInit(P val) { assert(val); } static void OnDereference(P val) { assert(val); } static void Swap(SAssertCheckStrict&) {} }; /* //! class SNullPointerException //! Used by some implementations of the CheckingPolicy used by CSmartPtr struct SNullPointerException : public std::runtime_error { SNullPointerException() : std::runtime_error("") { } }; */ template struct SFalseType { enum { Value = false }; }; //! class template SRejectNullStatic //! Implementation of the CheckingPolicy used by CSmartPtr //! Checks the pointer upon initialization and before dereference template struct SRejectNullStatic { SRejectNullStatic() {} template SRejectNullStatic(const SRejectNullStatic&) {} template SRejectNullStatic(const SNoCheck&) {} template SRejectNullStatic(const SAssertCheck&) {} template SRejectNullStatic(const SAssertCheckStrict&) {} static void OnDefault(const P&) { CompileTimeError< SFalseType

::Value > ERROR_This_Policy_Does_Not_Allow_Default_Initialization; } static void OnInit(const P& val) {} static void OnDereference(const P& val) {} static void Swap(SRejectNullStatic&) {} }; //! class template SRejectNull //! Implementation of the CheckingPolicy used by CSmartPtr //! Checks the pointer before dereference template struct SRejectNull { SRejectNull() {} template SRejectNull(const SRejectNull&) {} static void OnInit(P val) {} static void OnDefault(P val) { OnInit(val); } void OnDereference(P val) { OnInit(val); } void Swap(SRejectNull&) {} }; //! class template SRejectNullStrict //! Implementation of the CheckingPolicy used by CSmartPtr //! Checks the pointer upon initialization and before dereference template struct SRejectNullStrict { SRejectNullStrict() {} template SRejectNullStrict(const SRejectNullStrict&) {} template SRejectNullStrict(const SRejectNull&) {} static void OnInit(P val) {} void OnDereference(P val) { OnInit(val); } void Swap(SRejectNullStrict&) {} }; //! class template CByRef //! Transports a reference as a value //! Serves to implement the Colvin/Gibbons trick for CSmartPtr template class CByRef { public: CByRef(T& v) : value_(v) {} operator T&() { return value_; } private: T& value_; }; //! class template CSmartPtr (declaration) //! The reason for all the fuss above template < typename T, class Allocator = CDefaultAllocator, template class OwnershipPolicy = CRefCounted, class ConversionPolicy = SDisallowConversion, template class CheckingPolicy = SAssertCheck, template class StoragePolicy = CDefaultSPStorage > class CSmartPtr; //! class template CSmartPtr (definition) template < typename T, class Allocator, template class OwnershipPolicy, class ConversionPolicy, template class CheckingPolicy, template class StoragePolicy > class CSmartPtr : public StoragePolicy , public OwnershipPolicy::PointerType, Allocator> , public CheckingPolicy::StoredType> , public ConversionPolicy { typedef StoragePolicy SP; typedef OwnershipPolicy::PointerType, Allocator> 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 SSelect::Result CopyArg; CSmartPtr() { KP::OnDefault(GetImpl(*this)); } CSmartPtr(const StoredType& p) : SP(p) { KP::OnInit(GetImpl(*this)); } CSmartPtr(CopyArg& rhs) : SP(rhs), OP(rhs), KP(rhs), CP(rhs) { GetImplRef(*this) = OP::Clone(GetImplRef(rhs)); } template < typename T1, class A, template class OP1, class CP1, template class KP1, template class SP1 > CSmartPtr(const CSmartPtr& rhs) : SP(rhs), OP(rhs), KP(rhs), CP(rhs) { GetImplRef(*this) = OP::Clone(GetImplRef(rhs)); } template < typename T1, class A, template class OP1, class CP1, template class KP1, template class SP1 > CSmartPtr(CSmartPtr& rhs) : SP(rhs), OP(rhs), KP(rhs), CP(rhs) { GetImplRef(*this) = OP::Clone(GetImplRef(rhs)); } CSmartPtr(CByRef rhs) : SP(rhs), OP(rhs), KP(rhs), CP(rhs) {} operator CByRef() { return CByRef(*this); } CSmartPtr& operator=(CopyArg& rhs) { CSmartPtr temp(rhs); temp.Swap(*this); return *this; } template < typename T1, class A, template class OP1, class CP1, template class KP1, template class SP1 > CSmartPtr& operator=(const CSmartPtr& rhs) { CSmartPtr temp(rhs); temp.Swap(*this); return *this; } template < typename T1, class A, template class OP1, class CP1, template class KP1, template class SP1 > CSmartPtr& operator=(CSmartPtr& rhs) { CSmartPtr temp(rhs); temp.Swap(*this); return *this; } void Swap(CSmartPtr& rhs) { OP::Swap(rhs); CP::Swap(rhs); KP::Swap(rhs); SP::Swap(rhs); } ~CSmartPtr() { if (OP::Release(GetImpl(*static_cast(this)))) { SP::Destroy(); } } friend inline void Release(CSmartPtr& sp, typename SP::StoredType& p) { p = GetImplRef(sp); GetImplRef(sp) = SP::Default(); } friend inline void Reset(CSmartPtr& sp, typename SP::StoredType p) { CSmartPtr(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 CSmartPtr& lhs, const T* rhs) { return GetImpl(lhs) == rhs; } inline friend bool operator==(const T* lhs, const CSmartPtr& rhs) { return rhs == lhs; } inline friend bool operator!=(const CSmartPtr& lhs, const T* rhs) { return !(lhs == rhs); } inline friend bool operator!=(const T* lhs, const CSmartPtr& rhs) { return rhs != lhs; } //! Ambiguity buster template < typename T1, class A, template class OP1, class CP1, template class KP1, template class SP1 > bool operator==(const CSmartPtr& rhs) const { return *this == GetImpl(rhs); } template < typename T1, class A, template class OP1, class CP1, template class KP1, template class SP1 > bool operator!=(const CSmartPtr& rhs) const { return !(*this == rhs); } //! Ambiguity buster template < typename T1, class A, template class OP1, class CP1, template class KP1, template class SP1 > bool operator<(const CSmartPtr& 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 SSelect::Result AutomaticConversionResult; public: operator AutomaticConversionResult() const { return GetImpl(*this); } }; //! free comparison operators for class template CSmartPtr //! operator== for lhs = CSmartPtr, rhs = raw pointer template < typename T, class A, template class OP, class CP, template class KP, template class SP, typename U > inline bool operator==(const CSmartPtr& lhs, const U* rhs) { return GetImpl(lhs) == rhs; } //! operator== for lhs = raw pointer, rhs = CSmartPtr template < typename T, class A, template class OP, class CP, template class KP, template class SP, typename U > inline bool operator==(const U* lhs, const CSmartPtr& rhs) { return rhs == lhs; } //! operator!= for lhs = CSmartPtr, rhs = raw pointer template < typename T, class A, template class OP, class CP, template class KP, template class SP, typename U > inline bool operator!=(const CSmartPtr& lhs, const U* rhs) { return !(lhs == rhs); } //! operator!= for lhs = raw pointer, rhs = CSmartPtr template < typename T, class A, template class OP, class CP, template class KP, template class SP, typename U > inline bool operator!=(const U* lhs, const CSmartPtr& rhs) { return rhs != lhs; } //! operator< for lhs = CSmartPtr, rhs = raw pointer -- NOT DEFINED template < typename T, class A, template class OP, class CP, template class KP, template class SP, typename U > inline bool operator<(const CSmartPtr& lhs, const U* rhs); //! operator< for lhs = raw pointer, rhs = CSmartPtr -- NOT DEFINED template < typename T, class A, template class OP, class CP, template class KP, template class SP, typename U > inline bool operator<(const U* lhs, const CSmartPtr& rhs); //! operator> for lhs = CSmartPtr, rhs = raw pointer -- NOT DEFINED template < typename T, class A, template class OP, class CP, template class KP, template class SP, typename U > inline bool operator>(const CSmartPtr& lhs, const U* rhs) { return rhs < lhs; } //! operator> for lhs = raw pointer, rhs = CSmartPtr template < typename T, class A, template class OP, class CP, template class KP, template class SP, typename U > inline bool operator>(const U* lhs, const CSmartPtr& rhs) { return rhs < lhs; } //! operator<= for lhs = CSmartPtr, rhs = raw pointer template < typename T, class A, template class OP, class CP, template class KP, template class SP, typename U > inline bool operator<=(const CSmartPtr& lhs, const U* rhs) { return !(rhs < lhs); } //! operator<= for lhs = raw pointer, rhs = CSmartPtr template < typename T, class A, template class OP, class CP, template class KP, template class SP, typename U > inline bool operator<=(const U* lhs, const CSmartPtr& rhs) { return !(rhs < lhs); } //! operator>= for lhs = CSmartPtr, rhs = raw pointer template < typename T, class A, template class OP, class CP, template class KP, template class SP, typename U > inline bool operator>=(const CSmartPtr& lhs, const U* rhs) { return !(lhs < rhs); } //! operator>= for lhs = raw pointer, rhs = CSmartPtr template < typename T, class A, template class OP, class CP, template class KP, template class SP, typename U > inline bool operator>=(const U* lhs, const CSmartPtr& rhs) { return !(lhs < rhs); } } #endif // CRYINCLUDE_TOOLS_PRT_SMARTPTRALLOCATOR_H