9e3a736929
git-svn-id: svn://svn.code.sf.net/p/loki-lib/code/trunk@1052 7ec92016-0320-0410-acc4-a06ded1c099a
1781 lines
No EOL
49 KiB
C++
1781 lines
No EOL
49 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
||
// The Loki Library
|
||
// Copyright (c) 2006 Rich Sposato
|
||
// The copyright on this file is protected under the terms of the MIT license.
|
||
//
|
||
// 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 makes no representations about the
|
||
// suitability of this software for any purpose. It is provided "as is"
|
||
// without express or implied warranty.
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
#ifndef LOKI_STRONG_PTR_INC_
|
||
#define LOKI_STRONG_PTR_INC_
|
||
|
||
// $Id$
|
||
|
||
|
||
#include <loki/SmartPtr.h>
|
||
#if defined (LOKI_OBJECT_LEVEL_THREADING) || defined (LOKI_CLASS_LEVEL_THREADING)
|
||
#include <loki/Threads.h>
|
||
#endif
|
||
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
///
|
||
/// \par Terminology
|
||
/// These terms are used within this file's comments.
|
||
/// -# StrongPtr : Class used to implement both strong and weak pointers. The
|
||
/// second template parameter determines if a StrongPtr is weak or strong.
|
||
/// -# Strong pointer : A pointer that claims ownership of a shared object.
|
||
/// When the last strong copointer dies, the object is destroyed even if
|
||
/// there are weak copointers.
|
||
/// -# Weak pointer : A pointer that does not own the shared object it points
|
||
/// to. It only destroys the shared object if there no strong copointers
|
||
/// exist when it dies.
|
||
/// -# Copointers : All the pointers that refer to the same shared object.
|
||
/// The copointers must have the same ownership policy, but the other
|
||
/// policies may be different.
|
||
/// -# Pointee : The shared object.
|
||
///
|
||
/// \par OwnershipPolicy
|
||
/// The ownership policy has the pointer to the actual object, and it also
|
||
/// keeps track of the strong and weak copointers so that it can know if any
|
||
/// strong copointers remain. The plain pointer it maintains is stored as a
|
||
/// void pointer, which allows the ownership policy classes to be monolithic
|
||
/// classes instead of template classes. As monolithic classes, they reduce
|
||
/// amount of code-bloat.
|
||
///
|
||
/// \par Writing Your Own OwnershipPolicy
|
||
/// If you write your own policy, you must implement these 12 functions:
|
||
/// -# explicit YourPolicy( bool strong )
|
||
/// -# YourPolicy( void * p, bool strong )
|
||
/// -# YourPolicy( const YourPolicy & rhs, bool strong )
|
||
/// -# bool Release( bool strong )
|
||
/// -# void Increment( bool strong )
|
||
/// -# bool Decrement( bool strong )
|
||
/// -# bool HasStrongPointer( void ) const
|
||
/// -# void Swap( YourPolicy & rhs )
|
||
/// -# void SetPointer( void * p )
|
||
/// -# void ZapPointer( void )
|
||
/// -# void * GetPointer( void ) const
|
||
/// -# void * & GetPointerRef( void ) const
|
||
/// It is strongly recommended that all 12 of these functions be protected
|
||
/// instead of public. These two functions are optional for single-threaded
|
||
/// policies, but required for multi-threaded policies:
|
||
/// -# void Lock( void ) const
|
||
/// -# void Unlock( void ) const
|
||
/// This function is entirely optional:
|
||
/// -# bool Merge( TwoRefLinks & rhs )
|
||
///
|
||
/// \par DeletePolicy
|
||
/// The delete policy provides a mechanism to destroy an object and a default
|
||
/// value for an uninitialized pointer. You can override this policy with
|
||
/// your own when using the Singleton, NullObject, or Prototype design
|
||
/// patterns.
|
||
///
|
||
/// \par Writing Your Own DeletePolicy
|
||
/// If you write your own policy, you must implement these 3 functions:
|
||
/// -# void static Delete( const P * p )
|
||
/// -# static P * Default( void )
|
||
/// -# void Swap( YourResetPolicy & )
|
||
///
|
||
/// \par ResetPolicy
|
||
/// A reset policy tells the ReleaseAll and ResetAll functions whether they
|
||
/// should release or reset the StrongPtr copointers. These functions do
|
||
/// not affect just one StrongPtr, but all copointers. That is unlike
|
||
/// SmartPtr where the Release and Reset functions only affect 1 SmartPtr,
|
||
/// and leave all copointers untouched. A useful trick you can do with the
|
||
/// ResetPolicy is to not allow reset when a strong pointer exists, and then
|
||
/// use the NoCheck policy for all strong pointers. The reset policy
|
||
/// guarantees the strong pointers always have a valid pointee, so checking
|
||
/// is not required; but weak pointers may still require checking.
|
||
///
|
||
/// \par Writing Your Own ResetPolicy
|
||
/// If you write your own policy, you must implement these 2 functions:
|
||
/// -# bool OnReleaseAll( bool ) const
|
||
/// -# bool OnResetAll( bool ) const
|
||
/// The bool parameter means that this was called with a strong pointer or
|
||
/// one of its copointers is strong. The return value means the pointer
|
||
/// can be reset or released.
|
||
///
|
||
/// \defgroup StrongPointerOwnershipGroup StrongPtr Ownership policies
|
||
/// \ingroup SmartPointerGroup
|
||
/// \defgroup StrongPointerDeleteGroup Delete policies
|
||
/// \ingroup SmartPointerGroup
|
||
/// \defgroup StrongPointerResetGroup Reset policies
|
||
/// \ingroup SmartPointerGroup
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
namespace Loki
|
||
{
|
||
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
/// \class DeleteUsingFree
|
||
///
|
||
/// \ingroup StrongPointerDeleteGroup
|
||
/// Implementation of the DeletePolicy used by StrongPtr. Uses explicit call
|
||
/// to T's destructor followed by call to free. This policy is useful for
|
||
/// managing the lifetime of pointers to structs returned by C functions.
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
|
||
template < class P >
|
||
class DeleteUsingFree
|
||
{
|
||
public:
|
||
inline void static Delete( const P * p )
|
||
{
|
||
if ( 0 != p )
|
||
{
|
||
p->~P();
|
||
::free( p );
|
||
}
|
||
}
|
||
|
||
/// Provides default value to initialize the pointer
|
||
inline static P * Default( void )
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
inline void Swap( DeleteUsingFree & ) {}
|
||
};
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
/// \class DeleteNothing
|
||
///
|
||
/// \ingroup StrongPointerDeleteGroup
|
||
/// Implementation of the DeletePolicy used by StrongPtr. This will never
|
||
/// delete anything. You can use this policy with pointers to an undefined
|
||
/// type or a pure interface class with a protected destructor.
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
|
||
template < class P >
|
||
class DeleteNothing
|
||
{
|
||
public:
|
||
inline static void Delete( const P * )
|
||
{
|
||
// Do nothing at all!
|
||
}
|
||
|
||
inline static P * Default( void )
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
inline void Swap( DeleteNothing & ) {}
|
||
};
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
/// \class DeleteSingle
|
||
///
|
||
/// \ingroup StrongPointerDeleteGroup
|
||
/// Implementation of the DeletePolicy used by StrongPtr. This deletes just
|
||
/// one shared object. This is the default class for the DeletePolicy.
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
|
||
template < class P >
|
||
class DeleteSingle
|
||
{
|
||
public:
|
||
inline static void Delete( const P * p )
|
||
{
|
||
/** @note If you see an error message about a negative subscript, that
|
||
means your are attempting to use Loki to delete an incomplete type.
|
||
Please don't use this policy with incomplete types; you may want to
|
||
use DeleteNothing instead.
|
||
*/
|
||
typedef char Type_Must_Be_Defined[ sizeof(P) ? 1 : -1 ];
|
||
delete p;
|
||
}
|
||
|
||
inline static P * Default( void )
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
inline void Swap( DeleteSingle & ) {}
|
||
};
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
/// \class DeleteArray
|
||
///
|
||
/// \ingroup StrongPointerDeleteGroup
|
||
/// Implementation of the DeletePolicy used by StrongPtr. This deletes an
|
||
/// array of shared objects.
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
|
||
template < class P >
|
||
class DeleteArray
|
||
{
|
||
public:
|
||
inline static void Delete( const P * p )
|
||
{
|
||
/** @note If you see an error message about a negative subscript, that
|
||
means your are attempting to use Loki to delete an incomplete type.
|
||
Please don't use this policy with incomplete types; you may want to
|
||
use DeleteNothing instead.
|
||
*/
|
||
typedef char Type_Must_Be_Defined[ sizeof(P) ? 1 : -1 ];
|
||
delete [] p;
|
||
}
|
||
|
||
inline static P * Default( void )
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
inline void Swap( DeleteArray & ) {}
|
||
};
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
/// \class CantResetWithStrong
|
||
///
|
||
/// \ingroup StrongPointerResetGroup
|
||
/// Implementation of the ResetPolicy used by StrongPtr. This is the default
|
||
/// ResetPolicy for StrongPtr. It forbids reset and release only if a strong
|
||
/// copointer exists.
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
|
||
template < class P >
|
||
struct CantResetWithStrong
|
||
{
|
||
inline bool OnReleaseAll( bool hasStrongPtr ) const
|
||
{
|
||
return ! hasStrongPtr;
|
||
}
|
||
|
||
inline bool OnResetAll( bool hasStrongPtr ) const
|
||
{
|
||
return ! hasStrongPtr;
|
||
}
|
||
};
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
/// \class AllowReset
|
||
///
|
||
/// \ingroup StrongPointerResetGroup
|
||
/// Implementation of the ResetPolicy used by StrongPtr. It allows reset and
|
||
/// release under any circumstance.
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
|
||
template < class P >
|
||
struct AllowReset
|
||
{
|
||
inline bool OnReleaseAll( bool ) const
|
||
{
|
||
return true;
|
||
}
|
||
inline bool OnResetAll( bool ) const
|
||
{
|
||
return true;
|
||
}
|
||
};
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
/// \class NeverReset
|
||
///
|
||
/// \ingroup StrongPointerResetGroup
|
||
/// Implementation of the ResetPolicy used by StrongPtr. It forbids reset and
|
||
/// release under any circumstance.
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
|
||
template < class P >
|
||
struct NeverReset
|
||
{
|
||
inline bool OnReleaseAll( bool ) const
|
||
{
|
||
return false;
|
||
}
|
||
inline bool OnResetAll( bool ) const
|
||
{
|
||
return false;
|
||
}
|
||
};
|
||
|
||
// ----------------------------------------------------------------------------
|
||
|
||
namespace Private
|
||
{
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
/// \class TwoRefCountInfo
|
||
///
|
||
/// \ingroup StrongPointerOwnershipGroup
|
||
/// Implementation detail for reference counting strong and weak pointers.
|
||
/// It maintains a void pointer and 2 reference counts. Since it is just a
|
||
/// class for managing implementation details, it is not intended to be used
|
||
/// directly - which is why it is in a private namespace. Each instance is a
|
||
/// shared resource for all copointers, and there should be only one of these
|
||
/// for each set of copointers. This class is small, trivial, and inline.
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
|
||
class LOKI_EXPORT TwoRefCountInfo
|
||
{
|
||
public:
|
||
|
||
inline explicit TwoRefCountInfo( bool strong )
|
||
: m_pointer( 0 )
|
||
, m_strongCount( strong ? 1 : 0 )
|
||
, m_weakCount( strong ? 0 : 1 )
|
||
{
|
||
}
|
||
|
||
inline TwoRefCountInfo( void * p, bool strong )
|
||
: m_pointer( p )
|
||
, m_strongCount( strong ? 1 : 0 )
|
||
, m_weakCount( strong ? 0 : 1 )
|
||
{
|
||
}
|
||
|
||
inline ~TwoRefCountInfo( void )
|
||
{
|
||
assert( 0 == m_strongCount );
|
||
assert( 0 == m_weakCount );
|
||
}
|
||
|
||
inline bool HasStrongPointer( void ) const
|
||
{
|
||
return ( 0 < m_strongCount );
|
||
}
|
||
|
||
inline bool HasWeakPointer( void ) const
|
||
{
|
||
return ( 0 < m_weakCount );
|
||
}
|
||
|
||
inline void IncStrongCount( void )
|
||
{
|
||
++m_strongCount;
|
||
}
|
||
|
||
inline void IncWeakCount( void )
|
||
{
|
||
++m_weakCount;
|
||
}
|
||
|
||
inline bool DecStrongCount( void )
|
||
{
|
||
assert( 0 < m_strongCount );
|
||
--m_strongCount;
|
||
const bool isZero = ( 0 == m_strongCount );
|
||
return isZero;
|
||
}
|
||
|
||
inline void DecWeakCount( void )
|
||
{
|
||
assert( 0 < m_weakCount );
|
||
--m_weakCount;
|
||
}
|
||
|
||
inline void ZapPointer( void )
|
||
{
|
||
m_pointer = 0;
|
||
}
|
||
|
||
void SetPointer( void * p )
|
||
{
|
||
m_pointer = p;
|
||
}
|
||
|
||
inline void * GetPointer( void ) const
|
||
{
|
||
return m_pointer;
|
||
}
|
||
|
||
inline void * & GetPointerRef( void ) const
|
||
{
|
||
return const_cast< void * & >( m_pointer );
|
||
}
|
||
|
||
private:
|
||
/// Copy-constructor not implemented.
|
||
TwoRefCountInfo( const TwoRefCountInfo & );
|
||
/// Copy-assignment operator not implemented.
|
||
TwoRefCountInfo & operator = ( const TwoRefCountInfo & );
|
||
|
||
void * m_pointer;
|
||
unsigned int m_strongCount;
|
||
unsigned int m_weakCount;
|
||
};
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
/// \class LockableTwoRefCountInfo
|
||
///
|
||
/// \ingroup StrongPointerOwnershipGroup
|
||
/// Implementation detail for thread-safe reference counting for strong and
|
||
/// weak pointers. It uses TwoRefCountInfo to manage the pointer and counts.
|
||
/// All this does is provide a thread safety mechanism. Since it is just a
|
||
/// class for managing implementation details, it is not intended to be used
|
||
/// directly - which is why it is in a private namespace. Each instance is a
|
||
/// shared resource for all copointers, and there should be only one of these
|
||
/// for each set of copointers. This class is small, trivial, and inline.
|
||
///
|
||
/// \note This class is not designed for use with a single-threaded model.
|
||
/// Tests using a single-threaded model will not run properly, but tests in a
|
||
/// multi-threaded model with either class-level-locking or object-level-locking
|
||
/// do run properly.
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
|
||
#if defined (LOKI_OBJECT_LEVEL_THREADING) || defined (LOKI_CLASS_LEVEL_THREADING)
|
||
|
||
class LOKI_EXPORT LockableTwoRefCountInfo
|
||
: private Loki::Private::TwoRefCountInfo
|
||
{
|
||
public:
|
||
|
||
inline explicit LockableTwoRefCountInfo( bool strong )
|
||
: TwoRefCountInfo( strong )
|
||
, m_Mutex()
|
||
{
|
||
}
|
||
|
||
LockableTwoRefCountInfo( void * p, bool strong )
|
||
: TwoRefCountInfo( p, strong )
|
||
, m_Mutex()
|
||
{
|
||
}
|
||
|
||
inline ~LockableTwoRefCountInfo( void )
|
||
{
|
||
}
|
||
|
||
inline void Lock( void ) const
|
||
{
|
||
m_Mutex.Lock();
|
||
}
|
||
|
||
inline void Unlock( void ) const
|
||
{
|
||
m_Mutex.Unlock();
|
||
}
|
||
|
||
inline bool HasStrongPointer( void ) const
|
||
{
|
||
m_Mutex.Lock();
|
||
const bool has = TwoRefCountInfo::HasStrongPointer();
|
||
m_Mutex.Unlock();
|
||
return has;
|
||
}
|
||
|
||
inline bool HasWeakPointer( void ) const
|
||
{
|
||
m_Mutex.Lock();
|
||
const bool has = TwoRefCountInfo::HasWeakPointer();
|
||
m_Mutex.Unlock();
|
||
return has;
|
||
}
|
||
|
||
inline void IncStrongCount( void )
|
||
{
|
||
m_Mutex.Lock();
|
||
TwoRefCountInfo::IncStrongCount();
|
||
m_Mutex.Unlock();
|
||
}
|
||
|
||
inline void IncWeakCount( void )
|
||
{
|
||
m_Mutex.Lock();
|
||
TwoRefCountInfo::IncWeakCount();
|
||
m_Mutex.Unlock();
|
||
}
|
||
|
||
inline bool DecStrongCount( void )
|
||
{
|
||
m_Mutex.Lock();
|
||
const bool isZero = TwoRefCountInfo::DecStrongCount();
|
||
m_Mutex.Unlock();
|
||
return isZero;
|
||
}
|
||
|
||
inline void DecWeakCount( void )
|
||
{
|
||
m_Mutex.Lock();
|
||
TwoRefCountInfo::DecWeakCount();
|
||
m_Mutex.Unlock();
|
||
}
|
||
|
||
inline void ZapPointer( void )
|
||
{
|
||
m_Mutex.Lock();
|
||
TwoRefCountInfo::ZapPointer();
|
||
m_Mutex.Unlock();
|
||
}
|
||
|
||
void SetPointer( void * p )
|
||
{
|
||
m_Mutex.Lock();
|
||
TwoRefCountInfo::SetPointer( p );
|
||
m_Mutex.Unlock();
|
||
}
|
||
|
||
inline void * GetPointer( void ) const
|
||
{
|
||
return TwoRefCountInfo::GetPointer();
|
||
}
|
||
|
||
inline void * & GetPointerRef( void ) const
|
||
{
|
||
return TwoRefCountInfo::GetPointerRef();
|
||
}
|
||
|
||
private:
|
||
/// Default constructor is not available.
|
||
LockableTwoRefCountInfo( void );
|
||
/// Copy constructor is not available.
|
||
LockableTwoRefCountInfo( const LockableTwoRefCountInfo & );
|
||
/// Copy-assignment operator is not available.
|
||
LockableTwoRefCountInfo & operator = ( const LockableTwoRefCountInfo & );
|
||
|
||
mutable LOKI_DEFAULT_MUTEX m_Mutex;
|
||
};
|
||
|
||
#endif // if object-level-locking or class-level-locking
|
||
|
||
} // end namespace Private
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
/// \class TwoRefCounts
|
||
///
|
||
/// \ingroup StrongPointerOwnershipGroup
|
||
/// This implementation of StrongPtr's OwnershipPolicy uses a pointer to a
|
||
/// shared instance of TwoRefCountInfo. This is the default policy for
|
||
/// OwnershipPolicy. Some functions are trivial enough to be inline, while
|
||
/// others are implemented elsewhere. It is not thread safe, and is intended
|
||
/// for single-threaded environments.
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
|
||
class LOKI_EXPORT TwoRefCounts
|
||
{
|
||
protected:
|
||
|
||
explicit TwoRefCounts( bool strong );
|
||
|
||
TwoRefCounts( const void * p, bool strong );
|
||
|
||
TwoRefCounts( const TwoRefCounts & rhs, bool strong ) :
|
||
m_counts( rhs.m_counts )
|
||
{
|
||
Increment( strong );
|
||
}
|
||
|
||
TwoRefCounts( const TwoRefCounts & rhs, bool isNull, bool strong );
|
||
|
||
/** The destructor does not need to do anything since the call to
|
||
ZapPointer inside StrongPtr::~StrongPtr will do the cleanup which
|
||
this dtor would have done.
|
||
*/
|
||
inline ~TwoRefCounts( void ) {}
|
||
|
||
inline bool Release( bool strong )
|
||
{
|
||
return Decrement( strong );
|
||
}
|
||
|
||
bool HasStrongPointer( void ) const
|
||
{
|
||
return m_counts->HasStrongPointer();
|
||
}
|
||
|
||
void Swap( TwoRefCounts & rhs );
|
||
|
||
void SetPointer( void * p )
|
||
{
|
||
m_counts->SetPointer( p );
|
||
}
|
||
|
||
void ZapPointer( void );
|
||
|
||
inline void * & GetPointerRef( void ) const
|
||
{
|
||
return m_counts->GetPointerRef();
|
||
}
|
||
|
||
inline void * GetPointer( void ) const
|
||
{
|
||
return m_counts->GetPointer();
|
||
}
|
||
|
||
private:
|
||
TwoRefCounts( void );
|
||
TwoRefCounts & operator = ( const TwoRefCounts & );
|
||
|
||
void Increment( bool strong );
|
||
|
||
bool Decrement( bool strong );
|
||
|
||
/// Pointer to all shared data.
|
||
Loki::Private::TwoRefCountInfo * m_counts;
|
||
};
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
/// \class LockableTwoRefCounts
|
||
///
|
||
/// \ingroup StrongPointerOwnershipGroup
|
||
/// This implementation of StrongPtr's OwnershipPolicy uses a pointer to a
|
||
/// shared instance of LockableTwoRefCountInfo. It behaves very similarly to
|
||
/// TwoRefCounts, except that it provides thread-safety. Some functions are
|
||
/// trivial enough to be inline, while others are implemented elsewhere.
|
||
///
|
||
/// \note This class is not designed for use with a single-threaded model.
|
||
/// Tests using a single-threaded model will not run properly, but tests in a
|
||
/// multi-threaded model with either class-level-locking or object-level-locking
|
||
/// do run properly.
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
|
||
#if defined (LOKI_OBJECT_LEVEL_THREADING) || defined (LOKI_CLASS_LEVEL_THREADING)
|
||
|
||
class LOKI_EXPORT LockableTwoRefCounts
|
||
{
|
||
typedef SmallValueObject< ::Loki::ClassLevelLockable > ThreadSafePointerAllocator;
|
||
|
||
protected:
|
||
|
||
explicit LockableTwoRefCounts( bool strong )
|
||
: m_counts( NULL )
|
||
{
|
||
void * temp = ThreadSafePointerAllocator::operator new(
|
||
sizeof(Loki::Private::LockableTwoRefCountInfo) );
|
||
#ifdef DO_EXTRA_LOKI_TESTS
|
||
assert( temp != 0 );
|
||
#endif
|
||
m_counts = new ( temp ) Loki::Private::LockableTwoRefCountInfo( strong );
|
||
}
|
||
|
||
LockableTwoRefCounts( const void * p, bool strong )
|
||
: m_counts( NULL )
|
||
{
|
||
void * temp = ThreadSafePointerAllocator::operator new(
|
||
sizeof(Loki::Private::LockableTwoRefCountInfo) );
|
||
#ifdef DO_EXTRA_LOKI_TESTS
|
||
assert( temp != 0 );
|
||
#endif
|
||
void * p2 = const_cast< void * >( p );
|
||
m_counts = new ( temp )
|
||
Loki::Private::LockableTwoRefCountInfo( p2, strong );
|
||
}
|
||
|
||
LockableTwoRefCounts( const LockableTwoRefCounts & rhs, bool strong ) :
|
||
m_counts( rhs.m_counts )
|
||
{
|
||
Increment( strong );
|
||
}
|
||
|
||
LockableTwoRefCounts( const LockableTwoRefCounts & rhs, bool isNull, bool strong ) :
|
||
m_counts( ( isNull ) ? NULL : rhs.m_counts )
|
||
{
|
||
if ( isNull )
|
||
{
|
||
void * temp = ThreadSafePointerAllocator::operator new(
|
||
sizeof(Loki::Private::LockableTwoRefCountInfo) );
|
||
#ifdef DO_EXTRA_LOKI_TESTS
|
||
assert( temp != 0 );
|
||
#endif
|
||
m_counts = new ( temp ) Loki::Private::LockableTwoRefCountInfo( strong );
|
||
}
|
||
else
|
||
{
|
||
Increment( strong );
|
||
}
|
||
}
|
||
|
||
/** The destructor does not need to do anything since the call to
|
||
ZapPointer inside StrongPtr::~StrongPtr will do the cleanup which
|
||
this dtor would have done.
|
||
*/
|
||
inline ~LockableTwoRefCounts( void ) {}
|
||
|
||
inline void Lock( void ) const
|
||
{
|
||
m_counts->Lock();
|
||
}
|
||
|
||
inline void Unlock( void ) const
|
||
{
|
||
m_counts->Unlock();
|
||
}
|
||
|
||
inline bool Release( bool strong )
|
||
{
|
||
return Decrement( strong );
|
||
}
|
||
|
||
void Increment( bool strong )
|
||
{
|
||
if ( strong )
|
||
{
|
||
m_counts->IncStrongCount();
|
||
}
|
||
else
|
||
{
|
||
m_counts->IncWeakCount();
|
||
}
|
||
}
|
||
|
||
bool Decrement( bool strong )
|
||
{
|
||
bool noStrongPointers = false;
|
||
if ( strong )
|
||
{
|
||
noStrongPointers = m_counts->DecStrongCount();
|
||
}
|
||
else
|
||
{
|
||
m_counts->DecWeakCount();
|
||
noStrongPointers = !m_counts->HasStrongPointer();
|
||
}
|
||
return noStrongPointers;
|
||
}
|
||
|
||
bool HasStrongPointer( void ) const
|
||
{
|
||
return m_counts->HasStrongPointer();
|
||
}
|
||
|
||
void Swap( LockableTwoRefCounts & rhs )
|
||
{
|
||
std::swap( m_counts, rhs.m_counts );
|
||
}
|
||
|
||
void SetPointer( void * p )
|
||
{
|
||
m_counts->SetPointer( p );
|
||
}
|
||
|
||
void ZapPointer( void )
|
||
{
|
||
#ifdef DO_EXTRA_LOKI_TESTS
|
||
assert( !m_counts->HasStrongPointer() );
|
||
#endif
|
||
if ( m_counts->HasWeakPointer() )
|
||
{
|
||
m_counts->ZapPointer();
|
||
}
|
||
else
|
||
{
|
||
ThreadSafePointerAllocator::operator delete ( m_counts,
|
||
sizeof(Loki::Private::LockableTwoRefCountInfo) );
|
||
m_counts = NULL;
|
||
}
|
||
}
|
||
|
||
inline void * GetPointer( void ) const
|
||
{
|
||
return m_counts->GetPointer();
|
||
}
|
||
|
||
inline void * & GetPointerRef( void ) const
|
||
{
|
||
return m_counts->GetPointerRef();
|
||
}
|
||
|
||
private:
|
||
LockableTwoRefCounts( void );
|
||
LockableTwoRefCounts & operator = ( const LockableTwoRefCounts & );
|
||
|
||
/// Pointer to all shared data.
|
||
Loki::Private::LockableTwoRefCountInfo * m_counts;
|
||
};
|
||
|
||
#endif // if object-level-locking or class-level-locking
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
/// \class TwoRefLinks
|
||
///
|
||
/// \ingroup StrongPointerOwnershipGroup
|
||
/// This implementation of StrongPtr's OwnershipPolicy uses a doubly-linked
|
||
/// cycle of copointers to a shared object. Some functions are trivial enough
|
||
/// to be inline, while others are implemented in elsewhere. It is not thread
|
||
/// safe, and is intended for single-threaded environments.
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
|
||
class LOKI_EXPORT TwoRefLinks
|
||
{
|
||
protected:
|
||
|
||
inline explicit TwoRefLinks( bool strong )
|
||
: m_pointer( 0 )
|
||
, m_strong( strong )
|
||
{
|
||
m_prev = m_next = this;
|
||
}
|
||
|
||
TwoRefLinks( const void * p, bool strong );
|
||
|
||
TwoRefLinks( const TwoRefLinks & rhs, bool strong );
|
||
|
||
TwoRefLinks( const TwoRefLinks & rhs, bool isNull, bool strong );
|
||
|
||
bool Release( bool strong );
|
||
|
||
void Swap( TwoRefLinks & rhs );
|
||
|
||
bool Merge( TwoRefLinks & rhs );
|
||
|
||
bool HasStrongPointer( void ) const;
|
||
|
||
inline void ZapPointer( void )
|
||
{
|
||
ZapAllNodes();
|
||
}
|
||
|
||
void SetPointer( void * p );
|
||
|
||
inline void * GetPointer( void ) const
|
||
{
|
||
return m_pointer;
|
||
}
|
||
|
||
inline void * & GetPointerRef( void ) const
|
||
{
|
||
return const_cast< void * & >( m_pointer );
|
||
}
|
||
|
||
private:
|
||
static unsigned int CountPrevCycle( const TwoRefLinks * pThis );
|
||
static unsigned int CountNextCycle( const TwoRefLinks * pThis );
|
||
|
||
/// Not implemented.
|
||
TwoRefLinks( void );
|
||
/// Not implemented.
|
||
TwoRefLinks & operator = ( const TwoRefLinks & );
|
||
|
||
bool HasPrevNode( const TwoRefLinks * p ) const;
|
||
bool HasNextNode( const TwoRefLinks * p ) const;
|
||
bool AllNodesHaveSamePointer( void ) const;
|
||
void ZapAllNodes( void );
|
||
|
||
void * m_pointer;
|
||
mutable TwoRefLinks * m_prev;
|
||
mutable TwoRefLinks * m_next;
|
||
const bool m_strong;
|
||
};
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
/// \class StrongPtr
|
||
///
|
||
/// \ingroup SmartPointerGroup
|
||
///
|
||
/// \param Strong default = true,
|
||
/// \param OwnershipPolicy default = TwoRefCounts,
|
||
/// \param ConversionPolicy default = DisallowConversion,
|
||
/// \param CheckingPolicy default = AssertCheck,
|
||
/// \param ResetPolicy default = CantResetWithStrong,
|
||
/// \param DeletePolicy default = DeleteSingle
|
||
/// \param ConstnessPolicy default = LOKI_DEFAULT_CONSTNESS
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
|
||
template
|
||
<
|
||
typename T,
|
||
bool Strong = true,
|
||
class OwnershipPolicy = Loki::TwoRefCounts,
|
||
class ConversionPolicy = Loki::DisallowConversion,
|
||
template < class > class CheckingPolicy = Loki::AssertCheck,
|
||
template < class > class ResetPolicy = Loki::CantResetWithStrong,
|
||
template < class > class DeletePolicy = Loki::DeleteSingle,
|
||
template < class > class ConstnessPolicy = LOKI_DEFAULT_CONSTNESS
|
||
>
|
||
class StrongPtr
|
||
: public OwnershipPolicy
|
||
, public ConversionPolicy
|
||
, public CheckingPolicy< T * >
|
||
, public ResetPolicy< T >
|
||
, public DeletePolicy< T >
|
||
{
|
||
typedef ConversionPolicy CP;
|
||
typedef CheckingPolicy< T * > KP;
|
||
typedef ResetPolicy< T > RP;
|
||
typedef DeletePolicy< T > DP;
|
||
|
||
public:
|
||
|
||
typedef OwnershipPolicy OP;
|
||
|
||
typedef T * StoredType; // the type of the pointer
|
||
typedef T * PointerType; // type returned by operator->
|
||
typedef T & ReferenceType; // type returned by operator*
|
||
|
||
typedef typename ConstnessPolicy< T >::Type * ConstPointerType;
|
||
typedef typename ConstnessPolicy< T >::Type & ConstReferenceType;
|
||
|
||
private:
|
||
struct NeverMatched {};
|
||
|
||
#ifdef LOKI_SMARTPTR_CONVERSION_CONSTRUCTOR_POLICY
|
||
typedef typename Select< CP::allow, const StoredType&, NeverMatched>::Result ImplicitArg;
|
||
typedef typename Select<!CP::allow, const StoredType&, NeverMatched>::Result ExplicitArg;
|
||
#else
|
||
typedef const StoredType& ImplicitArg;
|
||
typedef typename Select<false, const StoredType&, NeverMatched>::Result ExplicitArg;
|
||
#endif
|
||
|
||
/// StrongPtr uses this helper class to specify the dynamic-caster constructor.
|
||
class DynamicCastHelper {};
|
||
|
||
/// Private constructor is only used for dynamic-casting.
|
||
template
|
||
<
|
||
typename T1,
|
||
bool S1,
|
||
class OP1,
|
||
class CP1,
|
||
template < class > class KP1,
|
||
template < class > class RP1,
|
||
template < class > class DP1,
|
||
template < class > class CNP1
|
||
>
|
||
StrongPtr( const StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs,
|
||
bool isNull, const DynamicCastHelper & helper )
|
||
// Dynamic casting from T1 to T and saving result in ownership policy.
|
||
: OP( rhs, isNull, Strong )
|
||
{
|
||
(void)helper; // do void cast to remove compiler warning.
|
||
}
|
||
|
||
/// Private constructor is only used for dynamic-casting.
|
||
template
|
||
<
|
||
typename T1,
|
||
bool S1,
|
||
class OP1,
|
||
class CP1,
|
||
template < class > class KP1,
|
||
template < class > class RP1,
|
||
template < class > class DP1,
|
||
template < class > class CNP1
|
||
>
|
||
StrongPtr( StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs,
|
||
bool isNull, const DynamicCastHelper & helper )
|
||
// Dynamic casting from T1 to T and saving result in ownership policy.
|
||
: OP( rhs, isNull, Strong )
|
||
{
|
||
(void)helper; // do void cast to remove compiler warning.
|
||
}
|
||
|
||
public:
|
||
|
||
StrongPtr( void ) : OP( Strong )
|
||
{
|
||
KP::OnDefault( GetPointer() );
|
||
}
|
||
|
||
explicit StrongPtr( ExplicitArg p ) : OP( p, Strong )
|
||
{
|
||
KP::OnInit( GetPointer() );
|
||
}
|
||
|
||
StrongPtr( ImplicitArg p ) : OP( p, Strong )
|
||
{
|
||
KP::OnInit( GetPointer() );
|
||
}
|
||
|
||
StrongPtr( const StrongPtr & rhs )
|
||
: OP( rhs, Strong ), CP( rhs ), KP( rhs ), DP( rhs )
|
||
{
|
||
}
|
||
|
||
template
|
||
<
|
||
typename T1,
|
||
bool S1,
|
||
class OP1,
|
||
class CP1,
|
||
template < class > class KP1,
|
||
template < class > class RP1,
|
||
template < class > class DP1,
|
||
template < class > class CNP1
|
||
>
|
||
StrongPtr(
|
||
const StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs )
|
||
: OP( rhs, Strong )
|
||
{
|
||
}
|
||
|
||
template
|
||
<
|
||
typename T1,
|
||
bool S1,
|
||
class OP1,
|
||
class CP1,
|
||
template < class > class KP1,
|
||
template < class > class RP1,
|
||
template < class > class DP1,
|
||
template < class > class CNP1
|
||
>
|
||
StrongPtr(
|
||
StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs )
|
||
: OP( rhs, Strong )
|
||
{
|
||
}
|
||
|
||
StrongPtr( RefToValue< StrongPtr > rhs )
|
||
: OP( rhs, Strong ), KP( rhs ), CP( rhs ), DP( rhs )
|
||
{
|
||
}
|
||
|
||
operator RefToValue< StrongPtr >( void )
|
||
{
|
||
return RefToValue< StrongPtr >( *this );
|
||
}
|
||
|
||
StrongPtr & operator = ( const StrongPtr & rhs )
|
||
{
|
||
if ( GetPointer() != rhs.GetPointer() )
|
||
{
|
||
StrongPtr temp( rhs );
|
||
temp.Swap( *this );
|
||
}
|
||
return *this;
|
||
}
|
||
|
||
StrongPtr & operator = ( T * p )
|
||
{
|
||
if ( GetPointer() != p )
|
||
{
|
||
StrongPtr temp( p );
|
||
Swap( temp );
|
||
}
|
||
return *this;
|
||
}
|
||
|
||
template
|
||
<
|
||
typename T1,
|
||
bool S1,
|
||
class OP1,
|
||
class CP1,
|
||
template < class > class KP1,
|
||
template < class > class RP1,
|
||
template < class > class DP1,
|
||
template < class > class CNP1
|
||
>
|
||
StrongPtr & operator = (
|
||
const StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs )
|
||
{
|
||
if ( !rhs.Equals( GetPointer() ) )
|
||
{
|
||
StrongPtr temp( rhs );
|
||
temp.Swap( *this );
|
||
}
|
||
return *this;
|
||
}
|
||
|
||
bool IsStrong( void ) const
|
||
{
|
||
return Strong;
|
||
}
|
||
|
||
void Swap( StrongPtr & rhs )
|
||
{
|
||
OP::Swap( rhs );
|
||
CP::Swap( rhs );
|
||
KP::Swap( rhs );
|
||
DP::Swap( rhs );
|
||
}
|
||
|
||
~StrongPtr()
|
||
{
|
||
if ( OP::Release( Strong ) )
|
||
{
|
||
// Must zap the pointer before deleteing the object. Otherwise a
|
||
// cycle of weak pointers will lead to recursion, which leads to
|
||
// to deleting the shared object multiple times, which leads to
|
||
// undefined behavior. Therefore, this must get pointer before
|
||
// zapping it, and then delete the temp pointer.
|
||
T * p = GetPointer();
|
||
OP::ZapPointer();
|
||
if ( p != 0 )
|
||
{
|
||
DP::Delete( p );
|
||
}
|
||
}
|
||
}
|
||
|
||
/// Dynamically-casts parameter pointer to the type specified by this SmartPtr type.
|
||
template
|
||
<
|
||
typename T1,
|
||
bool S1,
|
||
class OP1,
|
||
class CP1,
|
||
template < class > class KP1,
|
||
template < class > class RP1,
|
||
template < class > class DP1,
|
||
template < class > class CNP1
|
||
>
|
||
StrongPtr & DynamicCastFrom( const StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs )
|
||
{
|
||
typedef typename StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 >::PointerType RightPointerType;
|
||
const StrongPtr & sp = reinterpret_cast< const StrongPtr & >( rhs );
|
||
PointerType p = sp.GetPointer();
|
||
const RightPointerType rp = reinterpret_cast< const RightPointerType >( p );
|
||
p = dynamic_cast< const PointerType >( rp );
|
||
const bool isNull = ( NULL == p );
|
||
StrongPtr temp( rhs, isNull, DynamicCastHelper() );
|
||
Swap( temp );
|
||
return *this;
|
||
}
|
||
|
||
/// Dynamically-casts parameter pointer to the type specified by this SmartPtr type.
|
||
template
|
||
<
|
||
typename T1,
|
||
bool S1,
|
||
class OP1,
|
||
class CP1,
|
||
template < class > class KP1,
|
||
template < class > class RP1,
|
||
template < class > class DP1,
|
||
template < class > class CNP1
|
||
>
|
||
StrongPtr & DynamicCastFrom( StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs )
|
||
{
|
||
typedef typename StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 >::PointerType RightPointerType;
|
||
StrongPtr & sp = reinterpret_cast< StrongPtr & >( rhs );
|
||
PointerType p = sp.GetPointer();
|
||
RightPointerType rp = reinterpret_cast< RightPointerType >( p );
|
||
p = dynamic_cast< PointerType >( rp );
|
||
const bool isNull = ( NULL == p );
|
||
StrongPtr temp( rhs, isNull, DynamicCastHelper() );
|
||
Swap( temp );
|
||
return *this;
|
||
}
|
||
|
||
#ifdef LOKI_ENABLE_FRIEND_TEMPLATE_TEMPLATE_PARAMETER_WORKAROUND
|
||
|
||
// old non standard in class definition of friends
|
||
friend bool ReleaseAll( StrongPtr & sp,
|
||
typename StrongPtr::StoredType & p )
|
||
{
|
||
if ( !sp.RP::OnReleaseAll( sp.IsStrong() || sp.OP::HasStrongPointer() ) )
|
||
{
|
||
return false;
|
||
}
|
||
p = sp.GetPointer();
|
||
sp.OP::SetPointer( sp.DP::Default() );
|
||
return true;
|
||
}
|
||
|
||
friend bool ResetAll( StrongPtr & sp,
|
||
typename StrongPtr::StoredType p )
|
||
{
|
||
if ( sp.OP::GetPointer() == p )
|
||
{
|
||
return true;
|
||
}
|
||
if ( !sp.RP::OnResetAll( sp.IsStrong() || sp.OP::HasStrongPointer() ) )
|
||
{
|
||
return false;
|
||
}
|
||
sp.DP::Delete( sp.GetPointer() );
|
||
sp.OP::SetPointer( p );
|
||
return true;
|
||
}
|
||
|
||
#else
|
||
|
||
template
|
||
<
|
||
typename T1,
|
||
bool S1,
|
||
class OP1,
|
||
class CP1,
|
||
template < class > class KP1,
|
||
template < class > class RP1,
|
||
template < class > class DP1,
|
||
template < class > class CNP1
|
||
>
|
||
friend bool ReleaseAll( StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & sp,
|
||
typename StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 >::StoredType & p );
|
||
|
||
|
||
template
|
||
<
|
||
typename T1,
|
||
bool S1,
|
||
class OP1,
|
||
class CP1,
|
||
template < class > class KP1,
|
||
template < class > class RP1,
|
||
template < class > class DP1,
|
||
template < class > class CNP1
|
||
>
|
||
friend bool ResetAll( StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & sp,
|
||
typename StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 >::StoredType p );
|
||
|
||
#endif
|
||
|
||
|
||
/** Merges ownership of two StrongPtr's that point to same shared object
|
||
but are not copointers. Requires Merge function in OwnershipPolicy.
|
||
\return True for success, false if not pointer to same object.
|
||
*/
|
||
template
|
||
<
|
||
typename T1,
|
||
bool S1,
|
||
class OP1,
|
||
class CP1,
|
||
template < class > class KP1,
|
||
template < class > class RP1,
|
||
template < class > class DP1,
|
||
template < class > class CNP1
|
||
>
|
||
bool Merge( StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs )
|
||
{
|
||
if ( OP::GetPointer() != rhs.OP::GetPointer() )
|
||
{
|
||
return false;
|
||
}
|
||
return OP::Merge( rhs );
|
||
}
|
||
|
||
/** Locks StrongPtr so other threads can't affect pointer. Requires the
|
||
OwnershipPolicy to have Lock function.
|
||
*/
|
||
void Lock( void )
|
||
{
|
||
OP::Lock();
|
||
}
|
||
|
||
/** Unlocks StrongPtr so other threads can affect pointer. Requires the
|
||
OwnershipPolicy to have Unlock function.
|
||
*/
|
||
void Unlock( void )
|
||
{
|
||
OP::Unlock();
|
||
}
|
||
|
||
PointerType operator -> ()
|
||
{
|
||
KP::OnDereference( GetPointer() );
|
||
return GetPointer();
|
||
}
|
||
|
||
ConstPointerType operator -> () const
|
||
{
|
||
KP::OnDereference( GetPointer() );
|
||
return GetPointer();
|
||
}
|
||
|
||
ReferenceType operator * ()
|
||
{
|
||
KP::OnDereference( GetPointer() );
|
||
return * GetPointer();
|
||
}
|
||
|
||
ConstReferenceType operator * () const
|
||
{
|
||
KP::OnDereference( GetPointer() );
|
||
return * GetPointer();
|
||
}
|
||
|
||
/// Helper function which can be called to avoid exposing GetPointer function.
|
||
template < class T1 >
|
||
bool Equals( const T1 * p ) const
|
||
{
|
||
return ( GetPointer() == p );
|
||
}
|
||
|
||
/// Helper function which can be called to avoid exposing GetPointer function.
|
||
template < class T1 >
|
||
bool LessThan( const T1 * p ) const
|
||
{
|
||
return ( GetPointer() < p );
|
||
}
|
||
|
||
/// Helper function which can be called to avoid exposing GetPointer function.
|
||
template < class T1 >
|
||
bool GreaterThan( const T1 * p ) const
|
||
{
|
||
return ( GetPointer() > p );
|
||
}
|
||
|
||
/// Equality comparison operator is templated to handle ambiguity.
|
||
template
|
||
<
|
||
typename T1,
|
||
bool S1,
|
||
class OP1,
|
||
class CP1,
|
||
template < class > class KP1,
|
||
template < class > class RP1,
|
||
template < class > class DP1,
|
||
template < class > class CNP1
|
||
>
|
||
bool operator == (
|
||
const StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs ) const
|
||
{
|
||
return ( rhs.Equals( GetPointer() ) );
|
||
}
|
||
|
||
/// Inequality comparison operator is templated to handle ambiguity.
|
||
template
|
||
<
|
||
typename T1,
|
||
bool S1,
|
||
class OP1,
|
||
class CP1,
|
||
template < class > class KP1,
|
||
template < class > class RP1,
|
||
template < class > class DP1,
|
||
template < class > class CNP1
|
||
>
|
||
bool operator != (
|
||
const StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs ) const
|
||
{
|
||
return !( rhs.Equals( GetPointer() ) );
|
||
}
|
||
|
||
/// Less-than comparison operator is templated to handle ambiguity.
|
||
template
|
||
<
|
||
typename T1,
|
||
bool S1,
|
||
class OP1,
|
||
class CP1,
|
||
template < class > class KP1,
|
||
template < class > class RP1,
|
||
template < class > class DP1,
|
||
template < class > class CNP1
|
||
>
|
||
bool operator < (
|
||
const StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs ) const
|
||
{
|
||
return ( rhs.GreaterThan( GetPointer() ) );
|
||
}
|
||
|
||
/// Greater-than comparison operator is templated to handle ambiguity.
|
||
template
|
||
<
|
||
typename T1,
|
||
bool S1,
|
||
class OP1,
|
||
class CP1,
|
||
template < class > class KP1,
|
||
template < class > class RP1,
|
||
template < class > class DP1,
|
||
template < class > class CNP1
|
||
>
|
||
inline bool operator > (
|
||
const StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs ) const
|
||
{
|
||
return ( rhs.LessThan( GetPointer() ) );
|
||
}
|
||
|
||
/// Less-than-or-equal-to operator is templated to handle ambiguity.
|
||
template
|
||
<
|
||
typename T1,
|
||
bool S1,
|
||
class OP1,
|
||
class CP1,
|
||
template < class > class KP1,
|
||
template < class > class RP1,
|
||
template < class > class DP1,
|
||
template < class > class CNP1
|
||
>
|
||
inline bool operator <= (
|
||
const StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs ) const
|
||
{
|
||
return !( rhs.LessThan( GetPointer() ) );
|
||
}
|
||
|
||
/// Greater-than-or-equal-to operator is templated to handle ambiguity.
|
||
template
|
||
<
|
||
typename T1,
|
||
bool S1,
|
||
class OP1,
|
||
class CP1,
|
||
template < class > class KP1,
|
||
template < class > class RP1,
|
||
template < class > class DP1,
|
||
template < class > class CNP1
|
||
>
|
||
inline bool operator >= (
|
||
const StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs ) const
|
||
{
|
||
return !( rhs.GreaterThan( GetPointer() ) );
|
||
}
|
||
|
||
inline bool operator ! () const // Enables "if ( !sp ) ..."
|
||
{
|
||
return ( 0 == OP::GetPointer() );
|
||
}
|
||
|
||
protected:
|
||
|
||
inline PointerType GetPointer( void )
|
||
{
|
||
return reinterpret_cast< PointerType >( OP::GetPointer() );
|
||
}
|
||
|
||
inline ConstPointerType GetPointer( void ) const
|
||
{
|
||
return reinterpret_cast< ConstPointerType >( OP::GetPointer() );
|
||
}
|
||
|
||
private:
|
||
|
||
inline ReferenceType GetPointerRef( void )
|
||
{
|
||
return reinterpret_cast< ReferenceType >( OP::GetPointerRef() );
|
||
}
|
||
|
||
inline ConstReferenceType GetPointerRef( void ) const
|
||
{
|
||
return reinterpret_cast< ConstReferenceType >( OP::GetPointerRef() );
|
||
}
|
||
|
||
// Helper for enabling 'if (sp)'
|
||
struct Tester
|
||
{
|
||
Tester(int) {}
|
||
void dummy() {}
|
||
};
|
||
|
||
typedef void (Tester::*unspecified_boolean_type_)();
|
||
|
||
typedef typename Select< CP::allow, Tester, unspecified_boolean_type_ >::Result
|
||
unspecified_boolean_type;
|
||
|
||
public:
|
||
// enable 'if (sp)'
|
||
operator unspecified_boolean_type() const
|
||
{
|
||
return !*this ? 0 : &Tester::dummy;
|
||
}
|
||
|
||
private:
|
||
// Helper for disallowing automatic conversion
|
||
struct Insipid
|
||
{
|
||
Insipid(PointerType) {}
|
||
};
|
||
|
||
typedef typename Select< CP::allow, PointerType, Insipid >::Result
|
||
AutomaticConversionResult;
|
||
|
||
public:
|
||
operator AutomaticConversionResult() const
|
||
{
|
||
return GetPointer();
|
||
}
|
||
|
||
};
|
||
|
||
// ----------------------------------------------------------------------------
|
||
|
||
// friend functions
|
||
|
||
#ifndef LOKI_ENABLE_FRIEND_TEMPLATE_TEMPLATE_PARAMETER_WORKAROUND
|
||
|
||
template
|
||
<
|
||
typename U,
|
||
typename T,
|
||
bool S,
|
||
class OP,
|
||
class CP,
|
||
template < class > class KP,
|
||
template < class > class RP,
|
||
template < class > class DP,
|
||
template < class > class CNP
|
||
>
|
||
bool ReleaseAll( StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & sp,
|
||
typename StrongPtr< T, S, OP, CP, KP, RP, DP, CNP >::StoredType & p )
|
||
{
|
||
if ( !sp.RP<T>::OnReleaseAll( sp.IsStrong() || sp.OP::HasStrongPointer() ) )
|
||
{
|
||
return false;
|
||
}
|
||
p = sp.GetPointer();
|
||
sp.OP::SetPointer( sp.DP<T>::Default() );
|
||
return true;
|
||
}
|
||
|
||
template
|
||
<
|
||
typename U,
|
||
typename T,
|
||
bool S,
|
||
class OP,
|
||
class CP,
|
||
template < class > class KP,
|
||
template < class > class RP,
|
||
template < class > class DP,
|
||
template < class > class CNP
|
||
>
|
||
bool ResetAll( StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & sp,
|
||
typename StrongPtr< T, S, OP, CP, KP, RP, DP, CNP >::StoredType p )
|
||
{
|
||
if ( sp.OP::GetPointer() == p )
|
||
{
|
||
return true;
|
||
}
|
||
if ( !sp.RP<T>::OnResetAll( sp.IsStrong() || sp.OP::HasStrongPointer() ) )
|
||
{
|
||
return false;
|
||
}
|
||
sp.DP<T>::Delete( sp.GetPointer() );
|
||
sp.OP::SetPointer( p );
|
||
return true;
|
||
}
|
||
#endif
|
||
|
||
|
||
// free comparison operators for class template StrongPtr
|
||
|
||
/// operator== for lhs = StrongPtr, rhs = raw pointer
|
||
/// \ingroup SmartPointerGroup
|
||
template
|
||
<
|
||
typename U,
|
||
typename T,
|
||
bool S,
|
||
class OP,
|
||
class CP,
|
||
template < class > class KP,
|
||
template < class > class RP,
|
||
template < class > class DP,
|
||
template < class > class CNP
|
||
>
|
||
inline bool operator == (
|
||
const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & lhs, U * rhs )
|
||
{
|
||
return ( lhs.Equals( rhs ) );
|
||
}
|
||
|
||
/// operator== for lhs = raw pointer, rhs = StrongPtr
|
||
/// \ingroup SmartPointerGroup
|
||
template
|
||
<
|
||
typename U,
|
||
typename T,
|
||
bool S,
|
||
class OP,
|
||
class CP,
|
||
template < class > class KP,
|
||
template < class > class RP,
|
||
template < class > class DP,
|
||
template < class > class CNP
|
||
>
|
||
inline bool operator == ( U * lhs,
|
||
const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & rhs )
|
||
{
|
||
return ( rhs.Equals( lhs ) );
|
||
}
|
||
|
||
/// operator!= for lhs = StrongPtr, rhs = raw pointer
|
||
/// \ingroup SmartPointerGroup
|
||
template
|
||
<
|
||
typename U,
|
||
typename T,
|
||
bool S,
|
||
class OP,
|
||
class CP,
|
||
template < class > class KP,
|
||
template < class > class RP,
|
||
template < class > class DP,
|
||
template < class > class CNP
|
||
>
|
||
inline bool operator != (
|
||
const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & lhs, U * rhs )
|
||
{
|
||
return !( lhs.Equals( rhs ) );
|
||
}
|
||
|
||
/// operator!= for lhs = raw pointer, rhs = StrongPtr
|
||
/// \ingroup SmartPointerGroup
|
||
template
|
||
<
|
||
typename U,
|
||
typename T,
|
||
bool S,
|
||
class OP,
|
||
class CP,
|
||
template < class > class KP,
|
||
template < class > class RP,
|
||
template < class > class DP,
|
||
template < class > class CNP
|
||
>
|
||
inline bool operator != ( U * lhs,
|
||
const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & rhs )
|
||
{
|
||
return !( rhs.Equals( lhs ) );
|
||
}
|
||
|
||
/// operator< for lhs = StrongPtr, rhs = raw pointer
|
||
/// \ingroup SmartPointerGroup
|
||
template
|
||
<
|
||
typename U,
|
||
typename T,
|
||
bool S,
|
||
class OP,
|
||
class CP,
|
||
template < class > class KP,
|
||
template < class > class RP,
|
||
template < class > class DP,
|
||
template < class > class CNP
|
||
>
|
||
inline bool operator < (
|
||
const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & lhs, U * rhs )
|
||
{
|
||
return ( lhs.LessThan( rhs ) );
|
||
}
|
||
|
||
/// operator< for lhs = raw pointer, rhs = StrongPtr
|
||
/// \ingroup SmartPointerGroup
|
||
template
|
||
<
|
||
typename U,
|
||
typename T,
|
||
bool S,
|
||
class OP,
|
||
class CP,
|
||
template < class > class KP,
|
||
template < class > class RP,
|
||
template < class > class DP,
|
||
template < class > class CNP
|
||
>
|
||
inline bool operator < ( U * lhs,
|
||
const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & rhs )
|
||
{
|
||
return ( rhs.GreaterThan( lhs ) );
|
||
}
|
||
|
||
// operator> for lhs = StrongPtr, rhs = raw pointer
|
||
/// \ingroup SmartPointerGroup
|
||
template
|
||
<
|
||
typename U,
|
||
typename T,
|
||
bool S,
|
||
class OP,
|
||
class CP,
|
||
template < class > class KP,
|
||
template < class > class RP,
|
||
template < class > class DP,
|
||
template < class > class CNP
|
||
>
|
||
inline bool operator > (
|
||
const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & lhs, U * rhs )
|
||
{
|
||
return ( lhs.GreaterThan( rhs ) );
|
||
}
|
||
|
||
/// operator> for lhs = raw pointer, rhs = StrongPtr
|
||
/// \ingroup SmartPointerGroup
|
||
template
|
||
<
|
||
typename U,
|
||
typename T,
|
||
bool S,
|
||
class OP,
|
||
class CP,
|
||
template < class > class KP,
|
||
template < class > class RP,
|
||
template < class > class DP,
|
||
template < class > class CNP
|
||
>
|
||
inline bool operator > ( U * lhs,
|
||
const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & rhs )
|
||
{
|
||
return ( rhs.LessThan( lhs ) );
|
||
}
|
||
|
||
/// operator<= for lhs = StrongPtr, rhs = raw pointer
|
||
/// \ingroup SmartPointerGroup
|
||
template
|
||
<
|
||
typename U,
|
||
typename T,
|
||
bool S,
|
||
class OP,
|
||
class CP,
|
||
template < class > class KP,
|
||
template < class > class RP,
|
||
template < class > class DP,
|
||
template < class > class CNP
|
||
>
|
||
inline bool operator <= (
|
||
const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & lhs, U * rhs )
|
||
{
|
||
return !( lhs.GreaterThan( rhs ) );
|
||
}
|
||
|
||
/// operator<= for lhs = raw pointer, rhs = StrongPtr
|
||
/// \ingroup SmartPointerGroup
|
||
template
|
||
<
|
||
typename U,
|
||
typename T,
|
||
bool S,
|
||
class OP,
|
||
class CP,
|
||
template < class > class KP,
|
||
template < class > class RP,
|
||
template < class > class DP,
|
||
template < class > class CNP
|
||
>
|
||
inline bool operator <= ( U * lhs,
|
||
const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & rhs )
|
||
{
|
||
return !( rhs.LessThan( lhs ) );
|
||
}
|
||
|
||
/// operator>= for lhs = StrongPtr, rhs = raw pointer
|
||
/// \ingroup SmartPointerGroup
|
||
template
|
||
<
|
||
typename U,
|
||
typename T,
|
||
bool S,
|
||
class OP,
|
||
class CP,
|
||
template < class > class KP,
|
||
template < class > class RP,
|
||
template < class > class DP,
|
||
template < class > class CNP
|
||
>
|
||
inline bool operator >= (
|
||
const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & lhs, U * rhs )
|
||
{
|
||
return !( lhs.LessThan( rhs ) );
|
||
}
|
||
|
||
/// operator>= for lhs = raw pointer, rhs = StrongPtr
|
||
/// \ingroup SmartPointerGroup
|
||
template
|
||
<
|
||
typename U,
|
||
typename T,
|
||
bool S,
|
||
class OP,
|
||
class CP,
|
||
template < class > class KP,
|
||
template < class > class RP,
|
||
template < class > class DP,
|
||
template < class > class CNP
|
||
>
|
||
inline bool operator >= ( U * lhs,
|
||
const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & rhs )
|
||
{
|
||
return !( rhs.GreaterThan( lhs ) );
|
||
}
|
||
|
||
} // namespace Loki
|
||
|
||
namespace std
|
||
{
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
/// specialization of std::less for StroeTracker@Private@Loki@@@std@@@std@@QBEXABV123@@Z |