|
||||
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__
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |