FastJet 3.0beta1
SharedPtr.hh
00001 #ifndef __FASTJET_SHARED_PTR_HH__
00002 #define __FASTJET_SHARED_PTR_HH__
00003 
00004 //STARTHEADER
00005 // $Id: SharedPtr.hh 2257 2011-06-15 09:54:15Z salam $
00006 //
00007 // Copyright (c) 2005-2010, Matteo Cacciari, Gavin Salam and Gregory Soyez
00008 //
00009 //----------------------------------------------------------------------
00010 // This file is part of FastJet.
00011 //
00012 //  FastJet is free software; you can redistribute it and/or modify
00013 //  it under the terms of the GNU General Public License as published by
00014 //  the Free Software Foundation; either version 2 of the License, or
00015 //  (at your option) any later version.
00016 //
00017 //  The algorithms that underlie FastJet have required considerable
00018 //  development and are described in hep-ph/0512210. If you use
00019 //  FastJet as part of work towards a scientific publication, please
00020 //  include a citation to the FastJet paper.
00021 //
00022 //  FastJet is distributed in the hope that it will be useful,
00023 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00024 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00025 //  GNU General Public License for more details.
00026 //
00027 //  You should have received a copy of the GNU General Public License
00028 //  along with FastJet; if not, write to the Free Software
00029 //  Foundation, Inc.:
00030 //      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00031 //----------------------------------------------------------------------
00032 //ENDHEADER
00033 
00034 #include "fastjet/internal/base.hh"
00035 #include <cstdlib>  // for NULL!!!
00036 
00037 // for testing purposes, the following define makes it possible
00038 // for our SharedPtr simply to be derived from the STL TR1 one.
00039 // #define USETR1SHAREDPTR
00040 
00041 #ifdef USETR1SHAREDPTR
00042 #include <tr1/memory>
00043 #endif // USETR1SHAREDPTR
00044 
00045 FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
00046 
00047 #ifdef USETR1SHAREDPTR
00048 
00049 /// @ingroup advanced_usage
00050 /// \class SharedPtr
00051 /// replaces our shared pointer with the TR1 one (for testing purpose)
00052 ///
00053 /// for testing purposes, it can be useful to replace our home-made
00054 /// SharedPtr with the standard library one. Having a class derived
00055 /// from the standard one is way of arranging for this to happen.
00056 /// 
00057 /// The other way of working this is a template class with an 
00058 /// internal typedef (http://bytes.com/topic/c/answers/60312-typedef-template)
00059 /// since templated typedefs don't work in standard C++
00060 ///
00061 /// Note that some facilities that are present in the FastJet shared
00062 /// pointer (resetting use-count) are not handled by the TR1 shared
00063 /// pointer; and the FastJet SharedPtr has a different underlying data
00064 /// structure from the TR1 shared pointer, which prevents us from
00065 /// implementing some of TR1 features (notably assignment from shared
00066 /// pointers to a derived class).
00067 template<class T>
00068 class SharedPtr : public std::tr1::shared_ptr<T> {
00069 public:
00070   SharedPtr() : std::tr1::shared_ptr<T>() {}
00071   SharedPtr(T * t) : std::tr1::shared_ptr<T>(t) {}
00072   SharedPtr(const SharedPtr<T> & t) : std::tr1::shared_ptr<T>(t) {}
00073   // for some reason operator() doesn't get inherited
00074   inline operator bool() const {return (this->get()!=NULL);}
00075   /// return the pointer we're pointing to  
00076   T* operator ()() const{
00077     return this->get(); // automatically returns NULL when out-of-scope
00078   }
00079 };
00080 
00081 
00082 #else // USETR1SHAREDPTR
00083 
00084 /**
00085  * @ingroup advanced_usage
00086  * \class SharedPtr
00087  * an implementation of C++0x shared pointers (or boost's)
00088  *
00089  * this class implements a smart pointer, based on the shared+ptr
00090  * proposal. A description of shared_ptr can be found in Section 2.2.3
00091  * of the first C++ Technical Report (TR1)
00092  *   http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1745.pdf
00093  * or, alternatively, on the Boost C++ library website at
00094  *   http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/shared_ptr.htm
00095  *
00096  * Our implementation is compatible with both of these apart from a
00097  * series of members and functions that have not been implemented:
00098  *  - conversion from weak and auto pointers
00099  *  - support for deleters and allocators
00100  *  - static, constant and dynamic casts
00101  *  - constructor and assignment sharing ownership with a shared
00102  *    pointer r but storing a different pointer than r (needed for the
00103  *    previous item)
00104  * In the last 2 cases, their implementation would require storing two
00105  * pointers for every copies of the shared pointer, while our
00106  * implementation only needs one. We did not implement then since we
00107  * want to limit as much as possible memory and time consumption, and
00108  * can easily avoid (at least for our needs so far) the casts.
00109  *
00110  * We also add the possibility to force an update of the count.
00111  * 
00112  * The class has been tested against the existing boost (v1.42)
00113  * implementation (for the parts that we have implemented).
00114  */
00115 template<class T>
00116 class SharedPtr{
00117 public:
00118   /// forward declaration of the counting container
00119   class __SharedCountingPtr;
00120 
00121   /// default ctor
00122   SharedPtr() : _ptr(NULL){}
00123   
00124   /// initialise with the main data
00125   /// \param  t  : the object we want a smart pointer to
00126   template<class Y> explicit SharedPtr(Y* ptr){
00127     _ptr = new __SharedCountingPtr(ptr);
00128   }
00129   
00130   /// overload the copy ctor so that it updates count
00131   /// \param  share : the object we want to copy
00132   SharedPtr(SharedPtr const & share) : _ptr(share._get_container()){
00133     if (_ptr!=NULL) (*_ptr)++;
00134   }
00135   // old version
00136   //  SharedPtr(SharedPtr const & share) : _ptr(NULL){
00137   //    reset(share);
00138   //  }
00139     
00140   // will not work with the current structure
00141   // /// overload the copy ctor so that it updates count
00142   // /// \param  share : the object we want to copy
00143   // template<class Y> SharedPtr(SharedPtr<Y> const & share) : _ptr(NULL){
00144   //   reset(share);
00145   // }
00146 
00147   /// default dtor
00148   ~SharedPtr(){
00149     // make sure the object has been allocated
00150     if (_ptr==NULL) return;
00151 
00152     _decrease_count();
00153   }
00154 
00155   /// reset the pointer to default value (NULL)
00156   void reset(){
00157     // // if we already are pointing to sth, be sure to decrease its count
00158     // if (_ptr!=NULL) _decrease_count();
00159     // _ptr = NULL;
00160     SharedPtr().swap(*this);
00161   }
00162   
00163   // will not work with the current structure
00164   /// reset from a pointer
00165   template<class Y> void reset(Y * ptr){
00166     // // if we already are pointing to sth, be sure to decrease its count
00167     // if (_ptr!=NULL) _decrease_count();
00168     // 
00169     // _ptr = new __SharedCountingPtr(ptr);
00170     SharedPtr(ptr).swap(*this);
00171   }
00172 
00173   // not part of the standard
00174   /// do a smart copy
00175   /// \param  share : the object we want to copy
00176   /// Q? Do we need a non-template<Y> version as for the ctor and the assignment?
00177   template<class Y> void reset(SharedPtr<Y> const & share){
00178   //void reset(SharedPtr const & share){
00179     // if we already are pointing to sth, be sure to decrease its count
00180     if (_ptr!=NULL){
00181       // in the specific case where we're having the same
00182       // share,reset() has actually no effect. However if *this is the
00183       // only instance still alive (implying share==*this) bringing
00184       // the count down to 0 and deleting the object will not have the
00185       // expected effect. So we just avoid that situation explicitly
00186       if (_ptr == share._get_container()) return;
00187     
00188       _decrease_count();
00189     }
00190     
00191     // Watch out: if share is empty, construct an empty shared_ptr
00192     
00193     // copy the container
00194     _ptr = share._get_container();  // Note: automatically set it to NULL if share is empty
00195     
00196     if (_ptr!=NULL)
00197       (*_ptr)++;
00198   }
00199   
00200   /// overload the = operator so that it updates count
00201   /// \param  share : the object we want to copy
00202   SharedPtr& operator=(SharedPtr const & share){
00203     reset(share);
00204     return *this;
00205   }
00206   
00207   /// overload the = operator so that it updates count
00208   /// \param  share : the object we want to copy
00209   template<class Y> SharedPtr& operator=(SharedPtr<Y> const & share){
00210     reset(share);
00211     return *this;
00212   }
00213   
00214   /// return the pointer we're pointing to  
00215   T* operator ()() const{
00216     if (_ptr==NULL) return NULL;
00217     return _ptr->get(); // automatically returns NULL when out-of-scope
00218   }
00219   
00220   /// indirection, get a reference to the stored pointer
00221   ///
00222   /// !!! WATCH OUT
00223   /// It fails to check the requirement that the stored pointer must
00224   /// not be NULL!!  So you need explicitly to check the validity in
00225   /// your code
00226   inline T& operator*() const{
00227     return *(_ptr->get());
00228   }
00229 
00230   /// indirection, get the stored pointer
00231   ///
00232   /// !!! WATCH OUT
00233   /// It fails to check the requirement that the stored pointer must
00234   /// not be NULL!!  So you need explicitly to check the validity in
00235   /// your code
00236   inline T* operator->() const{
00237     if (_ptr==NULL) return NULL;
00238     return _ptr->get();
00239   }  
00240 
00241   /// get the stored pointer
00242   inline T* get() const{
00243     if (_ptr==NULL) return NULL;
00244     return _ptr->get();
00245   }
00246 
00247   /// check if the instance is unique
00248   inline bool unique() const{
00249     return (use_count()==1);
00250   }
00251 
00252   /// return the number of counts
00253   inline long use_count() const{
00254     if (_ptr==NULL) return 0;
00255     return _ptr->use_count(); // automatically returns NULL when out-of-scope
00256   }
00257 
00258   /// conversion to bool
00259   /// This will allow you to use the indirection nicely
00260   inline operator bool() const{
00261     return (get()!=NULL);
00262   }
00263 
00264   /// exchange the content of the two pointers
00265   inline void swap(SharedPtr & share){
00266     __SharedCountingPtr* share_container = share._ptr;
00267     share._ptr = _ptr;
00268     _ptr = share_container;
00269   }
00270 
00271   /// force the count to be set to a specified value
00272   ///   \param count   the value that we ned to reset to
00273   void set_count(const long & count){
00274     if (_ptr==NULL) return;
00275     _ptr->set_count(count);
00276   }
00277 
00278   /**
00279    * \if internal_doc
00280    * \class __SharedCountingPtr
00281    * A reference-counting pointer
00282    *
00283    * This is implemented as a container for that pointer together with
00284    * reference counting.
00285    * The pointer is deleted when the number of counts goes to 0;
00286    * \endif
00287    */
00288   class __SharedCountingPtr{
00289   public:
00290     /// default ctor
00291     __SharedCountingPtr() : _ptr(NULL), _count(0){}
00292     
00293     /// ctor with initialisation
00294     template<class Y> explicit __SharedCountingPtr(Y* ptr) : _ptr(ptr), _count(1){}
00295     
00296     /// default dtor
00297     ~__SharedCountingPtr(){ 
00298       // force the deletion of the object we keep track of
00299       if (_ptr!=NULL){ delete _ptr;}
00300     }
00301 
00302     /// return a pointer to the object
00303     inline T* get() const {return _ptr;}
00304 
00305     /// return the count
00306     inline long use_count() const {return _count;}
00307 
00308     /// postfix incrementation
00309     inline long operator++(int unused){return _count++;}
00310 
00311     /// postfix decrementation
00312     inline long operator--(int unused){return _count--;}
00313 
00314     /// prefix incrementation
00315     inline long operator++(){return ++_count;}
00316 
00317     /// prefix decrementation
00318     inline long operator--(){return --_count;}
00319 
00320     /// force the count to be set to a specified value
00321     ///   \param count   the value that we ned to reset to
00322     void set_count(const long & count){
00323       _count = count;
00324     }
00325 
00326   private:
00327     T *_ptr;              ///< the pointer we're counting the references to
00328     long _count;  ///< the number of references
00329   };
00330 
00331 private:
00332   /// return the common container
00333   inline __SharedCountingPtr* _get_container() const{
00334     return _ptr;
00335   }
00336 
00337   /// decrease the pointer count and support deletion
00338   /// Warning: we don't test that the pointer is allocated
00339   ///          This can be dangerous if we have explicitly reset the
00340   ///          count.  Generally speaking, if the count goes negative
00341   ///          after _ptr has been effectively deleted, this is going
00342   ///          to lead to a segmentation fault. But, if in the course
00343   ///          of the deletion of _ptr, the deletion of its pointer
00344   ///          (_ptr::_ptr, i.e. the real data we're storing) makes
00345   ///          the counts to become negative, this is going to pass
00346   ///          smoothly.
00347   void _decrease_count(){
00348     // decrease the count
00349     (*_ptr)--;
00350     
00351     // if no one else is using it, free the allocated memory
00352     if (_ptr->use_count()==0)
00353       delete _ptr; // that automatically deletes the object itself
00354   }
00355 
00356   // the real info
00357   __SharedCountingPtr *_ptr;
00358 };
00359 
00360 
00361 /// comparison: equality
00362 template<class T,class U>
00363 inline bool operator==(SharedPtr<T> const & t, SharedPtr<U> const & u){
00364   return t.get() == u.get();
00365 }
00366 
00367 /// comparison: difference
00368 template<class T,class U>
00369 inline bool operator!=(SharedPtr<T> const & t, SharedPtr<U> const & u){
00370   return t.get() != u.get();
00371 }
00372 
00373 /// comparison: orgering
00374 template<class T,class U>
00375 inline bool operator<(SharedPtr<T> const & t, SharedPtr<U> const & u){
00376   return t.get() < u.get();
00377 }
00378 
00379 /// swapping
00380 template<class T>
00381 inline void swap(SharedPtr<T> & a, SharedPtr<T> & b){
00382   return a.swap(b);
00383 }
00384 
00385 /// getting the pointer
00386 template<class T>
00387 inline T* get_pointer(SharedPtr<T> const & t){
00388   return t.get();
00389 }
00390 
00391 #endif // USETR1SHAREDPTR
00392 
00393 FASTJET_END_NAMESPACE      // defined in fastjet/internal/base.hh
00394 
00395 #endif   // __FASTJET_SHARED_PTR_HH__
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends