1 | #ifndef __FASTJET_SHARED_PTR_HH__ |
---|
2 | #define __FASTJET_SHARED_PTR_HH__ |
---|
3 | |
---|
4 | //STARTHEADER |
---|
5 | // $Id: SharedPtr.hh 2680 2011-11-12 17:12:05Z soyez $ |
---|
6 | // |
---|
7 | // Copyright (c) 2005-2011, 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 and are described in hep-ph/0512210. If you use |
---|
19 | // FastJet as part of work towards a scientific publication, please |
---|
20 | // include a citation to the FastJet paper. |
---|
21 | // |
---|
22 | // FastJet is distributed in the hope that it will be useful, |
---|
23 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
24 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
25 | // GNU General Public License for more details. |
---|
26 | // |
---|
27 | // You should have received a copy of the GNU General Public License |
---|
28 | // along with FastJet. If not, see <http://www.gnu.org/licenses/>. |
---|
29 | //---------------------------------------------------------------------- |
---|
30 | //ENDHEADER |
---|
31 | |
---|
32 | #include "fastjet/internal/base.hh" |
---|
33 | #include <cstdlib> // for NULL!!! |
---|
34 | |
---|
35 | // for testing purposes, the following define makes it possible |
---|
36 | // for our SharedPtr simply to be derived from the STL TR1 one. |
---|
37 | // #define USETR1SHAREDPTR |
---|
38 | |
---|
39 | #ifdef USETR1SHAREDPTR |
---|
40 | #include <tr1/memory> |
---|
41 | #endif // USETR1SHAREDPTR |
---|
42 | |
---|
43 | FASTJET_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh |
---|
44 | |
---|
45 | #ifdef USETR1SHAREDPTR |
---|
46 | |
---|
47 | /// @ingroup advanced_usage |
---|
48 | /// \class SharedPtr |
---|
49 | /// replaces our shared pointer with the TR1 one (for testing purpose) |
---|
50 | /// |
---|
51 | /// for testing purposes, it can be useful to replace our home-made |
---|
52 | /// SharedPtr with the standard library one. Having a class derived |
---|
53 | /// from the standard one is way of arranging for this to happen. |
---|
54 | /// |
---|
55 | /// The other way of working this is a template class with an |
---|
56 | /// internal typedef (http://bytes.com/topic/c/answers/60312-typedef-template) |
---|
57 | /// since templated typedefs don't work in standard C++ |
---|
58 | /// |
---|
59 | /// Note that some facilities that are present in the FastJet shared |
---|
60 | /// pointer (resetting use-count) are not handled by the TR1 shared |
---|
61 | /// pointer; and the FastJet SharedPtr has a different underlying data |
---|
62 | /// structure from the TR1 shared pointer, which prevents us from |
---|
63 | /// implementing some of TR1 features (notably assignment from shared |
---|
64 | /// pointers to a derived class). |
---|
65 | template<class T> |
---|
66 | class SharedPtr : public std::tr1::shared_ptr<T> { |
---|
67 | public: |
---|
68 | SharedPtr() : std::tr1::shared_ptr<T>() {} |
---|
69 | SharedPtr(T * t) : std::tr1::shared_ptr<T>(t) {} |
---|
70 | SharedPtr(const SharedPtr<T> & t) : std::tr1::shared_ptr<T>(t) {} |
---|
71 | // for some reason operator() doesn't get inherited |
---|
72 | inline operator bool() const {return (this->get()!=NULL);} |
---|
73 | /// return the pointer we're pointing to |
---|
74 | T* operator ()() const{ |
---|
75 | return this->get(); // automatically returns NULL when out-of-scope |
---|
76 | } |
---|
77 | }; |
---|
78 | |
---|
79 | |
---|
80 | #else // USETR1SHAREDPTR |
---|
81 | |
---|
82 | /** |
---|
83 | * @ingroup advanced_usage |
---|
84 | * \class SharedPtr |
---|
85 | * an implementation of C++0x shared pointers (or boost's) |
---|
86 | * |
---|
87 | * this class implements a smart pointer, based on the shared+ptr |
---|
88 | * proposal. A description of shared_ptr can be found in Section 2.2.3 |
---|
89 | * of the first C++ Technical Report (TR1) |
---|
90 | * http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1745.pdf |
---|
91 | * or, alternatively, on the Boost C++ library website at |
---|
92 | * http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/shared_ptr.htm |
---|
93 | * |
---|
94 | * Our implementation is compatible with both of these apart from a |
---|
95 | * series of members and functions that have not been implemented: |
---|
96 | * - conversion from weak and auto pointers |
---|
97 | * - support for deleters and allocators |
---|
98 | * - static, constant and dynamic casts |
---|
99 | * - constructor and assignment sharing ownership with a shared |
---|
100 | * pointer r but storing a different pointer than r (needed for the |
---|
101 | * previous item) |
---|
102 | * In the last 2 cases, their implementation would require storing two |
---|
103 | * pointers for every copies of the shared pointer, while our |
---|
104 | * implementation only needs one. We did not implement then since we |
---|
105 | * want to limit as much as possible memory and time consumption, and |
---|
106 | * can easily avoid (at least for our needs so far) the casts. |
---|
107 | * |
---|
108 | * We also add the possibility to force an update of the count. |
---|
109 | * |
---|
110 | * The class has been tested against the existing boost (v1.42) |
---|
111 | * implementation (for the parts that we have implemented). |
---|
112 | */ |
---|
113 | template<class T> |
---|
114 | class SharedPtr{ |
---|
115 | public: |
---|
116 | /// forward declaration of the counting container |
---|
117 | class __SharedCountingPtr; |
---|
118 | |
---|
119 | /// default ctor |
---|
120 | SharedPtr() : _ptr(NULL){} |
---|
121 | |
---|
122 | /// initialise with the main data |
---|
123 | /// \param t : the object we want a smart pointer to |
---|
124 | template<class Y> explicit SharedPtr(Y* ptr){ |
---|
125 | _ptr = new __SharedCountingPtr(ptr); |
---|
126 | } |
---|
127 | |
---|
128 | /// overload the copy ctor so that it updates count |
---|
129 | /// \param share : the object we want to copy |
---|
130 | SharedPtr(SharedPtr const & share) : _ptr(share._get_container()){ |
---|
131 | if (_ptr!=NULL) ++(*_ptr); |
---|
132 | } |
---|
133 | // old version |
---|
134 | // SharedPtr(SharedPtr const & share) : _ptr(NULL){ |
---|
135 | // reset(share); |
---|
136 | // } |
---|
137 | |
---|
138 | // will not work with the current structure |
---|
139 | // /// overload the copy ctor so that it updates count |
---|
140 | // /// \param share : the object we want to copy |
---|
141 | // template<class Y> SharedPtr(SharedPtr<Y> const & share) : _ptr(NULL){ |
---|
142 | // reset(share); |
---|
143 | // } |
---|
144 | |
---|
145 | /// default dtor |
---|
146 | ~SharedPtr(){ |
---|
147 | // make sure the object has been allocated |
---|
148 | if (_ptr==NULL) return; |
---|
149 | |
---|
150 | _decrease_count(); |
---|
151 | } |
---|
152 | |
---|
153 | /// reset the pointer to default value (NULL) |
---|
154 | void reset(){ |
---|
155 | // // if we already are pointing to sth, be sure to decrease its count |
---|
156 | // if (_ptr!=NULL) _decrease_count(); |
---|
157 | // _ptr = NULL; |
---|
158 | SharedPtr().swap(*this); |
---|
159 | } |
---|
160 | |
---|
161 | // will not work with the current structure |
---|
162 | /// reset from a pointer |
---|
163 | template<class Y> void reset(Y * ptr){ |
---|
164 | // // if we already are pointing to sth, be sure to decrease its count |
---|
165 | // if (_ptr!=NULL) _decrease_count(); |
---|
166 | // |
---|
167 | // _ptr = new __SharedCountingPtr(ptr); |
---|
168 | SharedPtr(ptr).swap(*this); |
---|
169 | } |
---|
170 | |
---|
171 | // not part of the standard |
---|
172 | /// do a smart copy |
---|
173 | /// \param share : the object we want to copy |
---|
174 | /// Q? Do we need a non-template<Y> version as for the ctor and the assignment? |
---|
175 | template<class Y> void reset(SharedPtr<Y> const & share){ |
---|
176 | //void reset(SharedPtr const & share){ |
---|
177 | // if we already are pointing to sth, be sure to decrease its count |
---|
178 | if (_ptr!=NULL){ |
---|
179 | // in the specific case where we're having the same |
---|
180 | // share,reset() has actually no effect. However if *this is the |
---|
181 | // only instance still alive (implying share==*this) bringing |
---|
182 | // the count down to 0 and deleting the object will not have the |
---|
183 | // expected effect. So we just avoid that situation explicitly |
---|
184 | if (_ptr == share._get_container()) return; |
---|
185 | |
---|
186 | _decrease_count(); |
---|
187 | } |
---|
188 | |
---|
189 | // Watch out: if share is empty, construct an empty shared_ptr |
---|
190 | |
---|
191 | // copy the container |
---|
192 | _ptr = share._get_container(); // Note: automatically set it to NULL if share is empty |
---|
193 | |
---|
194 | if (_ptr!=NULL) ++(*_ptr); |
---|
195 | } |
---|
196 | |
---|
197 | /// overload the = operator so that it updates count |
---|
198 | /// \param share : the object we want to copy |
---|
199 | SharedPtr& operator=(SharedPtr const & share){ |
---|
200 | reset(share); |
---|
201 | return *this; |
---|
202 | } |
---|
203 | |
---|
204 | /// overload the = operator so that it updates count |
---|
205 | /// \param share : the object we want to copy |
---|
206 | template<class Y> SharedPtr& operator=(SharedPtr<Y> const & share){ |
---|
207 | reset(share); |
---|
208 | return *this; |
---|
209 | } |
---|
210 | |
---|
211 | /// return the pointer we're pointing to |
---|
212 | T* operator ()() const{ |
---|
213 | if (_ptr==NULL) return NULL; |
---|
214 | return _ptr->get(); // automatically returns NULL when out-of-scope |
---|
215 | } |
---|
216 | |
---|
217 | /// indirection, get a reference to the stored pointer |
---|
218 | /// |
---|
219 | /// !!! WATCH OUT |
---|
220 | /// It fails to check the requirement that the stored pointer must |
---|
221 | /// not be NULL!! So you need explicitly to check the validity in |
---|
222 | /// your code |
---|
223 | inline T& operator*() const{ |
---|
224 | return *(_ptr->get()); |
---|
225 | } |
---|
226 | |
---|
227 | /// indirection, get the stored pointer |
---|
228 | /// |
---|
229 | /// !!! WATCH OUT |
---|
230 | /// It fails to check the requirement that the stored pointer must |
---|
231 | /// not be NULL!! So you need explicitly to check the validity in |
---|
232 | /// your code |
---|
233 | inline T* operator->() const{ |
---|
234 | if (_ptr==NULL) return NULL; |
---|
235 | return _ptr->get(); |
---|
236 | } |
---|
237 | |
---|
238 | /// get the stored pointer |
---|
239 | inline T* get() const{ |
---|
240 | if (_ptr==NULL) return NULL; |
---|
241 | return _ptr->get(); |
---|
242 | } |
---|
243 | |
---|
244 | /// check if the instance is unique |
---|
245 | inline bool unique() const{ |
---|
246 | return (use_count()==1); |
---|
247 | } |
---|
248 | |
---|
249 | /// return the number of counts |
---|
250 | inline long use_count() const{ |
---|
251 | if (_ptr==NULL) return 0; |
---|
252 | return _ptr->use_count(); // automatically returns NULL when out-of-scope |
---|
253 | } |
---|
254 | |
---|
255 | /// conversion to bool |
---|
256 | /// This will allow you to use the indirection nicely |
---|
257 | inline operator bool() const{ |
---|
258 | return (get()!=NULL); |
---|
259 | } |
---|
260 | |
---|
261 | /// exchange the content of the two pointers |
---|
262 | inline void swap(SharedPtr & share){ |
---|
263 | __SharedCountingPtr* share_container = share._ptr; |
---|
264 | share._ptr = _ptr; |
---|
265 | _ptr = share_container; |
---|
266 | } |
---|
267 | |
---|
268 | /// force the count to be set to a specified value |
---|
269 | /// \param count the value that we need to reset to |
---|
270 | void set_count(const long & count){ |
---|
271 | if (_ptr==NULL) return; |
---|
272 | _ptr->set_count(count); |
---|
273 | } |
---|
274 | |
---|
275 | /** |
---|
276 | * \if internal_doc |
---|
277 | * \class __SharedCountingPtr |
---|
278 | * A reference-counting pointer |
---|
279 | * |
---|
280 | * This is implemented as a container for that pointer together with |
---|
281 | * reference counting. |
---|
282 | * The pointer is deleted when the number of counts goes to 0; |
---|
283 | * \endif |
---|
284 | */ |
---|
285 | class __SharedCountingPtr{ |
---|
286 | public: |
---|
287 | /// default ctor |
---|
288 | __SharedCountingPtr() : _ptr(NULL), _count(0){} |
---|
289 | |
---|
290 | /// ctor with initialisation |
---|
291 | template<class Y> explicit __SharedCountingPtr(Y* ptr) : _ptr(ptr), _count(1){} |
---|
292 | |
---|
293 | /// default dtor |
---|
294 | ~__SharedCountingPtr(){ |
---|
295 | // force the deletion of the object we keep track of |
---|
296 | if (_ptr!=NULL){ delete _ptr;} |
---|
297 | } |
---|
298 | |
---|
299 | /// return a pointer to the object |
---|
300 | inline T* get() const {return _ptr;} |
---|
301 | |
---|
302 | /// return the count |
---|
303 | inline long use_count() const {return _count;} |
---|
304 | |
---|
305 | /// prefix increment operator |
---|
306 | inline long operator++(){return ++_count;} |
---|
307 | |
---|
308 | /// prefix decrement operator |
---|
309 | inline long operator--(){return --_count;} |
---|
310 | |
---|
311 | /// postfix increment operator |
---|
312 | /// The "dummy" int argument is just a C++ trick to differentiate |
---|
313 | /// it from the prefix increment |
---|
314 | inline long operator++(int){return _count++;} |
---|
315 | |
---|
316 | /// postfix decrement operator |
---|
317 | /// The "dummy" int argument is just a C++ trick to differentiate |
---|
318 | /// it from the prefix decrement |
---|
319 | inline long operator--(int){return _count--;} |
---|
320 | |
---|
321 | /// force the count to be set to a specified value |
---|
322 | /// \param count the value that we ned to reset to |
---|
323 | void set_count(const long & count){ |
---|
324 | _count = count; |
---|
325 | } |
---|
326 | |
---|
327 | private: |
---|
328 | T *_ptr; ///< the pointer we're counting the references to |
---|
329 | long _count; ///< the number of references |
---|
330 | }; |
---|
331 | |
---|
332 | private: |
---|
333 | /// return the common container |
---|
334 | inline __SharedCountingPtr* _get_container() const{ |
---|
335 | return _ptr; |
---|
336 | } |
---|
337 | |
---|
338 | /// decrease the pointer count and support deletion |
---|
339 | /// Warning: we don't test that the pointer is allocated |
---|
340 | /// This can be dangerous if we have explicitly reset the |
---|
341 | /// count. Generally speaking, if the count goes negative |
---|
342 | /// after _ptr has been effectively deleted, this is going |
---|
343 | /// to lead to a segmentation fault. But, if in the course |
---|
344 | /// of the deletion of _ptr, the deletion of its pointer |
---|
345 | /// (_ptr::_ptr, i.e. the real data we're storing) makes |
---|
346 | /// the counts to become negative, this is going to pass |
---|
347 | /// smoothly. |
---|
348 | void _decrease_count(){ |
---|
349 | // decrease the count |
---|
350 | (*_ptr)--; |
---|
351 | |
---|
352 | // if no one else is using it, free the allocated memory |
---|
353 | if (_ptr->use_count()==0) |
---|
354 | delete _ptr; // that automatically deletes the object itself |
---|
355 | } |
---|
356 | |
---|
357 | // the real info |
---|
358 | __SharedCountingPtr *_ptr; |
---|
359 | }; |
---|
360 | |
---|
361 | |
---|
362 | /// comparison: equality |
---|
363 | template<class T,class U> |
---|
364 | inline bool operator==(SharedPtr<T> const & t, SharedPtr<U> const & u){ |
---|
365 | return t.get() == u.get(); |
---|
366 | } |
---|
367 | |
---|
368 | /// comparison: difference |
---|
369 | template<class T,class U> |
---|
370 | inline bool operator!=(SharedPtr<T> const & t, SharedPtr<U> const & u){ |
---|
371 | return t.get() != u.get(); |
---|
372 | } |
---|
373 | |
---|
374 | /// comparison: orgering |
---|
375 | template<class T,class U> |
---|
376 | inline bool operator<(SharedPtr<T> const & t, SharedPtr<U> const & u){ |
---|
377 | return t.get() < u.get(); |
---|
378 | } |
---|
379 | |
---|
380 | /// swapping |
---|
381 | template<class T> |
---|
382 | inline void swap(SharedPtr<T> & a, SharedPtr<T> & b){ |
---|
383 | return a.swap(b); |
---|
384 | } |
---|
385 | |
---|
386 | /// getting the pointer |
---|
387 | template<class T> |
---|
388 | inline T* get_pointer(SharedPtr<T> const & t){ |
---|
389 | return t.get(); |
---|
390 | } |
---|
391 | |
---|
392 | #endif // USETR1SHAREDPTR |
---|
393 | |
---|
394 | FASTJET_END_NAMESPACE // defined in fastjet/internal/base.hh |
---|
395 | |
---|
396 | #endif // __FASTJET_SHARED_PTR_HH__ |
---|