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