Loading...
Searching...
No Matches
symengine_rcp.h
1#ifndef SYMENGINE_RCP_H
2#define SYMENGINE_RCP_H
3
4#include <iostream>
5#include <cstddef>
6#include <stdexcept>
7#include <string>
8#include <ciso646>
9
10#include <symengine/symengine_config.h>
11#include <symengine/symengine_assert.h>
12
13#if defined(WITH_SYMENGINE_RCP)
14
15#if defined(WITH_SYMENGINE_THREAD_SAFE)
16#include <atomic>
17#endif
18
19#else
20
21// Include all Teuchos headers here:
22#include <symengine/utilities/teuchos/Teuchos_RCP.hpp>
23#include <symengine/utilities/teuchos/Teuchos_TypeNameTraits.hpp>
24
25#endif
26
27namespace SymEngine
28{
29
30#if defined(WITH_SYMENGINE_RCP)
31
32/* Ptr */
33
34// Ptr is always pointing to a valid object (can never be nullptr).
35
36template <class T>
37class Ptr
38{
39public:
40 inline explicit Ptr(T *ptr) : ptr_(ptr)
41 {
42 SYMENGINE_ASSERT(ptr_ != nullptr)
43 }
44 inline Ptr(const Ptr<T> &ptr) : ptr_(ptr.ptr_) {}
45 template <class T2>
46 inline Ptr(const Ptr<T2> &ptr) : ptr_(ptr.get())
47 {
48 }
49 Ptr<T> &operator=(const Ptr<T> &ptr)
50 {
51 ptr_ = ptr.get();
52 return *this;
53 }
54#if defined(HAVE_DEFAULT_CONSTRUCTORS)
55 inline Ptr(Ptr &&) = default;
56 Ptr<T> &operator=(Ptr &&) = default;
57#endif
58 inline T *operator->() const
59 {
60 return ptr_;
61 }
62 inline T &operator*() const
63 {
64 return *ptr_;
65 }
66 inline T *get() const
67 {
68 return ptr_;
69 }
70 inline T *getRawPtr() const
71 {
72 return get();
73 }
74 inline const Ptr<T> ptr() const
75 {
76 return *this;
77 }
78
79private:
80 T *ptr_;
81};
82
83template <typename T>
84inline Ptr<T> outArg(T &arg)
85{
86 return Ptr<T>(&arg);
87}
88
93template <typename T>
94inline Ptr<T> ptrFromRef(T &arg)
95{
96 return Ptr<T>(&arg);
97}
98
99/* RCP */
100
101enum ENull { null };
102
103// RCP can be null. Functionally it should be equivalent to Teuchos::RCP.
104
105template <class T>
106class RCP
107{
108public:
109 RCP(ENull null_arg = null) : ptr_(nullptr) {}
110 explicit RCP(T *p) : ptr_(p)
111 {
112 SYMENGINE_ASSERT(ptr_ != nullptr)
113 (ptr_->refcount_)++;
114 }
115 // Copy constructor
116 RCP(const RCP<T> &rp) : ptr_(rp.ptr_)
117 {
118 if (not is_null())
119 (ptr_->refcount_)++;
120 }
121 // Copy constructor
122 template <class T2>
123 RCP(const RCP<T2> &r_ptr) : ptr_(r_ptr.get())
124 {
125 if (not is_null())
126 (ptr_->refcount_)++;
127 }
128 // Move constructor
129 RCP(RCP<T> &&rp) SYMENGINE_NOEXCEPT : ptr_(rp.ptr_)
130 {
131 rp.ptr_ = nullptr;
132 }
133 // Move constructor
134 template <class T2>
135 RCP(RCP<T2> &&r_ptr)
136 SYMENGINE_NOEXCEPT : ptr_(r_ptr.get())
137 {
138 r_ptr._set_null();
139 }
140 ~RCP() SYMENGINE_NOEXCEPT
141 {
142 if (ptr_ != nullptr and --(ptr_->refcount_) == 0)
143 delete ptr_;
144 }
145 T *operator->() const
146 {
147 SYMENGINE_ASSERT(ptr_ != nullptr)
148 return ptr_;
149 }
150 T &operator*() const
151 {
152 SYMENGINE_ASSERT(ptr_ != nullptr)
153 return *ptr_;
154 }
155 T *get() const
156 {
157 return ptr_;
158 }
159 Ptr<T> ptr() const
160 {
161 return Ptr<T>(get());
162 }
163 bool is_null() const
164 {
165 return ptr_ == nullptr;
166 }
167 template <class T2>
168 bool operator==(const RCP<T2> &p2) const
169 {
170 return ptr_ == p2.ptr_;
171 }
172 template <class T2>
173 bool operator!=(const RCP<T2> &p2) const
174 {
175 return ptr_ != p2.ptr_;
176 }
177 // Copy assignment
178 RCP<T> &operator=(const RCP<T> &r_ptr)
179 {
180 T *r_ptr_ptr_ = r_ptr.ptr_;
181 if (not r_ptr.is_null())
182 (r_ptr_ptr_->refcount_)++;
183 if (not is_null() and --(ptr_->refcount_) == 0)
184 delete ptr_;
185 ptr_ = r_ptr_ptr_;
186 return *this;
187 }
188 // Move assignment
189 RCP<T> &operator=(RCP<T> &&r_ptr)
190 {
191 std::swap(ptr_, r_ptr.ptr_);
192 return *this;
193 }
194 void reset()
195 {
196 if (not is_null() and --(ptr_->refcount_) == 0)
197 delete ptr_;
198 ptr_ = nullptr;
199 }
200 // Don't use this function directly:
201 void _set_null()
202 {
203 ptr_ = nullptr;
204 }
205
206private:
207 T *ptr_;
208};
209
210template <class T>
211inline RCP<T> rcp(T *p)
212{
213 return RCP<T>(p);
214}
215
216template <class T2, class T1>
217inline RCP<T2> rcp_static_cast(const RCP<T1> &p1)
218{
219 // Make the compiler check if the conversion is legal
220 T2 *check = static_cast<T2 *>(p1.get());
221 return RCP<T2>(check);
222}
223
224template <class T2, class T1>
225inline RCP<T2> rcp_dynamic_cast(const RCP<T1> &p1)
226{
227 if (not p1.is_null()) {
228 T2 *p = nullptr;
229 // Make the compiler check if the conversion is legal
230 p = dynamic_cast<T2 *>(p1.get());
231 if (p) {
232 return RCP<T2>(p);
233 }
234 }
235 throw std::runtime_error("rcp_dynamic_cast: cannot convert.");
236}
237
238template <class T2, class T1>
239inline RCP<T2> rcp_const_cast(const RCP<T1> &p1)
240{
241 // Make the compiler check if the conversion is legal
242 T2 *check = const_cast<T2 *>(p1.get());
243 return RCP<T2>(check);
244}
245
246template <class T>
247inline bool operator==(const RCP<T> &p, ENull)
248{
249 return p.get() == nullptr;
250}
251
252template <typename T>
253std::string typeName(const T &t)
254{
255 return "RCP<>";
256}
257
258void print_stack_on_segfault();
259
260#else
261
262using Teuchos::null;
263using Teuchos::outArg;
264using Teuchos::print_stack_on_segfault;
265using Teuchos::Ptr;
266using Teuchos::ptrFromRef;
267using Teuchos::RCP;
268using Teuchos::rcp;
269using Teuchos::rcp_const_cast;
270using Teuchos::rcp_dynamic_cast;
271using Teuchos::rcp_static_cast;
272using Teuchos::typeName;
273
274#endif
275
276template <class T>
278{
279 // Public interface
280public:
282 inline RCP<T> rcp_from_this()
283 {
284#if defined(WITH_SYMENGINE_RCP)
285 return rcp(static_cast<T *>(this));
286#else
287 return rcp_static_cast<T>(weak_self_ptr_.create_strong());
288#endif
289 }
290
292 inline RCP<const T> rcp_from_this() const
293 {
294#if defined(WITH_SYMENGINE_RCP)
295 return rcp(static_cast<const T *>(this));
296#else
297 return rcp_static_cast<const T>(weak_self_ptr_.create_strong());
298#endif
299 }
300
302 template <class T2>
303 inline RCP<const T2> rcp_from_this_cast() const
304 {
305#if defined(WITH_SYMENGINE_RCP)
306 return rcp(static_cast<const T2 *>(this));
307#else
308 return rcp_static_cast<const T2>(weak_self_ptr_.create_strong());
309#endif
310 }
311
312 unsigned int use_count() const
313 {
314#if defined(WITH_SYMENGINE_RCP)
315 return refcount_;
316#else
317 return weak_self_ptr_.strong_count();
318#endif
319 }
320
321 // Everything below is private interface
322private:
323#if defined(WITH_SYMENGINE_RCP)
324
326// The reference counter is defined either as "unsigned int" (faster, but
327// not thread safe) or as std::atomic<unsigned int> (slower, but thread
328// safe). Semantically they are almost equivalent, except that the
329// pre-decrement operator `operator--()` returns a copy for std::atomic
330// instead of a reference to itself.
331// The refcount_ is defined as mutable, because it does not change the
332// state of the instance, but changes when more copies
333// of the same instance are made.
334#if defined(WITH_SYMENGINE_THREAD_SAFE)
335 mutable std::atomic<unsigned int> refcount_; // reference counter
336#else
337 mutable unsigned int refcount_; // reference counter
338#endif // WITH_SYMENGINE_THREAD_SAFE
339public:
340 EnableRCPFromThis() : refcount_(0) {}
341
342private:
343#else
344 mutable RCP<T> weak_self_ptr_;
345
346 void set_weak_self_ptr(const RCP<T> &w)
347 {
348 weak_self_ptr_ = w;
349 }
350
351 void set_weak_self_ptr(const RCP<const T> &w) const
352 {
353 weak_self_ptr_ = rcp_const_cast<T>(w);
354 }
355#endif // WITH_SYMENGINE_RCP
356
357#if defined(WITH_SYMENGINE_RCP)
358 template <class T_>
359 friend class RCP;
360#endif
361
362 template <typename T_, typename... Args>
363 friend inline RCP<T_> make_rcp(Args &&...args);
364};
365
366template <typename T, typename... Args>
367inline RCP<T> make_rcp(Args &&...args)
368{
369#if defined(WITH_SYMENGINE_RCP)
370 return rcp(new T(std::forward<Args>(args)...));
371#else
372 RCP<T> p = rcp(new T(std::forward<Args>(args)...));
373 p->set_weak_self_ptr(p.create_weak());
374 return p;
375#endif
376}
377
378} // namespace SymEngine
379
380#endif
RCP< const T2 > rcp_from_this_cast() const
Get RCP<T2> pointer to self (it will cast the pointer to T2)
RCP< T > rcp_from_this()
Get RCP<T> pointer to self (it will cast the pointer to T)
RCP< const T > rcp_from_this() const
Get RCP<const T> pointer to self (it will cast the pointer to const T)
Main namespace for SymEngine package.
Definition add.cpp:19
void hash_combine(hash_t &seed, const T &v)
Definition basic-inl.h:95
T operator!=(T... args)
T swap(T... args)