Line data Source code
1 : #ifndef CRPROPA_REFERENCED_H
2 : #define CRPROPA_REFERENCED_H
3 :
4 : #include <cstddef>
5 : #include <type_traits>
6 :
7 : #ifdef DEBUG
8 : #include <iostream>
9 : #include <typeinfo>
10 : #endif
11 :
12 : namespace crpropa {
13 : /**
14 : * \addtogroup Core
15 : * @{
16 : */
17 :
18 : /**
19 : @class Referenced
20 : @brief Base class for reference counting
21 :
22 : A form of memory management is needed to prevent memory leaks when using MPC in Python via SWIG.
23 : This base class enables reference counting.
24 : Every reference increases the reference counter, every dereference decreases it.
25 : When the counter is decreased to 0, the object is deleted.
26 : Candidate, Module, MagneticField and Source inherit from this class
27 : */
28 : class Referenced {
29 : public:
30 :
31 3377708 : constexpr Referenced() noexcept :
32 3377688 : _referenceCount(0) {
33 : }
34 :
35 0 : constexpr Referenced(const Referenced&) noexcept :
36 0 : _referenceCount(0) {
37 : }
38 :
39 : constexpr Referenced& operator =(const Referenced&) noexcept {
40 : return *this;
41 : }
42 :
43 : inline size_t addReference() const noexcept {
44 : int newRef;
45 : #if defined(OPENMP_3_1)
46 : #pragma omp atomic capture
47 : {newRef = _referenceCount++;}
48 : #elif defined(__GNUC__)
49 10945715 : newRef = __sync_add_and_fetch(&_referenceCount, 1);
50 : #else
51 : #pragma omp critical(newRef)
52 : {newRef = _referenceCount++;}
53 : #endif
54 7570701 : return newRef;
55 : }
56 :
57 : #ifdef DEBUG
58 : inline size_t removeReference() const {
59 : if (_referenceCount == 0)
60 : std::cerr
61 : << "WARNING: Remove reference from Object with NO references: "
62 : << typeid(*this).name() << std::endl;
63 : #else
64 10947383 : inline size_t removeReference() const noexcept {
65 : #endif
66 : int newRef;
67 : #if defined(OPENMP_3_1)
68 : #pragma omp atomic capture
69 : {newRef = _referenceCount--;}
70 : #elif defined(__GNUC__)
71 10947383 : newRef = __sync_sub_and_fetch(&_referenceCount, 1);
72 : #else
73 : #pragma omp critical(newRef)
74 : {newRef = _referenceCount--;}
75 : #endif
76 :
77 10947383 : if (newRef == 0) {
78 3375656 : delete this;
79 : }
80 10947383 : return newRef;
81 : }
82 :
83 : inline int removeReferenceNoDelete() const noexcept {
84 0 : return --_referenceCount;
85 : }
86 :
87 : inline size_t getReferenceCount() const noexcept {
88 0 : return _referenceCount;
89 : }
90 :
91 : protected:
92 :
93 0 : virtual inline ~Referenced() {
94 : #ifdef DEBUG
95 : if (_referenceCount)
96 : std::cerr << "WARNING: Deleting Object with references: "
97 : << typeid(*this).name() << std::endl;
98 : #endif
99 0 : }
100 :
101 : mutable size_t _referenceCount;
102 : };
103 :
104 : inline void intrusive_ptr_add_ref(Referenced* p) {
105 : p->addReference();
106 : }
107 : inline void intrusive_ptr_release(Referenced* p) {
108 0 : p->removeReference();
109 : }
110 :
111 : // helper Reference class functions, which function to use is decided at compile time!
112 : template<class T>
113 : typename std::enable_if_t<std::is_base_of<Referenced, T>::value>
114 : inline addReferenceIf(T* ptr) noexcept {
115 7570721 : if (ptr) ptr->addReference();
116 : }
117 : template<class T>
118 : typename std::enable_if_t<!std::is_base_of<Referenced, T>::value>
119 : inline addReferenceIf(T* ptr) noexcept {}
120 :
121 : template<class T>
122 : typename std::enable_if_t<std::is_base_of<Referenced, T>::value>
123 : inline removeReferenceIf(T* ptr) noexcept {
124 10905073 : if (ptr) ptr->removeReference();
125 : }
126 : template<class T>
127 : typename std::enable_if_t<!std::is_base_of<Referenced, T>::value>
128 : inline removeReferenceIf(T* ptr) noexcept {}
129 :
130 : template<class T>
131 : typename std::enable_if_t<std::is_base_of<Referenced, T>::value>
132 : inline removeReferenceNoDeleteIf(T* ptr) noexcept {
133 0 : if (ptr) ptr->removeReferenceNoDelete();
134 : }
135 : template<class T>
136 : typename std::enable_if_t<!std::is_base_of<Referenced, T>::value>
137 : inline removeReferenceNoDeleteIf(T* ptr) noexcept {}
138 :
139 : /**
140 : @class ref_ptr
141 : @brief Referenced pointer
142 :
143 : This class manages the memory of objects that inherit the class Referenced.
144 : Every other object is not managed but instead treated as raw pointer and should
145 : be managed by the original variable owner.
146 : */
147 : template<class T>
148 : class ref_ptr {
149 : public:
150 : typedef T element_type;
151 :
152 : /** Default Constructor */
153 305 : constexpr ref_ptr() noexcept : _ptr(0) {}
154 : #ifndef SWIG
155 : /** Constructor from reference
156 : * Use this constructor if you want to use a stack pointer,
157 : * so every pointer not created with a new operator.
158 : */
159 : inline ref_ptr(T& ref) noexcept : _ptr(&ref) {}
160 : #endif
161 : /** Constructor from pointer
162 : * Should not be used with stack pointer,
163 : * so every pointer not created with a new operator.
164 : */
165 3338561 : inline ref_ptr(T* ptr) noexcept : _ptr(ptr) {
166 : addReferenceIf(_ptr);
167 : }
168 : /** Constructor from ref_ptr with same template type */
169 7566034 : inline ref_ptr(const ref_ptr& rp) noexcept : _ptr(rp._ptr) {
170 : addReferenceIf(_ptr);
171 2 : }
172 : /** Constructor from ref_ptr with other template type, must be convertable */
173 4 : template<class Other> inline ref_ptr(const ref_ptr<Other>& rp) noexcept : _ptr(rp._ptr) {
174 : addReferenceIf(_ptr);
175 : }
176 :
177 : /** destructor */
178 : inline ~ref_ptr() noexcept {
179 7570480 : removeReferenceIf(_ptr);
180 : _ptr = 0;
181 6674290 : }
182 :
183 : /** Assign operator for ref_ptr with same template type */
184 : inline ref_ptr& operator =(const ref_ptr& rp) noexcept {
185 253 : assign(rp);
186 0 : return *this;
187 : }
188 : /** Assign operator for ref_ptr with other template type, must be convertable */
189 : template<class Other> inline ref_ptr& operator =(const ref_ptr<Other>& rp) noexcept {
190 : assign(rp);
191 : return *this;
192 : }
193 : /** Assign operator for pointer, do not assign stack pointer */
194 158 : inline ref_ptr& operator =(T* ptr) noexcept {
195 397 : if (_ptr != ptr) {
196 : T* tmp_ptr = _ptr;
197 158 : _ptr = ptr;
198 : addReferenceIf(_ptr);
199 : removeReferenceIf(tmp_ptr);
200 : }
201 158 : return *this;
202 : }
203 : #ifndef SWIG
204 : /** Assign operator for stack references */
205 : inline ref_ptr& operator =(T& ref) noexcept {
206 : if (_ptr != &ref)
207 : _ptr = &ref;
208 : return *this;
209 : }
210 : #endif
211 :
212 : inline operator T*() const noexcept {
213 481152 : return _ptr;
214 : }
215 :
216 : inline T& operator*() const noexcept {
217 6484 : return *_ptr;
218 : }
219 : inline T* operator->() const noexcept {
220 6174249 : return _ptr;
221 : }
222 : inline T* get() const {
223 37 : return _ptr;
224 : }
225 :
226 : inline bool operator!() const noexcept {
227 0 : return _ptr == 0;
228 : } // not required
229 : inline bool valid() const noexcept {
230 5881542 : return _ptr != 0;
231 : }
232 :
233 : inline T* release() noexcept {
234 0 : T* tmp = _ptr;
235 : removeReferenceNoDeleteIf(_ptr);
236 0 : _ptr = 0;
237 : return tmp;
238 : }
239 :
240 : inline void swap(ref_ptr& rp) noexcept {
241 0 : T* tmp = _ptr;
242 0 : _ptr = rp._ptr;
243 0 : rp._ptr = tmp;
244 : }
245 :
246 : private:
247 :
248 1354 : template<class Other> inline void assign(const ref_ptr<Other>& rp) noexcept {
249 1354 : if (_ptr != rp._ptr) {
250 : T* tmp_ptr = _ptr;
251 1328 : _ptr = rp._ptr;
252 : addReferenceIf(_ptr);
253 : removeReferenceIf(tmp_ptr);
254 : }
255 1354 : }
256 :
257 : template<class Other> friend class ref_ptr;
258 :
259 : T* _ptr;
260 : };
261 :
262 : template<class T> inline
263 : void swap(ref_ptr<T>& rp1, ref_ptr<T>& rp2) {
264 : rp1.swap(rp2);
265 : }
266 :
267 : template<class T> inline T* get_pointer(const ref_ptr<T>& rp) {
268 : return rp.get();
269 : }
270 :
271 : template<class T, class Y> inline ref_ptr<T> static_pointer_cast(
272 : const ref_ptr<Y>& rp) {
273 : return static_cast<T*>(rp.get());
274 : }
275 :
276 : template<class T, class Y> inline ref_ptr<T> dynamic_pointer_cast(
277 : const ref_ptr<Y>& rp) {
278 : return dynamic_cast<T*>(rp.get());
279 : }
280 :
281 : template<class T, class Y> inline ref_ptr<T> const_pointer_cast(
282 : const ref_ptr<Y>& rp) {
283 : return const_cast<T*>(rp.get());
284 : }
285 :
286 : /** @}*/
287 : } // namespace crpropa
288 :
289 : #endif // CRPROPA_REFERENCED_H
|