2006-01-15 22:03:10 +00:00
////////////////////////////////////////////////////////////////////////////////
// The Loki Library
// Copyright (c) 2006 Peter K<> mmel
// 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_PIMPL_H
# define LOKI_PIMPL_H
# include <loki/TypeTraits.h>
2006-01-23 17:23:46 +00:00
# include <loki/SmartPtr.h>
2006-01-17 12:03:36 +00:00
# include <exception>
2006-01-19 18:16:39 +00:00
# include <memory>
2006-01-15 22:03:10 +00:00
# ifndef LOKI_INHERITED_PIMPL_NAME
2006-01-16 13:27:49 +00:00
# define LOKI_INHERITED_PIMPL_NAME d
2006-01-15 22:03:10 +00:00
# endif
# ifndef LOKI_INHERITED_RIMPL_NAME
2006-01-16 13:27:49 +00:00
# define LOKI_INHERITED_RIMPL_NAME d
2006-01-15 22:03:10 +00:00
# endif
namespace Loki
{
2006-01-16 13:30:26 +00:00
/////////////////////
2006-01-16 13:27:49 +00:00
// template for the implementations
/////////////////////
2006-01-15 22:03:10 +00:00
template < class T >
struct Impl ;
2006-01-16 19:48:23 +00:00
2006-01-15 22:03:10 +00:00
/////////////////////
// creation policies
/////////////////////
2006-01-16 13:27:49 +00:00
// hard coded creation preferred
2006-01-15 22:03:10 +00:00
/////////////////////
// destroy policies
/////////////////////
template < class T >
struct AutoDeletePimpl
{
2006-01-16 13:27:49 +00:00
static void Destroy ( T ptr )
2006-01-16 13:30:26 +00:00
{
typedef char T_must_be_defined [
sizeof ( typename TypeTraits < T > : : PointeeType ) ? 1 : - 1 ] ;
delete ptr ;
ptr = 0 ;
}
2006-01-15 22:03:10 +00:00
} ;
template < class T >
struct DontDeletePimpl
{
static void Destroy ( T )
{ }
} ;
2006-01-16 19:48:23 +00:00
/////////////////////
// error handling
/////////////////////
template < class T >
struct ExceptionOnPimplError
{
struct Exception : public std : : exception
{
const char * what ( ) const throw ( ) { return " error in loki/Pimpl.h " ; }
} ;
static void PimplError ( )
{
throw Exception ( ) ;
}
} ;
template < class T >
struct IgnorPimplError
{
static void PimplError ( )
{ }
} ;
2006-01-15 22:03:10 +00:00
/////////////////////
2006-01-16 13:27:49 +00:00
// Helper class AutoPtrHolder to manage pimpl lifetime
2006-01-15 22:03:10 +00:00
/////////////////////
2006-01-16 13:30:26 +00:00
namespace Private
{
2006-01-17 12:03:36 +00:00
// does not work with std::auto_ptr
2006-01-16 13:30:26 +00:00
template
<
class Impl ,
class Ptr ,
template < class > class Del
>
struct AutoPtrHolder
{
2006-01-16 18:21:01 +00:00
AutoPtrHolder ( ) : ptr ( Ptr ( ) )
{ }
2006-01-16 13:30:26 +00:00
2006-01-18 16:49:32 +00:00
// defined in #include<loki/PimplDef.h>
~ AutoPtrHolder ( ) ;
2006-01-16 18:21:01 +00:00
Ptr Create ( )
{
ptr = Ptr ( new Impl ) ;
return ptr ;
}
Ptr ptr ;
} ;
2006-01-19 18:16:39 +00:00
// don't compile with std::auto_ptr
template < class Impl , template < class > class Del >
struct AutoPtrHolder < Impl , std : : auto_ptr < Impl > , Del > { } ;
2006-01-17 12:03:36 +00:00
2006-01-16 18:21:01 +00:00
template
<
class Impl ,
class Ptr ,
2006-01-16 19:48:23 +00:00
template < class > class Del ,
template < class > class ErrorPolicy = ExceptionOnPimplError
2006-01-16 18:21:01 +00:00
>
2006-01-17 11:07:34 +00:00
struct AutoPtrHolderChecked : AutoPtrHolder < Impl , Ptr , Del >
2006-01-16 18:21:01 +00:00
{
static bool init_ ;
2006-01-17 11:07:34 +00:00
AutoPtrHolderChecked ( )
2006-01-16 18:21:01 +00:00
{
init_ = true ;
}
2006-01-16 13:30:26 +00:00
template < class T >
operator T & ( )
{
2006-01-16 19:48:23 +00:00
// if this throws change the declaration order
// of the DeclaredRimpl construct
2006-01-16 18:21:01 +00:00
if ( ! init_ )
2006-01-16 19:48:23 +00:00
ErrorPolicy < T > : : PimplError ( ) ;
2006-01-17 12:03:36 +00:00
AutoPtrHolder < Impl , Ptr , Del > : : Create ( ) ;
return * AutoPtrHolder < Impl , Ptr , Del > : : ptr ;
2006-01-16 13:30:26 +00:00
}
} ;
2006-01-15 22:03:10 +00:00
2006-01-16 18:21:01 +00:00
template
<
class Impl ,
class Ptr ,
2006-01-16 19:48:23 +00:00
template < class > class Del ,
template < class > class Err
2006-01-16 18:21:01 +00:00
>
2006-01-16 19:48:23 +00:00
bool AutoPtrHolderChecked < Impl , Ptr , Del , Err > : : init_ = false ;
2006-01-16 18:21:01 +00:00
2006-01-15 22:03:10 +00:00
template < class T >
2006-01-16 13:27:49 +00:00
struct HavePtrHolder
2006-01-15 22:03:10 +00:00
{
2006-01-16 13:27:49 +00:00
T ptr ;
2006-01-15 22:03:10 +00:00
} ;
}
/////////////////////
// Pimpl usage policies
/////////////////////
template < class Impl , typename Ptr , template < class > class Del >
2006-01-16 13:27:49 +00:00
class InheritedPimpl : private
2006-01-16 13:30:26 +00:00
Private : : HavePtrHolder < Private : : AutoPtrHolder < Impl , Ptr , Del > >
2006-01-16 13:27:49 +00:00
{
typedef Private : : HavePtrHolder < Private : : AutoPtrHolder < Impl , Ptr , Del > > PtrHolder ;
public :
2006-01-23 17:23:46 +00:00
Ptr LOKI_INHERITED_PIMPL_NAME ;
2006-01-16 13:27:49 +00:00
protected :
InheritedPimpl ( ) : LOKI_INHERITED_PIMPL_NAME ( PtrHolder : : ptr . Create ( ) )
{ }
2006-01-16 13:30:26 +00:00
private :
InheritedPimpl & operator = ( const InheritedPimpl & ) ;
2006-01-16 13:27:49 +00:00
} ;
template < class Impl , typename Ptr , template < class > class Del >
2006-01-16 13:30:26 +00:00
class DeclaredPimpl : private
Private : : HavePtrHolder < Private : : AutoPtrHolder < Impl , Ptr , Del > >
2006-01-15 22:03:10 +00:00
{
2006-01-16 13:27:49 +00:00
typedef Private : : HavePtrHolder < Private : : AutoPtrHolder < Impl , Ptr , Del > > PtrHolder ;
2006-01-15 22:03:10 +00:00
2006-01-23 17:23:46 +00:00
# if defined(LOKI_DEFAULT_CONSTNESS)
typedef typename LOKI_DEFAULT_CONSTNESS < Ptr > : : Type ConstPtr ;
typedef typename LOKI_DEFAULT_CONSTNESS < Impl > : : Type ConstImpl ;
# else // default: enable
2006-01-26 14:28:59 +00:00
typedef const Ptr ConstPtr ;
typedef const Impl ConstImpl ;
2006-01-23 17:23:46 +00:00
# endif
2006-01-15 22:03:10 +00:00
public :
2006-01-23 17:23:46 +00:00
Ptr operator - > ( )
{
return ptr ;
}
Impl & operator * ( )
{
return * ptr ;
}
ConstPtr operator - > ( ) const
2006-01-15 22:03:10 +00:00
{
return ptr ;
}
2006-01-23 17:23:46 +00:00
ConstImpl & operator * ( ) const
2006-01-15 22:03:10 +00:00
{
return * ptr ;
}
protected :
2006-01-16 13:30:26 +00:00
DeclaredPimpl ( ) : ptr ( PtrHolder : : ptr . Create ( ) )
2006-01-15 22:03:10 +00:00
{ }
private :
2006-01-16 13:30:26 +00:00
DeclaredPimpl & operator = ( const DeclaredPimpl & ) ;
2006-01-15 22:03:10 +00:00
const Ptr ptr ;
} ;
/////////////////////
// Rimpl usage policies
/////////////////////
template < class Impl , typename Ptr , template < class > class Del >
2006-01-16 13:27:49 +00:00
class InheritedRimpl : private
2006-01-16 13:30:26 +00:00
Private : : HavePtrHolder < Private : : AutoPtrHolder < Impl , Ptr , Del > >
2006-01-15 22:03:10 +00:00
{
2006-01-16 13:27:49 +00:00
typedef Private : : HavePtrHolder < Private : : AutoPtrHolder < Impl , Ptr , Del > > PtrHolder ;
2006-01-15 22:03:10 +00:00
public :
Impl & LOKI_INHERITED_RIMPL_NAME ;
protected :
InheritedRimpl ( ) :
2006-01-16 13:27:49 +00:00
LOKI_INHERITED_RIMPL_NAME ( * PtrHolder : : ptr . Create ( ) )
2006-01-15 22:03:10 +00:00
{ }
private :
InheritedRimpl & operator = ( const InheritedRimpl & ) ;
} ;
2006-01-16 13:27:49 +00:00
template < class Impl , typename PointerPolicy , template < class > class DeletePolicy >
class DeclaredRimpl : public Impl
{
protected :
DeclaredRimpl ( )
{ }
} ;
2006-01-15 22:03:10 +00:00
/////////////////////
// Wrapper for "pointer to implementation" alias pimpl.
// Impl: implementation class
// PointerTypePolicy: arbitrary pointer implementation
// DeletePolicy: delete implementation object on destruction of PtrImpl
// UsagePolicy: how to access the stored pointer, as pointer, checked, unchecked
/////////////////////
template
<
class Impl ,
class PointerPolicy = Impl * ,
template < class > class DeletePolicy = AutoDeletePimpl ,
template < class , class , template < class > class > class UsagePolicy = InheritedPimpl
>
class PtrImpl : public UsagePolicy < Impl , PointerPolicy , DeletePolicy >
{
public :
typedef Impl ImplType ;
typedef PointerPolicy PointerType ;
2006-01-16 13:27:49 +00:00
PtrImpl ( ) : UsagePolicy < Impl , PointerPolicy , DeletePolicy > ( )
2006-01-15 22:03:10 +00:00
{ }
2006-01-16 13:30:26 +00:00
private :
PtrImpl & operator = ( const PtrImpl & ) ;
2006-01-15 22:03:10 +00:00
} ;
/////////////////////
// Predefined convenience "templated typedef"
/////////////////////
template < class T >
struct Pimpl
{
2006-01-16 13:30:26 +00:00
// declare pimpl
2006-01-15 22:03:10 +00:00
typedef PtrImpl
<
Impl < T > ,
Impl < T > * ,
AutoDeletePimpl ,
DeclaredPimpl
>
Type ;
2006-01-16 13:30:26 +00:00
// inherit pimpl
2006-01-15 22:03:10 +00:00
typedef PtrImpl
<
Impl < T > ,
Impl < T > * ,
AutoDeletePimpl ,
InheritedPimpl
>
Owner ;
} ;
template < class T >
struct Rimpl
{
2006-01-16 13:30:26 +00:00
// declare rimpl
2006-01-15 22:03:10 +00:00
typedef PtrImpl
<
Impl < T > ,
Impl < T > * ,
DontDeletePimpl ,
DeclaredRimpl
>
2006-01-18 19:03:25 +00:00
Ptr ;
2006-01-15 22:03:10 +00:00
2006-01-16 13:30:26 +00:00
// init declared rimpl
2006-01-16 18:21:01 +00:00
typedef Private : : AutoPtrHolderChecked
2006-01-15 22:03:10 +00:00
<
2006-01-18 19:03:25 +00:00
Ptr ,
Ptr * ,
2006-01-15 22:03:10 +00:00
AutoDeletePimpl
>
2006-01-16 13:27:49 +00:00
Init ;
2006-01-15 22:03:10 +00:00
2006-01-18 19:03:25 +00:00
typedef Ptr & Type ;
2006-01-15 22:03:10 +00:00
2006-01-18 16:49:32 +00:00
// inherit rimpl
2006-01-15 22:03:10 +00:00
typedef PtrImpl
<
Impl < T > ,
Impl < T > * ,
AutoDeletePimpl ,
InheritedRimpl
>
Owner ;
} ;
}
# endif
2006-01-16 19:05:09 +00:00
// $Log$
2006-01-26 14:28:59 +00:00
// Revision 1.14 2006/01/26 14:28:59 syntheticpp
// remove wrong 'typename'
//
2006-01-23 17:23:46 +00:00
// Revision 1.13 2006/01/23 17:22:49 syntheticpp
// add support of deep constness, only supported by (future) Loki::SmartPtr, not supported by boost::shared_ptr and plain pointer. Maybe deep constness forces a redesign of Pimpl. Is there a way to support deep constness by a rimpl?
//
2006-01-19 18:16:39 +00:00
// Revision 1.12 2006/01/19 18:16:39 syntheticpp
// disable usage with auto_ptr: don't compile with std::auto_ptr
//
2006-01-18 19:03:25 +00:00
// Revision 1.11 2006/01/18 19:03:06 syntheticpp
// make rimpl type really a reference
//
2006-01-18 16:49:32 +00:00
// Revision 1.10 2006/01/18 16:49:06 syntheticpp
// move definition of the destructor to extra file, because msvc tries to use the incomplete type; not inlining does not help; maybe this is a compiler bug.
//
2006-01-17 12:03:36 +00:00
// Revision 1.9 2006/01/17 12:03:36 syntheticpp
// add comment about auto_ptr
//
2006-01-17 11:07:34 +00:00
// Revision 1.8 2006/01/17 11:07:34 syntheticpp
// AutoPtrHolderChecked inherits from AutoPtrHolder
//
2006-01-16 19:48:23 +00:00
// Revision 1.7 2006/01/16 19:48:23 syntheticpp
// add error policy
//
2006-01-16 19:05:09 +00:00
// Revision 1.6 2006/01/16 19:05:09 rich_sposato
// Added cvs keywords.
//