Inferno  0.2
shared_ptr.hpp
Go to the documentation of this file.
00001 /*
00002  * shared_ptr.hpp
00003  *
00004  *  Created on: 9 Jun 2010
00005  *      Author: jgraley
00006  */
00007 
00008 #ifndef SHARED_PTR_HPP
00009 #define SHARED_PTR_HPP
00010 
00011 #include "common/common.hpp"
00012 #include "common/magic.hpp"
00013 
00014 // Covariant NULL pointer bug
00015 //
00016 // JSG: There's an unfortunate bug in GCC 3.4.4 on cygwin whereby a covariant return thunk
00017 // for a pointer goes wrong when the pointer is NULL. We can end up dereferencing a NULL (or offset-from-NULL)
00018 // pointer inside the thunk itself which is opaque code, not a lot of fun overall.
00019 //
00020 // It seems to be OK on GCC4 on Linux, and c++/20746 (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=20746) seems to have a fix,
00021 // but I think it only applies to GCC4 (4.0.2 and 4.1).
00022 //
00023 // So I've just hacked covariant returns to not be covariant whenever I get a problem (just returns same as
00024 // base class, is this "isovariant"?)
00025 //
00026 
00027 // Shared pointer wrapper with OO support
00028 
00029 namespace OOStd {
00030 
00031 template<typename SUB_BASE, typename VALUE_INTERFACE, typename VALUE_TYPE>
00032 struct SharedPtr;
00033 
00034 // An interface for our SharedPtr object. This interface works regardless of pointed-to
00035 // type; it also masquerades as a SharedPtr to the VALUE_INTERFACE type, which should be the
00036 // base class of the pointed-to things.
00037 template<typename SUB_BASE, typename VALUE_INTERFACE>
00038 struct SharedPtrInterface : virtual SUB_BASE, public Traceable
00039 {
00040     // Convert to and from shared_ptr<VALUE_INTERFACE> and SharedPtr<VALUE_INTERFACE>
00041   virtual operator shared_ptr<VALUE_INTERFACE>() const = 0;
00042   virtual operator SharedPtr<SUB_BASE, VALUE_INTERFACE, VALUE_INTERFACE>() const = 0;
00043 
00044     virtual operator bool() const = 0; // for testing against NULL
00045     virtual VALUE_INTERFACE *get() const = 0; // As per shared_ptr<>, ie gets the actual C pointer
00046     virtual VALUE_INTERFACE &operator *() const = 0; 
00047     virtual SharedPtrInterface &operator=( const SharedPtrInterface &o )
00048     {
00049       (void)SUB_BASE::operator=( o ); // vital for itemiser!
00050       (void)Traceable::operator=( o );
00051       return *this;
00052     }
00053     virtual SharedPtr<SUB_BASE, VALUE_INTERFACE, VALUE_INTERFACE> MakeValueArchitype() const = 0; // construct an object of the VALUE_TYPE type (NOT a clone 
00054                                                                                         // of the object we're pointing to) 
00055 };
00056 
00057 template<typename SUB_BASE, typename VALUE_INTERFACE, typename VALUE_TYPE>
00058 struct SharedPtr : virtual SharedPtrInterface<SUB_BASE, VALUE_INTERFACE>, shared_ptr<VALUE_TYPE>
00059 {
00060     inline SharedPtr() {}
00061 
00062     inline SharedPtr( VALUE_TYPE *o ) :
00063         shared_ptr<VALUE_TYPE>( o )
00064     {
00065     }
00066 
00067     template< typename OTHER >
00068     inline SharedPtr( const shared_ptr<OTHER> &o ) :
00069         shared_ptr<VALUE_TYPE>( o )
00070     {
00071     }
00072 
00073     template< typename OTHER >
00074     inline SharedPtr( const SharedPtr<SUB_BASE, VALUE_INTERFACE, OTHER> &o ) :
00075         shared_ptr<VALUE_TYPE>( (shared_ptr<OTHER>)(o) )
00076     {
00077     }
00078 
00079     virtual operator shared_ptr<VALUE_INTERFACE>() const
00080     {
00081         const shared_ptr<VALUE_TYPE> p = (const shared_ptr<VALUE_TYPE>)*this;
00082         return p;
00083     }
00084 
00085   virtual operator SharedPtr<SUB_BASE, VALUE_INTERFACE, VALUE_INTERFACE>() const
00086   {
00087         const shared_ptr<VALUE_TYPE> p1 = *(const shared_ptr<VALUE_TYPE> *)this;
00088         return SharedPtr<SUB_BASE, VALUE_INTERFACE, VALUE_INTERFACE>( p1 );
00089   }
00090 
00091 
00092     virtual VALUE_TYPE *get() const 
00093     {
00094       VALUE_TYPE *e = shared_ptr<VALUE_TYPE>::get();
00095       //TRACE("sp::get() returns %p\n", e );
00096       return e;
00097     }
00098 
00099     virtual VALUE_TYPE &operator *() const 
00100     {
00101       return shared_ptr<VALUE_TYPE>::operator *();
00102     }
00103 
00104     virtual SharedPtr &operator=( shared_ptr<VALUE_INTERFACE> n )
00105     {   
00106         if( n )
00107         {
00108             shared_ptr<VALUE_TYPE> p = dynamic_pointer_cast<VALUE_TYPE>(shared_ptr<VALUE_INTERFACE>(n));
00109             ASSERT( p )("OOStd inferred dynamic cast has failed: from ")(*n)
00110                  (" to type ")(Traceable::CPPFilt( typeid( VALUE_TYPE ).name() ))("\n");
00111           (void)shared_ptr<VALUE_TYPE>::operator=( p );
00112         }
00113         else
00114         {
00115             (void)shared_ptr<VALUE_TYPE>::operator=( shared_ptr<VALUE_TYPE>() );
00116         }
00117       return *this;
00118     }
00119 
00120     template< typename OTHER >
00121     inline SharedPtr &operator=( SharedPtr<SUB_BASE, VALUE_INTERFACE, OTHER> n )
00122     {
00123       (void)operator=( shared_ptr<OTHER>(n) );
00124       return *this;
00125     }
00126 
00127     virtual SharedPtr &operator=( const SharedPtrInterface<SUB_BASE, VALUE_INTERFACE> &n )
00128     {
00129       (void)operator=( shared_ptr<VALUE_INTERFACE>(n) );
00130       return *this;
00131     }
00132 
00133     virtual operator bool() const
00134     {
00135       return !!*(const shared_ptr<VALUE_TYPE> *)this;
00136     }
00137 
00138   static inline SharedPtr<SUB_BASE, VALUE_INTERFACE, VALUE_TYPE>
00139       DynamicCast( const SharedPtrInterface<SUB_BASE, VALUE_INTERFACE> &g )
00140   {
00141     if( g )
00142     {
00143       shared_ptr<VALUE_TYPE> v = dynamic_pointer_cast<VALUE_TYPE>(shared_ptr<VALUE_INTERFACE>(g));
00144       return SharedPtr<SUB_BASE, VALUE_INTERFACE, VALUE_TYPE>(v);
00145     }
00146     else
00147     {
00148       return SharedPtr<SUB_BASE, VALUE_INTERFACE, VALUE_TYPE>();
00149     }
00150   }
00151   // For when OOStd itself needs to dyncast, as opposed to the user asking for it.
00152   static inline SharedPtr<SUB_BASE, VALUE_INTERFACE, VALUE_TYPE>
00153       InferredDynamicCast( const SharedPtrInterface<SUB_BASE, VALUE_INTERFACE> &g )
00154   {
00155     if( g )
00156     {
00157       shared_ptr<VALUE_TYPE> v = dynamic_pointer_cast<VALUE_TYPE>(shared_ptr<VALUE_INTERFACE>(g));
00158       ASSERT( v )("OOStd inferred dynamic cast has failed: from ")(*g)
00159                  (" to type ")(Traceable::CPPFilt( typeid( VALUE_TYPE ).name() ))("\n");
00160       return SharedPtr<SUB_BASE, VALUE_INTERFACE, VALUE_TYPE>(v);
00161     }
00162     else
00163     {
00164         // Null came in, null goes out.
00165       return SharedPtr<SUB_BASE, VALUE_INTERFACE, VALUE_TYPE>();
00166     }
00167   }
00168   virtual SharedPtr<SUB_BASE, VALUE_INTERFACE, VALUE_INTERFACE> MakeValueArchitype() const
00169   {
00170         ASSERTFAIL("MakeValueArchitype() not implemented for this SharedPtr\n");
00171     }
00172 };
00173 
00174 // Similar signature to boost shared_ptr operator==, and we restrict the pointers
00175 // to having the same subbase and base target
00176 template< typename SUB_BASE, typename VALUE_INTERFACE, typename X, typename Y >
00177 inline bool operator==( const SharedPtr<SUB_BASE, VALUE_INTERFACE, X> &x,
00178                     const SharedPtr<SUB_BASE, VALUE_INTERFACE, Y> &y)
00179 {
00180   return operator==( (const shared_ptr<X> &)x, (const shared_ptr<Y> &)y );
00181 }
00182 
00183 // Similar signature to boost shared_ptr operator==, and we restrict the pointers
00184 // to having the same subbase and base target
00185 template< typename SUB_BASE, typename VALUE_INTERFACE >
00186 inline bool operator==( const SharedPtrInterface<SUB_BASE, VALUE_INTERFACE> &x,
00187                     const SharedPtrInterface<SUB_BASE, VALUE_INTERFACE> &y)
00188 {
00189   return x.get() == y.get();
00190 }
00191 
00192 template< typename SUB_BASE, typename VALUE_INTERFACE, typename X, typename Y >
00193 inline bool operator!=( const SharedPtr<SUB_BASE, VALUE_INTERFACE, X> &x,
00194                     const SharedPtr<SUB_BASE, VALUE_INTERFACE, Y> &y)
00195 {
00196   return operator!=( (const shared_ptr<X> &)x, (const shared_ptr<Y> &)y );
00197 }
00198 
00199 }; // namespace
00200 
00201 #endif /* SHARED_PTR_HPP */