FastJet  3.4.0
SharedPtr.hh
1  #ifndef __FASTJET_SHARED_PTR_HH__
2 #define __FASTJET_SHARED_PTR_HH__
3 
4 //FJSTARTHEADER
5 // $Id$
6 //
7 // Copyright (c) 2005-2021, Matteo Cacciari, Gavin P. Salam and Gregory Soyez
8 //
9 //----------------------------------------------------------------------
10 // This file is part of FastJet.
11 //
12 // FastJet is free software; you can redistribute it and/or modify
13 // it under the terms of the GNU General Public License as published by
14 // the Free Software Foundation; either version 2 of the License, or
15 // (at your option) any later version.
16 //
17 // The algorithms that underlie FastJet have required considerable
18 // development. They are described in the original FastJet paper,
19 // hep-ph/0512210 and in the manual, arXiv:1111.6097. If you use
20 // FastJet as part of work towards a scientific publication, please
21 // quote the version you use and include a citation to the manual and
22 // optionally also to hep-ph/0512210.
23 //
24 // FastJet is distributed in the hope that it will be useful,
25 // but WITHOUT ANY WARRANTY; without even the implied warranty of
26 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 // GNU General Public License for more details.
28 //
29 // You should have received a copy of the GNU General Public License
30 // along with FastJet. If not, see <http://www.gnu.org/licenses/>.
31 //----------------------------------------------------------------------
32 //FJENDHEADER
33 
34 #include "fastjet/internal/base.hh"
35 #include "fastjet/config.h"
36 #include <cstdlib> // for NULL!!!
37 #include "fastjet/internal/deprecated.hh"
38 
39 #ifdef FASTJET_HAVE_THREAD_SAFETY
40 // use C11's shared pointer
41 //std::shared_ptr #include <memory>
42 #include <atomic>
43 #endif // FASTJET_HAVE_THREAD_SAFETY
44 
45 FASTJET_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
46 
47 
48 /**
49  * @ingroup advanced_usage
50  * \class SharedPtr
51  *
52  * An implementation of shared pointers that is broadly similar to C++11
53  * shared_ptr (https://en.cppreference.com/w/cpp/memory/shared_ptr).
54  * One key additional feature is
55  *
56  * - the ability to force an update of the count with the set_count(...)
57  * member.
58  *
59  * This effectively allows us to incorporate an offset in the count,
60  * which allows deletions to be triggered even when some pointers remain.
61  * We use this in particular for automatic deletion of a ClusterSequence
62  * when no pointers to its structure object remain other than those in
63  * the PseudoJets that are part of the ClusterSequence object itself.
64  *
65  * Key features that are missing relative to C++11 are
66  *
67  * - conversion from weak and auto pointers
68  * - support for deleters and allocators
69  * - static, constant and dynamic casts
70  * - constructor and assignment sharing ownership with a shared
71  * pointer r but storing a different pointer than r (needed for the
72  * previous item)
73  *
74  * In the last 2 cases, their implementation would require storing two
75  * pointers for every copies of the shared pointer, while our
76  * implementation only needs one. We did not implement them since we
77  * want to limit as much as possible memory and time consumption, and
78  * can easily avoid (at least for our needs so far) the casts.
79  *
80  * The class has been tested against the boost (v1.42)
81  * implementation (for the parts that we have implemented).
82  */
83 #ifdef FASTJET_HAVE_THREAD_SAFETY
84 template<class T>
85 class SharedPtr{
86 public:
87  /// forward declaration of the counting container
88  class __SharedCountingPtr;
89 
90  /// default ctor
91  SharedPtr() : _ptr(NULL){}
92 
93  /// initialise with the main data
94  /// \param t : the object we want a smart pointer to
95  template<class Y> explicit SharedPtr(Y* ptr){
96  _ptr = new __SharedCountingPtr(ptr);
97  }
98 
99  /// overload the copy ctor so that it updates count
100  /// \param share : the object we want to copy
101  SharedPtr(SharedPtr const & share) : _ptr(share._get_container()){
102  // unless we're sharing nothing, increase the counter to reflect
103  // the fact that we have a newcomer sharing the pointer
104  if (_ptr!=NULL) (*_ptr)++;
105  }
106 
107  /// default dtor
108  ~SharedPtr(){
109  // make sure the object has been allocated
110  if (_ptr==NULL) return;
111 
112  _decrease_count();
113  }
114 
115  /// reset the pointer to default value (NULL)
116  void reset(){
117  SharedPtr().swap(*this);
118  }
119 
120  // will not work with the current structure
121  /// reset from a pointer
122  template<class Y> void reset(Y * ptr){
123  SharedPtr(ptr).swap(*this);
124  }
125 
126  // not part of the standard
127  /// do a smart copy
128  /// \param share : the object we want to copy
129  template<class Y> void reset(SharedPtr<Y> const & share){
130  // if we already are pointing to sth, be sure to decrease its count
131  if (_ptr!=NULL){
132  // in the specific case where we're share is the same as *this,
133  // reset() has no effect. However if *this is the only instance
134  // still alive (implying share==*this) bringing the count down
135  // to 0 and deleting the object will not have the expected
136  // effect. So we just avoid that situation explicitly
137  if (_ptr == share._get_container()) return;
138 
139  _decrease_count();
140  }
141 
142  // Watch out: if share is empty, construct an empty shared_ptr
143 
144  // copy the container
145  _ptr = share._get_container(); // Note: automatically set it to NULL if share is empty
146 
147  if (_ptr!=NULL) (*_ptr)++;
148  }
149 
150  /// overload the = operator so that it updates count
151  /// \param share : the object we want to copy
152  SharedPtr& operator=(SharedPtr const & share){
153  reset(share);
154  return *this;
155  }
156 
157  /// overload the = operator so that it updates count
158  /// \param share : the object we want to copy
159  template<class Y> SharedPtr& operator=(SharedPtr<Y> const & share){
160  reset(share);
161  return *this;
162  }
163 
164  /// indirection, get a reference to the stored pointer
165  ///
166  /// !!! WATCH OUT
167  /// It does NOT impose the requirement that the stored pointer must
168  /// not be NULL!! So you need explicitly to check the validity in
169  /// your code
170  inline T& operator*() const{
171  return *(_ptr->get());
172  }
173 
174  /// indirection, get the stored pointer
175  ///
176  /// !!! WATCH OUT
177  /// It fails to check the requirement that the stored pointer must
178  /// not be NULL!! So you need explicitly to check the validity in
179  /// your code
180  inline T* operator->() const{
181  if (_ptr==NULL) return NULL;
182  return _ptr->get();
183  }
184 
185  /// get the stored pointer
186  inline T* get() const{
187  if (_ptr==NULL) return NULL;
188  return _ptr->get();
189  }
190 
191  /// return the pointer we're pointing to
192  ///
193  /// WARNING: THIS IS DEPRECATED AND IS VERY LIKELY TO DISAPPEAR IN A
194  /// FUTURE RELEASE. USE get() INSTEAD
195  T* operator ()() const{
196  if (_ptr==NULL) return NULL;
197  return _ptr->get(); // automatically returns NULL when out-of-scope
198  }
199 
200  /// check if the instance is unique
201  inline bool unique() const{
202  //GS: do we need some specific spin-lock here?
203  return (use_count()==1);
204  }
205 
206  /// return the number of counts
207  inline long use_count() const{
208  if (_ptr==NULL) return 0;
209  return _ptr->use_count(); // automatically returns NULL when out-of-scope
210  }
211 
212  /// conversion to bool
213  /// This will allow you to use the indirection nicely
214  inline operator bool() const{
215  return (get()!=NULL);
216  }
217 
218  /// exchange the content of the two pointers
219  inline void swap(SharedPtr & share){
220  __SharedCountingPtr* share_container = share._ptr;
221  share._ptr = _ptr;
222  _ptr = share_container;
223  }
224 
225  /// force the count to be set to a specified value
226  /// \param count the value that we need to reset to
227  void set_count(const long & count){
228  if (_ptr==NULL) return;
229  _ptr->set_count(count);
230  }
231 
232  /**
233  * \if internal_doc
234  * \class __SharedCountingPtr
235  * A reference-counting pointer
236  *
237  * This is implemented as a container for that pointer together with
238  * reference counting.
239  * The pointer is deleted when the number of counts goes to 0;
240  * \endif
241  */
242  class __SharedCountingPtr : public std::atomic<long>{
243  public:
244  /// default ctor
245  __SharedCountingPtr() : std::atomic<long>(0), _ptr(NULL){}
246 
247  /// ctor with initialisation
248  template<class Y> explicit __SharedCountingPtr(Y* ptr)
249  : std::atomic<long>(1), _ptr(ptr){}
250 
251  /// default dtor
252  ~__SharedCountingPtr(){
253  // force the deletion of the object we keep track of
254  if (_ptr!=NULL){ delete _ptr;}
255  }
256 
257  /// return a pointer to the object
258  inline T* get() const {return _ptr;}
259 
260  /// return the count
261  inline long use_count() const {return (long)(*this);}
262 
263  /// force the count to be set to a specified value
264  /// \param count the value that we ned to reset to
265  inline void set_count(const long & count){ store(count);}
266 
267  private:
268  T *_ptr; ///< the pointer we're counting the references to
269  };
270 
271 private:
272  /// return the common container
273  inline __SharedCountingPtr* _get_container() const{
274  return _ptr;
275  }
276 
277  /// decrease the pointer count and support deletion
278  /// Warning: we don't test that the pointer is allocated
279  /// This can be dangerous if we have explicitly reset the
280  /// count. Generally speaking, if the count goes negative
281  /// after _ptr has been effectively deleted, this is going
282  /// to lead to a segmentation fault. But, if in the course
283  /// of the deletion of _ptr, the deletion of its pointer
284  /// (_ptr::_ptr, i.e. the real data we're storing) makes
285  /// the counts to become negative, this is going to pass
286  /// smoothly.
287  void _decrease_count(){
288  //// decrease the count
289  //(*_ptr)--;
290  //
291  //// if no one else is using it, free the allocated memory
292  //if (_ptr->use_count()==0)
293  // delete _ptr; // that automatically deletes the object itself
294  // NB: https://en.cppreference.com/w/cpp/atomic/atomic/operator_arith
295  // indicates that this uses the atomic fetch_sub(...) function, which
296  // is what ensures thread safety of the deletion.
297  if (((*_ptr)--) == 1)
298  delete _ptr;
299  }
300 
301  // the real info
302  __SharedCountingPtr *_ptr;
303 };
304 
305 
306 /// comparison: equality
307 template<class T,class U>
308 inline bool operator==(SharedPtr<T> const & t, SharedPtr<U> const & u){
309  return t.get() == u.get();
310 }
311 
312 /// comparison: difference
313 template<class T,class U>
314 inline bool operator!=(SharedPtr<T> const & t, SharedPtr<U> const & u){
315  return t.get() != u.get();
316 }
317 
318 /// comparison: orgering
319 template<class T,class U>
320 inline bool operator<(SharedPtr<T> const & t, SharedPtr<U> const & u){
321  return t.get() < u.get();
322 }
323 
324 /// swapping
325 template<class T>
326 inline void swap(SharedPtr<T> & a, SharedPtr<T> & b){
327  return a.swap(b);
328 }
329 
330 /// getting the pointer
331 template<class T>
332 inline T* get_pointer(SharedPtr<T> const & t){
333  return t.get();
334 }
335 
336 
337 
338 #else // FASTJET_HAVE_THREAD_SAFETY
339 
340 template<class T>
341 class SharedPtr{
342 public:
343  /// forward declaration of the counting container
344  class __SharedCountingPtr;
345 
346  /// default ctor
347  SharedPtr() : _ptr(NULL){}
348 
349  /// initialise with the main data
350  /// \param t : the object we want a smart pointer to
351  template<class Y> explicit SharedPtr(Y* ptr){
352  _ptr = new __SharedCountingPtr(ptr);
353  }
354 
355  /// overload the copy ctor so that it updates count
356  /// \param share : the object we want to copy
357  SharedPtr(SharedPtr const & share) : _ptr(share._get_container()){
358  if (_ptr!=NULL) ++(*_ptr);
359  }
360  // old version
361  // SharedPtr(SharedPtr const & share) : _ptr(NULL){
362  // reset(share);
363  // }
364 
365  // will not work with the current structure
366  // /// overload the copy ctor so that it updates count
367  // /// \param share : the object we want to copy
368  // template<class Y> SharedPtr(SharedPtr<Y> const & share) : _ptr(NULL){
369  // reset(share);
370  // }
371 
372  /// default dtor
374  // make sure the object has been allocated
375  if (_ptr==NULL) return;
376 
377  _decrease_count();
378  }
379 
380  /// reset the pointer to default value (NULL)
381  void reset(){
382  // // if we already are pointing to sth, be sure to decrease its count
383  // if (_ptr!=NULL) _decrease_count();
384  // _ptr = NULL;
385  SharedPtr().swap(*this);
386  }
387 
388  // will not work with the current structure
389  /// reset from a pointer
390  template<class Y> void reset(Y * ptr){
391  // // if we already are pointing to sth, be sure to decrease its count
392  // if (_ptr!=NULL) _decrease_count();
393  //
394  // _ptr = new __SharedCountingPtr(ptr);
395  SharedPtr(ptr).swap(*this);
396  }
397 
398  // not part of the standard
399  /// do a smart copy
400  /// \param share : the object we want to copy
401  /// Q? Do we need a non-template<Y> version as for the ctor and the assignment?
402  template<class Y> void reset(SharedPtr<Y> const & share){
403  //void reset(SharedPtr const & share){
404  // if we already are pointing to sth, be sure to decrease its count
405  if (_ptr!=NULL){
406  // in the specific case where we're having the same
407  // share,reset() has actually no effect. However if *this is the
408  // only instance still alive (implying share==*this) bringing
409  // the count down to 0 and deleting the object will not have the
410  // expected effect. So we just avoid that situation explicitly
411  if (_ptr == share._get_container()) return;
412 
413  _decrease_count();
414  }
415 
416  // Watch out: if share is empty, construct an empty shared_ptr
417 
418  // copy the container
419  _ptr = share._get_container(); // Note: automatically set it to NULL if share is empty
420 
421  if (_ptr!=NULL) ++(*_ptr);
422  }
423 
424  /// overload the = operator so that it updates count
425  /// \param share : the object we want to copy
426  SharedPtr& operator=(SharedPtr const & share){
427  reset(share);
428  return *this;
429  }
430 
431  /// overload the = operator so that it updates count
432  /// \param share : the object we want to copy
433  template<class Y> SharedPtr& operator=(SharedPtr<Y> const & share){
434  reset(share);
435  return *this;
436  }
437 
438  // 2015-04-23: this does not belong to most standard implmentations
439  // (use get() instead), we should get rid of it
440  //
441  /// return the pointer we're pointing to
442  ///
443  /// Since FastJet 3.2.0, this is depracated since it is no longer
444  /// part of std::shared_ptr<T>. Use SharedPtr<T>::get() instead
445  FASTJET_DEPRECATED_MSG("Use SharedPtr<T>::get() instead",
446  T* operator ()() const){
447  if (_ptr==NULL) return NULL;
448  return _ptr->get(); // automatically returns NULL when out-of-scope
449  }
450 
451  /// indirection, get a reference to the stored pointer
452  ///
453  /// !!! WATCH OUT
454  /// It fails to check the requirement that the stored pointer must
455  /// not be NULL!! So you need explicitly to check the validity in
456  /// your code
457  inline T& operator*() const{
458  return *(_ptr->get());
459  }
460 
461  /// indirection, get the stored pointer
462  ///
463  /// !!! WATCH OUT
464  /// It fails to check the requirement that the stored pointer must
465  /// not be NULL!! So you need explicitly to check the validity in
466  /// your code
467  inline T* operator->() const{
468  if (_ptr==NULL) return NULL;
469  return _ptr->get();
470  }
471 
472  /// get the stored pointer
473  inline T* get() const{
474  if (_ptr==NULL) return NULL;
475  return _ptr->get();
476  }
477 
478  /// check if the instance is unique
479  inline bool unique() const{
480  return (use_count()==1);
481  }
482 
483  /// return the number of counts
484  inline long use_count() const{
485  if (_ptr==NULL) return 0;
486  return _ptr->use_count(); // automatically returns NULL when out-of-scope
487  }
488 
489  /// conversion to bool
490  /// This will allow you to use the indirection nicely
491  #ifdef FASTJET_HAVE_EXPLICIT_FOR_OPERATORS
492  explicit
493  #endif
494  inline operator bool() const{
495  return (get()!=NULL);
496  }
497 
498  /// exchange the content of the two pointers
499  inline void swap(SharedPtr & share){
500  __SharedCountingPtr* share_container = share._ptr;
501  share._ptr = _ptr;
502  _ptr = share_container;
503  }
504 
505  /// force the count to be set to a specified value
506  /// \param count the value that we need to reset to
507  void set_count(const long & count){
508  if (_ptr==NULL) return;
509  _ptr->set_count(count);
510  }
511 
512  /**
513  * \if internal_doc
514  * \class __SharedCountingPtr
515  * A reference-counting pointer
516  *
517  * This is implemented as a container for that pointer together with
518  * reference counting.
519  * The pointer is deleted when the number of counts goes to 0;
520  * \endif
521  */
522  class __SharedCountingPtr{
523  public:
524  /// default ctor
525  __SharedCountingPtr() : _ptr(NULL), _count(0){}
526 
527  /// ctor with initialisation
528  template<class Y> explicit __SharedCountingPtr(Y* ptr) : _ptr(ptr), _count(1){}
529 
530  /// default dtor
531  ~__SharedCountingPtr(){
532  // force the deletion of the object we keep track of
533  if (_ptr!=NULL){ delete _ptr;}
534  }
535 
536  /// return a pointer to the object
537  inline T* get() const {return _ptr;}
538 
539  /// return the count
540  inline long use_count() const {return _count;}
541 
542  /// prefix increment operator
543  inline long operator++(){return ++_count;}
544 
545  /// prefix decrement operator
546  inline long operator--(){return --_count;}
547 
548  /// postfix increment operator
549  /// The "dummy" int argument is just a C++ trick to differentiate
550  /// it from the prefix increment
551  inline long operator++(int){return _count++;}
552 
553  /// postfix decrement operator
554  /// The "dummy" int argument is just a C++ trick to differentiate
555  /// it from the prefix decrement
556  inline long operator--(int){return _count--;}
557 
558  /// force the count to be set to a specified value
559  /// \param count the value that we ned to reset to
560  void set_count(const long & count){
561  _count = count;
562  }
563 
564  private:
565  T *_ptr; ///< the pointer we're counting the references to
566  long _count; ///< the number of references
567  };
568 
569 private:
570  /// return the common container
571  inline __SharedCountingPtr* _get_container() const{
572  return _ptr;
573  }
574 
575  /// decrease the pointer count and support deletion
576  /// Warning: we don't test that the pointer is allocated
577  /// This can be dangerous if we have explicitly reset the
578  /// count. Generally speaking, if the count goes negative
579  /// after _ptr has been effectively deleted, this is going
580  /// to lead to a segmentation fault. But, if in the course
581  /// of the deletion of _ptr, the deletion of its pointer
582  /// (_ptr::_ptr, i.e. the real data we're storing) makes
583  /// the counts to become negative, this is going to pass
584  /// smoothly.
585  void _decrease_count(){
586  // decrease the count
587  (*_ptr)--;
588 
589  // if no one else is using it, free the allocated memory
590  if (_ptr->use_count()==0)
591  delete _ptr; // that automatically deletes the object itself
592  }
593 
594  // the real info
595  __SharedCountingPtr *_ptr;
596 };
597 
598 
599 /// comparison: equality
600 template<class T,class U>
601 inline bool operator==(SharedPtr<T> const & t, SharedPtr<U> const & u){
602  return t.get() == u.get();
603 }
604 
605 /// comparison: difference
606 template<class T,class U>
607 inline bool operator!=(SharedPtr<T> const & t, SharedPtr<U> const & u){
608  return t.get() != u.get();
609 }
610 
611 /// comparison: orgering
612 template<class T,class U>
613 inline bool operator<(SharedPtr<T> const & t, SharedPtr<U> const & u){
614  return t.get() < u.get();
615 }
616 
617 /// swapping
618 template<class T>
619 inline void swap(SharedPtr<T> & a, SharedPtr<T> & b){
620  return a.swap(b);
621 }
622 
623 /// getting the pointer
624 template<class T>
625 inline T* get_pointer(SharedPtr<T> const & t){
626  return t.get();
627 }
628 
629 #endif // FASTJET_HAVE_THREAD_SAFETY
630 
631 FASTJET_END_NAMESPACE // defined in fastjet/internal/base.hh
632 
633 #endif // __FASTJET_SHARED_PTR_HH__
An implementation of shared pointers that is broadly similar to C++11 shared_ptr (https://en....
Definition: SharedPtr.hh:341
T * get() const
get the stored pointer
Definition: SharedPtr.hh:473
void reset(SharedPtr< Y > const &share)
do a smart copy
Definition: SharedPtr.hh:402
SharedPtr & operator=(SharedPtr const &share)
overload the = operator so that it updates count
Definition: SharedPtr.hh:426
T * operator->() const
indirection, get the stored pointer
Definition: SharedPtr.hh:467
SharedPtr(SharedPtr const &share)
overload the copy ctor so that it updates count
Definition: SharedPtr.hh:357
~SharedPtr()
default dtor
Definition: SharedPtr.hh:373
SharedPtr & operator=(SharedPtr< Y > const &share)
overload the = operator so that it updates count
Definition: SharedPtr.hh:433
SharedPtr()
default ctor
Definition: SharedPtr.hh:347
T & operator*() const
indirection, get a reference to the stored pointer
Definition: SharedPtr.hh:457
void reset()
reset the pointer to default value (NULL)
Definition: SharedPtr.hh:381
SharedPtr(Y *ptr)
initialise with the main data
Definition: SharedPtr.hh:351
bool unique() const
check if the instance is unique
Definition: SharedPtr.hh:479
void swap(SharedPtr &share)
exchange the content of the two pointers
Definition: SharedPtr.hh:499
long use_count() const
return the number of counts
Definition: SharedPtr.hh:484
void set_count(const long &count)
force the count to be set to a specified value
Definition: SharedPtr.hh:507
void reset(Y *ptr)
reset from a pointer
Definition: SharedPtr.hh:390
Selector operator*(const Selector &s1, const Selector &s2)
successive application of 2 selectors
Definition: Selector.cc:559
bool operator!=(const PseudoJet &a, const PseudoJet &b)
inequality test which is exact opposite of operator==
Definition: PseudoJet.hh:922
bool operator<(SharedPtr< T > const &t, SharedPtr< U > const &u)
comparison: orgering
Definition: SharedPtr.hh:613
T * get_pointer(SharedPtr< T > const &t)
getting the pointer
Definition: SharedPtr.hh:625
bool operator==(const PseudoJet &a, const PseudoJet &b)
returns true if the 4 momentum components of the two PseudoJets are identical and all the internal in...
Definition: PseudoJet.cc:356
void swap(SharedPtr< T > &a, SharedPtr< T > &b)
swapping
Definition: SharedPtr.hh:619