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 
27 namespace 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 
36 template <class T>
37 class Ptr
38 {
39 public:
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 
79 private:
80  T *ptr_;
81 };
82 
83 template <typename T>
84 inline Ptr<T> outArg(T &arg)
85 {
86  return Ptr<T>(&arg);
87 }
88 
93 template <typename T>
94 inline Ptr<T> ptrFromRef(T &arg)
95 {
96  return Ptr<T>(&arg);
97 }
98 
99 /* RCP */
100 
101 enum ENull { null };
102 
103 // RCP can be null. Functionally it should be equivalent to Teuchos::RCP.
104 
105 template <class T>
106 class RCP
107 {
108 public:
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 
206 private:
207  T *ptr_;
208 };
209 
210 template <class T>
211 inline RCP<T> rcp(T *p)
212 {
213  return RCP<T>(p);
214 }
215 
216 template <class T2, class T1>
217 inline 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 
224 template <class T2, class T1>
225 inline 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 
238 template <class T2, class T1>
239 inline 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 
246 template <class T>
247 inline bool operator==(const RCP<T> &p, ENull)
248 {
249  return p.get() == nullptr;
250 }
251 
252 template <typename T>
253 std::string typeName(const T &t)
254 {
255  return "RCP<>";
256 }
257 
258 void print_stack_on_segfault();
259 
260 #else
261 
262 using Teuchos::null;
263 using Teuchos::outArg;
264 using Teuchos::print_stack_on_segfault;
265 using Teuchos::Ptr;
266 using Teuchos::ptrFromRef;
267 using Teuchos::RCP;
268 using Teuchos::rcp;
269 using Teuchos::rcp_const_cast;
270 using Teuchos::rcp_dynamic_cast;
271 using Teuchos::rcp_static_cast;
272 using Teuchos::typeName;
273 
274 #endif
275 
276 template <class T>
278 {
279  // Public interface
280 public:
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
322 private:
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
339 public:
340  EnableRCPFromThis() : refcount_(0) {}
341 
342 private:
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 
366 template <typename T, typename... Args>
367 inline 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
T operator!=(T... args)
T swap(T... args)