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