HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_IntrusivePtr.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: UT_IntrusivePtr.h (UT Library, C++)
7  *
8  * COMMENTS: A wrapper around hboost::intrusive_ptr.
9  *
10  */
11 
12 #ifndef __UT_INTRUSIVEPTR_H_INCLUDED__
13 #define __UT_INTRUSIVEPTR_H_INCLUDED__
14 
15 #include <SYS/SYS_AtomicInt.h>
16 #include <SYS/SYS_Inline.h>
17 #include <SYS/SYS_Types.h>
18 #include <memory> // For std::default_delete
19 #include <hboost/intrusive_ptr.hpp>
20 
21 /// @brief Wrapper around hboost::intrusive_ptr
22 ///
23 /// An intrusive pointer assumes that the referenced object implements
24 /// reference counting on itself. The reference counting is implemented using
25 /// the methods @c intrusive_ptr_add_ref() and @c intrusive_ptr_release().
26 ///
27 /// For simple usages, simply derive from UT_IntrusiveRefCounter.
28 ///
29 /// Here's a roll your own example: @code
30 /// class Foo {
31 /// public:
32 /// Foo() : myCount(0) {}
33 /// ~Foo() {}
34 /// void incref()
35 /// {
36 /// myCount.add(1);
37 /// }
38 /// void decref()
39 /// {
40 /// if (myCount.add(-1) == 0)
41 /// delete this;
42 /// }
43 /// SYS_AtomicInt32 myCount;
44 /// };
45 /// static inline void intrusive_ptr_add_ref(Foo *o) { o->incref(); }
46 /// static inline void intrusive_ptr_release(Foo *o) { o->decref(); }
47 ///
48 /// using FooHandle = UT_IntrusivePtr<Foo>;
49 /// @endcode
50 /// @see UT_SharedPtr
51 template<class T>
52 class UT_IntrusivePtr : public hboost::intrusive_ptr<T>
53 {
54 public:
56  UT_IntrusivePtr() noexcept
57  : hboost::intrusive_ptr<T>() {}
58 
59  // NOTE: This should really be explicit, but there are so many
60  // places currently implicitly casting to UT_IntrusivePtr that
61  // it could take quite a while to fix.
63  /*explicit*/ UT_IntrusivePtr(T *p)
64  : hboost::intrusive_ptr<T>(p, true) {}
65 
67  UT_IntrusivePtr(T *p, bool add_ref)
68  : hboost::intrusive_ptr<T>(p, add_ref) {}
69 
72  : hboost::intrusive_ptr<T>(p) {}
73 
74  template <typename Y>
77  : hboost::intrusive_ptr<T>(p) {}
78 
81  : hboost::intrusive_ptr<T>(std::move(p)) {}
82 
83  template <typename Y>
86  : hboost::intrusive_ptr<T>(std::move(p)) {}
87 
90  {
92  return *this;
93  }
94 
95  template <typename Y>
98  {
100  return *this;
101  }
102 
105  {
106  hboost::intrusive_ptr<T>::operator=(std::move(that));
107  return *this;
108  }
109 
110  template <typename Y>
113  {
114  hboost::intrusive_ptr<T>::operator=(std::move(that));
115  return *this;
116  }
117 };
118 
119 /// Constructs an object of type T wrapped in a UT_IntrusivePtr
120 template <typename T, typename... ArgsT>
122 UTmakeIntrusive(ArgsT &&... args)
123 {
124  return UT_IntrusivePtr<T>(new T(std::forward<ArgsT>(args)...));
125 }
126 
127 /// Thread-safe policy for UT_IntrusiveRefCounter
129 {
131  using pod_type = uint32;
132 
134  static uint32 load(const type& counter) noexcept
135  {
136  return counter.relaxedLoad();
137  }
138 
140  static void increment(type& counter) noexcept
141  {
142  (void)counter.add(1);
143  }
145  static void increment(type& counter, pod_type refs_to_add) noexcept
146  {
147  (void)counter.add(refs_to_add);
148  }
149 
151  static uint32 decrement(type& counter) noexcept
152  {
153  return counter.add(-1);
154  }
156  static uint32 decrement(type& counter, pod_type refs_to_remove) noexcept
157  {
158  return counter.add(-int32(refs_to_remove));
159  }
160 
162  static bool conditionalIncrement(type& counter) noexcept
163  {
164  // This is the same idea as weak_ptr::lock(), where we only want to
165  // increment the reference count if it's non-zero.
166  // See <boost/smart_ptr/detail/sp_counted_base_std_atomic.hpp>
167  //
168  // Note that relaxed operations are acceptable here:
169  // https://en.cppreference.com/w/cpp/atomic/memory_order#Release-Acquire_ordering notes:
170  // - Typical use for relaxed memory ordering is incrementing
171  // counters, such as the reference counters of std::shared_ptr,
172  // since this only requires atomicity, but not ordering or
173  // synchronization (note that decrementing the shared_ptr counters
174  // requires acquire-release synchronization with the destructor)
175 
176  int32 r = counter.relaxedLoad();
177 
178  while (true)
179  {
180  if (r == 0)
181  return r;
182 
183  if (counter.compareExchangeWeak(
184  r, r + 1,
187  {
188  return r;
189  }
190  }
191  }
192 };
193 
194 /// NON Thread-safe policy for UT_IntrusiveRefCounter
196 {
197  using type = uint32;
198  using pod_type = uint32;
199 
201  static uint32 load(const type& counter) noexcept { return counter; }
202 
204  static void increment(type& counter) noexcept
205  {
206  ++counter;
207  }
209  static void increment(type& counter, pod_type refs_to_add) noexcept
210  {
211  counter += refs_to_add;
212  }
213 
215  static uint32 decrement(type& counter) noexcept
216  {
217  return (--counter);
218  }
220  static uint32 decrement(type& counter, pod_type refs_to_remove) noexcept
221  {
222  return (counter -= refs_to_remove);
223  }
224 
226  static bool conditionalIncrement(type& counter) noexcept
227  {
228  pod_type r = counter;
229  if (r != 0)
230  ++counter;
231 
232  return r != 0;
233  }
234 };
235 
236 // Forward declarations for friends.
237 template <
238  typename DerivedT,
239  typename Deleter = std::default_delete<DerivedT>,
240  typename CounterPolicyT = UT_IntrusiveThreadSafeCounterPolicy
241 >
243 
244 template <typename DerivedT, typename Deleter, typename CounterPolicyT>
247 
248 template <typename DerivedT, typename Deleter, typename CounterPolicyT>
251 
252 template <typename DerivedT, typename Deleter, typename CounterPolicyT>
255  typename CounterPolicyT::pod_type refs_to_add) noexcept;
256 
257 template <typename DerivedT, typename Deleter, typename CounterPolicyT>
260  typename CounterPolicyT::pod_type refs_to_remove) noexcept;
261 
262 /// @brief A reference counter base class for use with UT_IntrusivePtr
263 ///
264 /// This base class can be used with user-defined classes to add support for
265 /// @c UT_IntrusivePtr. The class contains a reference counter defined by the
266 /// @c CounterPolicyT. Upon releasing the last @c UT_IntrusivePtr referencing
267 /// the object derived from the @c UT_IntrusiveRefCounter class, operator
268 /// @c delete is automatically called on the pointer to the object.
269 ///
270 /// The other template parameter, @c DerivedT, is the user's class that
271 /// derives from @c UT_IntrusiveRefCounter.
272 ///
273 /// Example: @code
274 /// class MyClass : public UT_IntrusiveRefCounter<MyClass>
275 /// { ... };
276 /// using MyClassPtr = UT_IntrusivePtr<MyClass>;
277 /// @endcode
278 template <
279  typename DerivedT,
280  typename Deleter,
281  typename CounterPolicyT
282 >
284 {
285 public:
286  /// Default constructor: Sets counter to 0.
289  : myRefCount(0)
290  {
291  }
292  /// Copy constructor: Sets counter to 0.
295  : myRefCount(0)
296  {
297  }
298  /// Assignment operator: Does not modify counter.
300  {
301  return *this;
302  }
303  /// Return current counter
305  uint32 use_count() const noexcept
306  {
307  return CounterPolicyT::load(myRefCount);
308  }
309 
310  /// Adds a reference only if the reference count is not zero.
311  /// This can be used to implement an operation similar to weak_ptr::lock().
313  bool conditionalAddRef() noexcept
314  {
315  return CounterPolicyT::conditionalIncrement(myRefCount);
316  }
317 
318 protected:
319  /// Destructor: Only derived classes can destruct this.
322  {
323  }
324 
325 private:
326  mutable typename CounterPolicyT::type myRefCount;
327 
328  friend void intrusive_ptr_add_ref<DerivedT,Deleter,CounterPolicyT>(
330  ) noexcept;
331  friend void intrusive_ptr_release<DerivedT,Deleter,CounterPolicyT>(
333  ) noexcept;
334  friend void intrusive_ptr_add_ref<DerivedT,Deleter,CounterPolicyT>(
336  typename CounterPolicyT::pod_type refs_to_add) noexcept;
337  friend void intrusive_ptr_release<DerivedT,Deleter,CounterPolicyT>(
339  typename CounterPolicyT::pod_type refs_to_remove) noexcept;
340 
341 };
342 
343 template <typename DerivedT, typename Deleter, typename CounterPolicyT>
344 SYS_FORCE_INLINE void
347 {
348  CounterPolicyT::increment(p->myRefCount);
349 }
350 template <typename DerivedT, typename Deleter, typename CounterPolicyT>
351 SYS_FORCE_INLINE void
354 {
355  if (CounterPolicyT::decrement(p->myRefCount) == 0)
356  {
357  Deleter d;
358  d(SYSconst_cast(static_cast<const DerivedT *>(p)));
359  }
360 }
361 
362 template <typename DerivedT, typename Deleter, typename CounterPolicyT>
363 SYS_FORCE_INLINE void
366  typename CounterPolicyT::pod_type refs_to_add) noexcept
367 {
368  CounterPolicyT::increment(p->myRefCount, refs_to_add);
369 }
370 template <typename DerivedT, typename Deleter, typename CounterPolicyT>
371 SYS_FORCE_INLINE void
374  typename CounterPolicyT::pod_type refs_to_remove) noexcept
375 {
376  if (CounterPolicyT::decrement(p->myRefCount, refs_to_remove) == 0)
377  {
378  Deleter d;
379  d(SYSconst_cast(static_cast<const DerivedT *>(p)));
380  }
381 }
382 
383 // For UT::ArraySet.
384 namespace UT
385 {
386 template <typename T>
387 struct DefaultClearer;
388 
389 template <typename T>
391 {
392  static void clear(UT_IntrusivePtr<T> &v)
393  { v = UT_IntrusivePtr<T>(); }
394  static bool isClear(const UT_IntrusivePtr<T> &v)
395  { return v.get() == nullptr; }
397  { new ((void *)p) UT_IntrusivePtr<T>(nullptr); }
398  static const bool clearNeedsDestruction = false;
399 };
400 } // namespace UT
401 
402 #endif // __UT_INTRUSIVEPTR_H_INCLUDED__
SYS_FORCE_INLINE UT_IntrusivePtr(T *p, bool add_ref)
SYS_FORCE_INLINE bool conditionalAddRef() noexcept
int int32
Definition: SYS_Types.h:39
static SYS_FORCE_INLINE void increment(type &counter, pod_type refs_to_add) noexcept
static SYS_FORCE_INLINE void increment(type &counter, pod_type refs_to_add) noexcept
SYS_FORCE_INLINE UT_IntrusivePtr() noexcept
void
Definition: png.h:1083
const GLdouble * v
Definition: glcorearb.h:837
void intrusive_ptr_release(const UT_IntrusiveRefCounter< DerivedT, Deleter, CounterPolicyT > *p) noexcept
static SYS_FORCE_INLINE void increment(type &counter) noexcept
UT_IntrusivePtr< T > UTmakeIntrusive(ArgsT &&...args)
Constructs an object of type T wrapped in a UT_IntrusivePtr.
SYS_FORCE_INLINE UT_IntrusivePtr(T *p)
SYS_FORCE_INLINE T * SYSconst_cast(const T *foo)
Definition: SYS_Types.h:136
SYS_AtomicInt< int32 > SYS_AtomicInt32
Definition: SYS_AtomicInt.h:95
static SYS_FORCE_INLINE bool conditionalIncrement(type &counter) noexcept
SYS_FORCE_INLINE UT_IntrusivePtr(const UT_IntrusivePtr< Y > &p)
A reference counter base class for use with UT_IntrusivePtr.
void intrusive_ptr_add_ref(const UT_IntrusiveRefCounter< DerivedT, Deleter, CounterPolicyT > *p) noexcept
NON Thread-safe policy for UT_IntrusiveRefCounter.
UT_IntrusiveRefCounter & operator=(const UT_IntrusiveRefCounter &) noexcept
Assignment operator: Does not modify counter.
static bool isClear(const UT_IntrusivePtr< T > &v)
SYS_FORCE_INLINE uint32 use_count() const noexcept
Return current counter.
#define SYS_FORCE_INLINE
Definition: SYS_Inline.h:45
SYS_FORCE_INLINE UT_IntrusivePtr< T > & operator=(UT_IntrusivePtr< T > &&that)
SYS_FORCE_INLINE UT_IntrusivePtr< T > & operator=(const UT_IntrusivePtr< T > &that)
Wrapper around hboost::intrusive_ptr.
SYS_FORCE_INLINE UT_IntrusivePtr(const UT_IntrusivePtr< T > &p)
SYS_FORCE_INLINE UT_IntrusiveRefCounter(const UT_IntrusiveRefCounter &) noexcept
Copy constructor: Sets counter to 0.
SYS_FORCE_INLINE UT_IntrusivePtr< T > & operator=(UT_IntrusivePtr< Y > &&that)
Any reordering the compiler or hardware chooses to do is okay.
static void clearConstruct(UT_IntrusivePtr< T > *p)
static SYS_FORCE_INLINE uint32 decrement(type &counter, pod_type refs_to_remove) noexcept
static void clear(UT_IntrusivePtr< T > &v)
SYS_FORCE_INLINE UT_IntrusivePtr(UT_IntrusivePtr< T > &&p)
static SYS_FORCE_INLINE bool conditionalIncrement(type &counter) noexcept
static SYS_FORCE_INLINE uint32 decrement(type &counter, pod_type refs_to_remove) noexcept
LeafData & operator=(const LeafData &)=delete
static SYS_FORCE_INLINE uint32 decrement(type &counter) noexcept
static SYS_FORCE_INLINE uint32 load(const type &counter) noexcept
**If you just want to fire and args
Definition: thread.h:609
unsigned int uint32
Definition: SYS_Types.h:40
SYS_FORCE_INLINE ~UT_IntrusiveRefCounter()
Destructor: Only derived classes can destruct this.
GLboolean r
Definition: glcorearb.h:1222
SYS_FORCE_INLINE UT_IntrusivePtr< T > & operator=(const UT_IntrusivePtr< Y > &that)
SYS_FORCE_INLINE UT_IntrusiveRefCounter() noexcept
Default constructor: Sets counter to 0.
static SYS_FORCE_INLINE uint32 decrement(type &counter) noexcept
SYS_FORCE_INLINE UT_IntrusivePtr(UT_IntrusivePtr< Y > &&p)
type
Definition: core.h:1059
static SYS_FORCE_INLINE uint32 load(const type &counter) noexcept
Thread-safe policy for UT_IntrusiveRefCounter.
static SYS_FORCE_INLINE void increment(type &counter) noexcept
A simple intrusive pointer, modeled after std::shared_ptr.
Definition: refcnt.h:28