Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:57:19

0001  #ifndef __FASTJET_SHARED_PTR_HH__
0002 #define __FASTJET_SHARED_PTR_HH__
0003 
0004 //FJSTARTHEADER
0005 // $Id$
0006 //
0007 // Copyright (c) 2005-2021, Matteo Cacciari, Gavin P. Salam and Gregory Soyez
0008 //
0009 //----------------------------------------------------------------------
0010 // This file is part of FastJet.
0011 //
0012 //  FastJet is free software; you can redistribute it and/or modify
0013 //  it under the terms of the GNU General Public License as published by
0014 //  the Free Software Foundation; either version 2 of the License, or
0015 //  (at your option) any later version.
0016 //
0017 //  The algorithms that underlie FastJet have required considerable
0018 //  development. They are described in the original FastJet paper,
0019 //  hep-ph/0512210 and in the manual, arXiv:1111.6097. If you use
0020 //  FastJet as part of work towards a scientific publication, please
0021 //  quote the version you use and include a citation to the manual and
0022 //  optionally also to hep-ph/0512210.
0023 //
0024 //  FastJet is distributed in the hope that it will be useful,
0025 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
0026 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0027 //  GNU General Public License for more details.
0028 //
0029 //  You should have received a copy of the GNU General Public License
0030 //  along with FastJet. If not, see <http://www.gnu.org/licenses/>.
0031 //----------------------------------------------------------------------
0032 //FJENDHEADER
0033 
0034 #include "fastjet/internal/base.hh"
0035 #include "fastjet/config.h"
0036 #include <cstdlib>  // for NULL!!!
0037 #include "fastjet/internal/deprecated.hh"
0038 
0039 #ifdef FASTJET_HAVE_THREAD_SAFETY
0040 // use C11's shared pointer
0041 //std::shared_ptr #include <memory>
0042 #include <atomic>
0043 #endif // FASTJET_HAVE_THREAD_SAFETY
0044 
0045 FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
0046 
0047 
0048 /**
0049  * @ingroup advanced_usage
0050  * \class SharedPtr
0051  * 
0052  * An implementation of shared pointers that is broadly similar to C++11
0053  * shared_ptr (https://en.cppreference.com/w/cpp/memory/shared_ptr). 
0054  * One key additional feature is
0055  * 
0056  * - the ability to force an update of the count with the set_count(...)
0057  *   member.
0058  *   
0059  * This effectively allows us to incorporate an offset in the count, 
0060  * which allows deletions to be triggered even when some pointers remain. 
0061  * We use this in particular for automatic deletion of a ClusterSequence
0062  * when no pointers to its structure object remain other than those in 
0063  * the PseudoJets that are part of the ClusterSequence object itself. 
0064  * 
0065  * Key features that are missing relative to C++11 are 
0066  * 
0067  *  - conversion from weak and auto pointers
0068  *  - support for deleters and allocators
0069  *  - static, constant and dynamic casts
0070  *  - constructor and assignment sharing ownership with a shared
0071  *    pointer r but storing a different pointer than r (needed for the
0072  *    previous item)
0073  * 
0074  * In the last 2 cases, their implementation would require storing two
0075  * pointers for every copies of the shared pointer, while our
0076  * implementation only needs one. We did not implement them since we
0077  * want to limit as much as possible memory and time consumption, and
0078  * can easily avoid (at least for our needs so far) the casts.
0079  * 
0080  * The class has been tested against the boost (v1.42)
0081  * implementation (for the parts that we have implemented).
0082  */
0083 #ifdef FASTJET_HAVE_THREAD_SAFETY
0084 template<class T>
0085 class SharedPtr{
0086 public:
0087   /// forward declaration of the counting container
0088   class __SharedCountingPtr;
0089 
0090   /// default ctor
0091   SharedPtr() : _ptr(NULL){}
0092   
0093   /// initialise with the main data
0094   /// \param  t  : the object we want a smart pointer to
0095   template<class Y> explicit SharedPtr(Y* ptr){
0096     _ptr = new __SharedCountingPtr(ptr);
0097   }
0098   
0099   /// overload the copy ctor so that it updates count
0100   /// \param  share : the object we want to copy
0101   SharedPtr(SharedPtr const & share) : _ptr(share._get_container()){
0102     // unless we're sharing nothing, increase the counter to reflect
0103     // the fact that we have a newcomer sharing the pointer
0104     if (_ptr!=NULL) (*_ptr)++;
0105   }
0106 
0107   /// default dtor
0108   ~SharedPtr(){
0109     // make sure the object has been allocated
0110     if (_ptr==NULL) return;
0111 
0112     _decrease_count();
0113   }
0114 
0115   /// reset the pointer to default value (NULL)
0116   void reset(){
0117     SharedPtr().swap(*this);
0118   }
0119   
0120   // will not work with the current structure
0121   /// reset from a pointer
0122   template<class Y> void reset(Y * ptr){
0123     SharedPtr(ptr).swap(*this);
0124   }
0125 
0126   // not part of the standard
0127   /// do a smart copy
0128   /// \param  share : the object we want to copy
0129   template<class Y> void reset(SharedPtr<Y> const & share){
0130     // if we already are pointing to sth, be sure to decrease its count
0131     if (_ptr!=NULL){
0132       // in the specific case where we're share is the same as *this,
0133       // reset() has no effect. However if *this is the only instance
0134       // still alive (implying share==*this) bringing the count down
0135       // to 0 and deleting the object will not have the expected
0136       // effect. So we just avoid that situation explicitly
0137       if (_ptr == share._get_container()) return;
0138     
0139       _decrease_count();
0140     }
0141     
0142     // Watch out: if share is empty, construct an empty shared_ptr
0143     
0144     // copy the container
0145     _ptr = share._get_container();  // Note: automatically set it to NULL if share is empty
0146     
0147     if (_ptr!=NULL) (*_ptr)++;
0148   }
0149   
0150   /// overload the = operator so that it updates count
0151   /// \param  share : the object we want to copy
0152   SharedPtr& operator=(SharedPtr const & share){
0153     reset(share);
0154     return *this;
0155   }
0156   
0157   /// overload the = operator so that it updates count
0158   /// \param  share : the object we want to copy
0159   template<class Y> SharedPtr& operator=(SharedPtr<Y> const & share){
0160     reset(share);
0161     return *this;
0162   }
0163 
0164   /// indirection, get a reference to the stored pointer
0165   ///
0166   /// !!! WATCH OUT
0167   /// It does NOT impose the requirement that the stored pointer must
0168   /// not be NULL!!  So you need explicitly to check the validity in
0169   /// your code
0170   inline T& operator*() const{
0171     return *(_ptr->get());
0172   }
0173 
0174   /// indirection, get the stored pointer
0175   ///
0176   /// !!! WATCH OUT
0177   /// It fails to check the requirement that the stored pointer must
0178   /// not be NULL!!  So you need explicitly to check the validity in
0179   /// your code
0180   inline T* operator->() const{
0181     if (_ptr==NULL) return NULL;
0182     return _ptr->get();
0183   }  
0184 
0185   /// get the stored pointer
0186   inline T* get() const{
0187     if (_ptr==NULL) return NULL;
0188     return _ptr->get();
0189   }
0190 
0191   /// return the pointer we're pointing to
0192   ///
0193   /// WARNING: THIS IS DEPRECATED AND IS VERY LIKELY TO DISAPPEAR IN A
0194   /// FUTURE RELEASE. USE get() INSTEAD
0195   T* operator ()() const{
0196     if (_ptr==NULL) return NULL;
0197     return _ptr->get(); // automatically returns NULL when out-of-scope
0198   }
0199 
0200   /// check if the instance is unique
0201   inline bool unique() const{
0202     //GS: do we need some specific spin-lock here?
0203     return (use_count()==1);
0204   }
0205 
0206   /// return the number of counts
0207   inline long use_count() const{
0208     if (_ptr==NULL) return 0;
0209     return _ptr->use_count(); // automatically returns NULL when out-of-scope
0210   }
0211 
0212   /// conversion to bool
0213   /// This will allow you to use the indirection nicely
0214   inline operator bool() const{
0215     return (get()!=NULL);
0216   }
0217 
0218   /// exchange the content of the two pointers
0219   inline void swap(SharedPtr & share){
0220     __SharedCountingPtr* share_container = share._ptr;
0221     share._ptr = _ptr;
0222     _ptr = share_container;
0223   }
0224 
0225   /// force the count to be set to a specified value
0226   ///   \param count   the value that we need to reset to
0227   void set_count(const long & count){
0228     if (_ptr==NULL) return;
0229     _ptr->set_count(count);
0230   }
0231 
0232   /**
0233    * \if internal_doc
0234    * \class __SharedCountingPtr
0235    * A reference-counting pointer
0236    *
0237    * This is implemented as a container for that pointer together with
0238    * reference counting.
0239    * The pointer is deleted when the number of counts goes to 0;
0240    * \endif
0241    */
0242   class __SharedCountingPtr : public std::atomic<long>{
0243   public:
0244     /// default ctor
0245     __SharedCountingPtr() : std::atomic<long>(0), _ptr(NULL){} 
0246     
0247     /// ctor with initialisation
0248     template<class Y> explicit __SharedCountingPtr(Y* ptr)
0249       : std::atomic<long>(1), _ptr(ptr){}
0250     
0251     /// default dtor
0252     ~__SharedCountingPtr(){ 
0253       // force the deletion of the object we keep track of
0254       if (_ptr!=NULL){ delete _ptr;}
0255     }
0256 
0257     /// return a pointer to the object
0258     inline T* get() const {return _ptr;}
0259 
0260     /// return the count
0261     inline long use_count() const {return (long)(*this);}
0262 
0263     /// force the count to be set to a specified value
0264     ///   \param count   the value that we ned to reset to
0265     inline void set_count(const long & count){ store(count);}
0266 
0267   private:
0268     T *_ptr;               ///< the pointer we're counting the references to
0269   };
0270 
0271 private:
0272   /// return the common container
0273   inline __SharedCountingPtr* _get_container() const{
0274     return _ptr;
0275   }
0276 
0277   /// decrease the pointer count and support deletion
0278   /// Warning: we don't test that the pointer is allocated
0279   ///          This can be dangerous if we have explicitly reset the
0280   ///          count.  Generally speaking, if the count goes negative
0281   ///          after _ptr has been effectively deleted, this is going
0282   ///          to lead to a segmentation fault. But, if in the course
0283   ///          of the deletion of _ptr, the deletion of its pointer
0284   ///          (_ptr::_ptr, i.e. the real data we're storing) makes
0285   ///          the counts to become negative, this is going to pass
0286   ///          smoothly.
0287   void _decrease_count(){
0288     //// decrease the count
0289     //(*_ptr)--;
0290     //
0291     //// if no one else is using it, free the allocated memory
0292     //if (_ptr->use_count()==0)
0293     //  delete _ptr; // that automatically deletes the object itself
0294     // NB: https://en.cppreference.com/w/cpp/atomic/atomic/operator_arith
0295     // indicates that this uses the atomic fetch_sub(...) function, which
0296     // is what ensures thread safety of the deletion.
0297     if (((*_ptr)--) == 1)
0298       delete _ptr;
0299   }
0300 
0301   // the real info
0302   __SharedCountingPtr *_ptr;
0303 };
0304 
0305 
0306 /// comparison: equality
0307 template<class T,class U>
0308 inline bool operator==(SharedPtr<T> const & t, SharedPtr<U> const & u){
0309   return t.get() == u.get();
0310 }
0311 
0312 /// comparison: difference
0313 template<class T,class U>
0314 inline bool operator!=(SharedPtr<T> const & t, SharedPtr<U> const & u){
0315   return t.get() != u.get();
0316 }
0317 
0318 /// comparison: orgering
0319 template<class T,class U>
0320 inline bool operator<(SharedPtr<T> const & t, SharedPtr<U> const & u){
0321   return t.get() < u.get();
0322 }
0323 
0324 /// swapping
0325 template<class T>
0326 inline void swap(SharedPtr<T> & a, SharedPtr<T> & b){
0327   return a.swap(b);
0328 }
0329 
0330 /// getting the pointer
0331 template<class T>
0332 inline T* get_pointer(SharedPtr<T> const & t){
0333   return t.get();
0334 }
0335 
0336 
0337 
0338 #else  // FASTJET_HAVE_THREAD_SAFETY
0339 
0340 template<class T>
0341 class SharedPtr{
0342 public:
0343   /// forward declaration of the counting container
0344   class __SharedCountingPtr;
0345 
0346   /// default ctor
0347   SharedPtr() : _ptr(NULL){}
0348   
0349   /// initialise with the main data
0350   /// \param  t  : the object we want a smart pointer to
0351   template<class Y> explicit SharedPtr(Y* ptr){
0352     _ptr = new __SharedCountingPtr(ptr);
0353   }
0354   
0355   /// overload the copy ctor so that it updates count
0356   /// \param  share : the object we want to copy
0357   SharedPtr(SharedPtr const & share) : _ptr(share._get_container()){
0358     if (_ptr!=NULL) ++(*_ptr);
0359   }
0360   // old version
0361   //  SharedPtr(SharedPtr const & share) : _ptr(NULL){
0362   //    reset(share);
0363   //  }
0364     
0365   // will not work with the current structure
0366   // /// overload the copy ctor so that it updates count
0367   // /// \param  share : the object we want to copy
0368   // template<class Y> SharedPtr(SharedPtr<Y> const & share) : _ptr(NULL){
0369   //   reset(share);
0370   // }
0371 
0372   /// default dtor
0373   ~SharedPtr(){
0374     // make sure the object has been allocated
0375     if (_ptr==NULL) return;
0376 
0377     _decrease_count();
0378   }
0379 
0380   /// reset the pointer to default value (NULL)
0381   void reset(){
0382     // // if we already are pointing to sth, be sure to decrease its count
0383     // if (_ptr!=NULL) _decrease_count();
0384     // _ptr = NULL;
0385     SharedPtr().swap(*this);
0386   }
0387   
0388   // will not work with the current structure
0389   /// reset from a pointer
0390   template<class Y> void reset(Y * ptr){
0391     // // if we already are pointing to sth, be sure to decrease its count
0392     // if (_ptr!=NULL) _decrease_count();
0393     // 
0394     // _ptr = new __SharedCountingPtr(ptr);
0395     SharedPtr(ptr).swap(*this);
0396   }
0397 
0398   // not part of the standard
0399   /// do a smart copy
0400   /// \param  share : the object we want to copy
0401   /// Q? Do we need a non-template<Y> version as for the ctor and the assignment?
0402   template<class Y> void reset(SharedPtr<Y> const & share){
0403   //void reset(SharedPtr const & share){
0404     // if we already are pointing to sth, be sure to decrease its count
0405     if (_ptr!=NULL){
0406       // in the specific case where we're having the same
0407       // share,reset() has actually no effect. However if *this is the
0408       // only instance still alive (implying share==*this) bringing
0409       // the count down to 0 and deleting the object will not have the
0410       // expected effect. So we just avoid that situation explicitly
0411       if (_ptr == share._get_container()) return;
0412     
0413       _decrease_count();
0414     }
0415     
0416     // Watch out: if share is empty, construct an empty shared_ptr
0417     
0418     // copy the container
0419     _ptr = share._get_container();  // Note: automatically set it to NULL if share is empty
0420     
0421     if (_ptr!=NULL) ++(*_ptr);
0422   }
0423   
0424   /// overload the = operator so that it updates count
0425   /// \param  share : the object we want to copy
0426   SharedPtr& operator=(SharedPtr const & share){
0427     reset(share);
0428     return *this;
0429   }
0430   
0431   /// overload the = operator so that it updates count
0432   /// \param  share : the object we want to copy
0433   template<class Y> SharedPtr& operator=(SharedPtr<Y> const & share){
0434     reset(share);
0435     return *this;
0436   }
0437   
0438   // 2015-04-23: this does not belong to most standard implmentations
0439   // (use get() instead), we should  get rid of it
0440   //
0441   /// return the pointer we're pointing to  
0442   ///
0443   /// Since FastJet 3.2.0, this is depracated since it is no longer
0444   /// part of std::shared_ptr<T>. Use SharedPtr<T>::get() instead
0445   FASTJET_DEPRECATED_MSG("Use SharedPtr<T>::get() instead",
0446   T* operator ()() const){
0447     if (_ptr==NULL) return NULL;
0448     return _ptr->get(); // automatically returns NULL when out-of-scope
0449   }
0450   
0451   /// indirection, get a reference to the stored pointer
0452   ///
0453   /// !!! WATCH OUT
0454   /// It fails to check the requirement that the stored pointer must
0455   /// not be NULL!!  So you need explicitly to check the validity in
0456   /// your code
0457   inline T& operator*() const{
0458     return *(_ptr->get());
0459   }
0460 
0461   /// indirection, get the stored pointer
0462   ///
0463   /// !!! WATCH OUT
0464   /// It fails to check the requirement that the stored pointer must
0465   /// not be NULL!!  So you need explicitly to check the validity in
0466   /// your code
0467   inline T* operator->() const{
0468     if (_ptr==NULL) return NULL;
0469     return _ptr->get();
0470   }  
0471 
0472   /// get the stored pointer
0473   inline T* get() const{
0474     if (_ptr==NULL) return NULL;
0475     return _ptr->get();
0476   }
0477 
0478   /// check if the instance is unique
0479   inline bool unique() const{
0480     return (use_count()==1);
0481   }
0482 
0483   /// return the number of counts
0484   inline long use_count() const{
0485     if (_ptr==NULL) return 0;
0486     return _ptr->use_count(); // automatically returns NULL when out-of-scope
0487   }
0488 
0489   /// conversion to bool
0490   /// This will allow you to use the indirection nicely
0491   #ifdef FASTJET_HAVE_EXPLICIT_FOR_OPERATORS
0492   explicit
0493   #endif
0494   inline operator bool() const{
0495     return (get()!=NULL);
0496   }
0497 
0498   /// exchange the content of the two pointers
0499   inline void swap(SharedPtr & share){
0500     __SharedCountingPtr* share_container = share._ptr;
0501     share._ptr = _ptr;
0502     _ptr = share_container;
0503   }
0504 
0505   /// force the count to be set to a specified value
0506   ///   \param count   the value that we need to reset to
0507   void set_count(const long & count){
0508     if (_ptr==NULL) return;
0509     _ptr->set_count(count);
0510   }
0511 
0512   /**
0513    * \if internal_doc
0514    * \class __SharedCountingPtr
0515    * A reference-counting pointer
0516    *
0517    * This is implemented as a container for that pointer together with
0518    * reference counting.
0519    * The pointer is deleted when the number of counts goes to 0;
0520    * \endif
0521    */
0522   class __SharedCountingPtr{
0523   public:
0524     /// default ctor
0525     __SharedCountingPtr() : _ptr(NULL), _count(0){}
0526     
0527     /// ctor with initialisation
0528     template<class Y> explicit __SharedCountingPtr(Y* ptr) : _ptr(ptr), _count(1){}
0529     
0530     /// default dtor
0531     ~__SharedCountingPtr(){ 
0532       // force the deletion of the object we keep track of
0533       if (_ptr!=NULL){ delete _ptr;}
0534     }
0535 
0536     /// return a pointer to the object
0537     inline T* get() const {return _ptr;}
0538 
0539     /// return the count
0540     inline long use_count() const {return _count;}
0541 
0542     /// prefix increment operator
0543     inline long operator++(){return ++_count;}
0544 
0545     /// prefix decrement operator
0546     inline long operator--(){return --_count;}
0547 
0548     /// postfix increment operator
0549     /// The "dummy" int argument is just a C++ trick to differentiate
0550     /// it from the prefix increment
0551     inline long operator++(int){return _count++;}
0552 
0553     /// postfix decrement operator
0554     /// The "dummy" int argument is just a C++ trick to differentiate
0555     /// it from the prefix decrement
0556     inline long operator--(int){return _count--;}
0557 
0558     /// force the count to be set to a specified value
0559     ///   \param count   the value that we ned to reset to
0560     void set_count(const long & count){
0561       _count = count;
0562     }
0563 
0564   private:
0565     T *_ptr;      ///< the pointer we're counting the references to
0566     long _count;  ///< the number of references
0567   };
0568 
0569 private:
0570   /// return the common container
0571   inline __SharedCountingPtr* _get_container() const{
0572     return _ptr;
0573   }
0574 
0575   /// decrease the pointer count and support deletion
0576   /// Warning: we don't test that the pointer is allocated
0577   ///          This can be dangerous if we have explicitly reset the
0578   ///          count.  Generally speaking, if the count goes negative
0579   ///          after _ptr has been effectively deleted, this is going
0580   ///          to lead to a segmentation fault. But, if in the course
0581   ///          of the deletion of _ptr, the deletion of its pointer
0582   ///          (_ptr::_ptr, i.e. the real data we're storing) makes
0583   ///          the counts to become negative, this is going to pass
0584   ///          smoothly.
0585   void _decrease_count(){
0586     // decrease the count
0587     (*_ptr)--;
0588     
0589     // if no one else is using it, free the allocated memory
0590     if (_ptr->use_count()==0)
0591       delete _ptr; // that automatically deletes the object itself
0592   }
0593 
0594   // the real info
0595   __SharedCountingPtr *_ptr;
0596 };
0597 
0598 
0599 /// comparison: equality
0600 template<class T,class U>
0601 inline bool operator==(SharedPtr<T> const & t, SharedPtr<U> const & u){
0602   return t.get() == u.get();
0603 }
0604 
0605 /// comparison: difference
0606 template<class T,class U>
0607 inline bool operator!=(SharedPtr<T> const & t, SharedPtr<U> const & u){
0608   return t.get() != u.get();
0609 }
0610 
0611 /// comparison: orgering
0612 template<class T,class U>
0613 inline bool operator<(SharedPtr<T> const & t, SharedPtr<U> const & u){
0614   return t.get() < u.get();
0615 }
0616 
0617 /// swapping
0618 template<class T>
0619 inline void swap(SharedPtr<T> & a, SharedPtr<T> & b){
0620   return a.swap(b);
0621 }
0622 
0623 /// getting the pointer
0624 template<class T>
0625 inline T* get_pointer(SharedPtr<T> const & t){
0626   return t.get();
0627 }
0628 
0629 #endif // FASTJET_HAVE_THREAD_SAFETY
0630 
0631 FASTJET_END_NAMESPACE      // defined in fastjet/internal/base.hh
0632 
0633 #endif   // __FASTJET_SHARED_PTR_HH__