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