FastJet 3.4.1
SharedPtr.hh
1 #ifndef __FASTJET_SHARED_PTR_HH__
2#define __FASTJET_SHARED_PTR_HH__
3
4//FJSTARTHEADER
5// $Id$
6//
7// Copyright (c) 2005-2023, 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
45FASTJET_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
84template<class T>
85class SharedPtr{
86public:
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
271private:
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
307template<class T,class U>
308inline bool operator==(SharedPtr<T> const & t, SharedPtr<U> const & u){
309 return t.get() == u.get();
310}
311
312/// comparison: difference
313template<class T,class U>
314inline bool operator!=(SharedPtr<T> const & t, SharedPtr<U> const & u){
315 return t.get() != u.get();
316}
317
318/// comparison: ordering
319template<class T,class U>
320inline bool operator<(SharedPtr<T> const & t, SharedPtr<U> const & u){
321 return t.get() < u.get();
322}
323
324/// swapping
325template<class T>
326inline void swap(SharedPtr<T> & a, SharedPtr<T> & b){
327 return a.swap(b);
328}
329
330/// getting the pointer
331template<class T>
332inline T* get_pointer(SharedPtr<T> const & t){
333 return t.get();
334}
335
336
337
338#else // FASTJET_HAVE_THREAD_SAFETY
339
340template<class T>
342public:
343 /// forward declaration of the counting container
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
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 */
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
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
569private:
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
600template<class T,class U>
601inline bool operator==(SharedPtr<T> const & t, SharedPtr<U> const & u){
602 return t.get() == u.get();
603}
604
605/// comparison: difference
606template<class T,class U>
607inline bool operator!=(SharedPtr<T> const & t, SharedPtr<U> const & u){
608 return t.get() != u.get();
609}
610
611/// comparison: ordering
612template<class T,class U>
613inline bool operator<(SharedPtr<T> const & t, SharedPtr<U> const & u){
614 return t.get() < u.get();
615}
616
617/// swapping
618template<class T>
619inline void swap(SharedPtr<T> & a, SharedPtr<T> & b){
620 return a.swap(b);
621}
622
623/// getting the pointer
624template<class T>
625inline T* get_pointer(SharedPtr<T> const & t){
626 return t.get();
627}
628
629#endif // FASTJET_HAVE_THREAD_SAFETY
630
631FASTJET_END_NAMESPACE // defined in fastjet/internal/base.hh
632
633#endif // __FASTJET_SHARED_PTR_HH__
T * get() const
return a pointer to the object
Definition: SharedPtr.hh:537
long operator--()
prefix decrement operator
Definition: SharedPtr.hh:546
void set_count(const long &count)
force the count to be set to a specified value
Definition: SharedPtr.hh:560
long operator++(int)
postfix increment operator The "dummy" int argument is just a C++ trick to differentiate it from the ...
Definition: SharedPtr.hh:551
long operator++()
prefix increment operator
Definition: SharedPtr.hh:543
long use_count() const
return the count
Definition: SharedPtr.hh:540
long operator--(int)
postfix decrement operator The "dummy" int argument is just a C++ trick to differentiate it from the ...
Definition: SharedPtr.hh:556
__SharedCountingPtr(Y *ptr)
ctor with initialisation
Definition: SharedPtr.hh:528
An implementation of shared pointers that is broadly similar to C++11 shared_ptr (https://en....
Definition: SharedPtr.hh:341
void reset(SharedPtr< Y > const &share)
do a smart copy
Definition: SharedPtr.hh:402
SharedPtr(SharedPtr const &share)
overload the copy ctor so that it updates count
Definition: SharedPtr.hh:357
T & operator*() const
indirection, get a reference to the stored pointer
Definition: SharedPtr.hh:457
SharedPtr & operator=(SharedPtr< Y > const &share)
overload the = operator so that it updates count
Definition: SharedPtr.hh:433
~SharedPtr()
default dtor
Definition: SharedPtr.hh:373
T * get() const
get the stored pointer
Definition: SharedPtr.hh:473
SharedPtr()
default ctor
Definition: SharedPtr.hh:347
T * operator->() const
indirection, get the stored pointer
Definition: SharedPtr.hh:467
void reset()
reset the pointer to default value (NULL)
Definition: SharedPtr.hh:381
SharedPtr & operator=(SharedPtr const &share)
overload the = operator so that it updates count
Definition: SharedPtr.hh:426
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:926
bool operator<(SharedPtr< T > const &t, SharedPtr< U > const &u)
comparison: ordering
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:345
void swap(SharedPtr< T > &a, SharedPtr< T > &b)
swapping
Definition: SharedPtr.hh:619