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_PointerHash.h>
18 #include <SYS/SYS_Types.h>
19 #include <hboost/smart_ptr/intrusive_ptr.hpp> // IWYU pragma: export
20 
21 #include <memory> // for std::default_delete
22 
23 /// @brief Wrapper around hboost::intrusive_ptr
24 ///
25 /// An intrusive pointer assumes that the referenced object implements
26 /// reference counting on itself. The reference counting is implemented using
27 /// the methods @c intrusive_ptr_add_ref() and @c intrusive_ptr_release().
28 ///
29 /// For simple usages, simply derive from UT_IntrusiveRefCounter.
30 ///
31 /// Here's a roll your own example: @code
32 /// class Foo
33 /// {
34 /// public:
35 /// Foo() : myCount(0) {}
36 /// ~Foo() {}
37 /// void incref()
38 /// {
39 /// myCount.add(1);
40 /// }
41 /// void decref()
42 /// {
43 /// if (myCount.add(-1) == 0)
44 /// delete this;
45 /// }
46 /// SYS_AtomicInt32 myCount;
47 /// };
48 /// static inline void intrusive_ptr_add_ref(Foo *o) { o->incref(); }
49 /// static inline void intrusive_ptr_release(Foo *o) { o->decref(); }
50 ///
51 /// using FooHandle = UT_IntrusivePtr<Foo>;
52 /// @endcode
53 /// @see UT_SharedPtr
54 template<class T>
55 class UT_IntrusivePtr : public hboost::intrusive_ptr<T>
56 {
57 public:
59  UT_IntrusivePtr() noexcept
60  : hboost::intrusive_ptr<T>() {}
61 
62  // NOTE: This should really be explicit, but there are so many
63  // places currently implicitly casting to UT_IntrusivePtr that
64  // it could take quite a while to fix.
66  /*explicit*/ UT_IntrusivePtr(T *p)
67  : hboost::intrusive_ptr<T>(p, true) {}
68 
70  UT_IntrusivePtr(T *p, bool add_ref)
71  : hboost::intrusive_ptr<T>(p, add_ref) {}
72 
75  : hboost::intrusive_ptr<T>(p) {}
76 
77  template <typename Y>
80  : hboost::intrusive_ptr<T>(p) {}
81 
84  : hboost::intrusive_ptr<T>(std::move(p)) {}
85 
86  template <typename Y>
89  : hboost::intrusive_ptr<T>(std::move(p)) {}
90 
93  {
95  return *this;
96  }
97 
98  template <typename Y>
101  {
103  return *this;
104  }
105 
108  {
109  hboost::intrusive_ptr<T>::operator=(std::move(that));
110  return *this;
111  }
112 
113  template <typename Y>
116  {
117  hboost::intrusive_ptr<T>::operator=(std::move(that));
118  return *this;
119  }
120 };
121 
122 /// std::hash specialization for UT_IntrusivePtr<T>
123 namespace std
124 {
125  template <typename T>
126  struct hash<UT_IntrusivePtr<T>>
127  {
128  size_t operator()(const UT_IntrusivePtr<T> &p) const
129  {
130  return SYSpointerHash(p.get());
131  }
132  };
133 }
134 
135 /// Constructs an object of type T wrapped in a UT_IntrusivePtr
136 template <typename T, typename... ArgsT>
138 UTmakeIntrusive(ArgsT &&... args)
139 {
140  return UT_IntrusivePtr<T>(new T(std::forward<ArgsT>(args)...));
141 }
142 
143 /// Thread-safe policy for UT_IntrusiveRefCounter
145 {
147  using pod_type = uint32;
148 
150  static uint32 load(const type& counter) noexcept
151  {
152  return counter.relaxedLoad();
153  }
154 
156  static void increment(type& counter) noexcept
157  {
158  (void)counter.add(1);
159  }
161  static void increment(type& counter, pod_type refs_to_add) noexcept
162  {
163  (void)counter.add(refs_to_add);
164  }
165 
167  static uint32 decrement(type& counter) noexcept
168  {
169  return counter.add(-1);
170  }
172  static uint32 decrement(type& counter, pod_type refs_to_remove) noexcept
173  {
174  return counter.add(-int32(refs_to_remove));
175  }
176 
178  static bool conditionalIncrement(type& counter) noexcept
179  {
180  // This is the same idea as weak_ptr::lock(), where we only want to
181  // increment the reference count if it's non-zero.
182  // See <boost/smart_ptr/detail/sp_counted_base_std_atomic.hpp>
183  //
184  // Note that relaxed operations are acceptable here:
185  // https://en.cppreference.com/w/cpp/atomic/memory_order#Release-Acquire_ordering notes:
186  // - Typical use for relaxed memory ordering is incrementing
187  // counters, such as the reference counters of std::shared_ptr,
188  // since this only requires atomicity, but not ordering or
189  // synchronization (note that decrementing the shared_ptr counters
190  // requires acquire-release synchronization with the destructor)
191 
192  int32 r = counter.relaxedLoad();
193 
194  while (true)
195  {
196  if (r == 0)
197  return r;
198 
199  if (counter.compareExchangeWeak(
200  r, r + 1,
203  {
204  return r;
205  }
206  }
207  }
208 };
209 
210 /// NON Thread-safe policy for UT_IntrusiveRefCounter
212 {
213  using type = uint32;
214  using pod_type = uint32;
215 
217  static uint32 load(const type& counter) noexcept { return counter; }
218 
220  static void increment(type& counter) noexcept
221  {
222  ++counter;
223  }
225  static void increment(type& counter, pod_type refs_to_add) noexcept
226  {
227  counter += refs_to_add;
228  }
229 
231  static uint32 decrement(type& counter) noexcept
232  {
233  return (--counter);
234  }
236  static uint32 decrement(type& counter, pod_type refs_to_remove) noexcept
237  {
238  return (counter -= refs_to_remove);
239  }
240 
242  static bool conditionalIncrement(type& counter) noexcept
243  {
244  pod_type r = counter;
245  if (r != 0)
246  ++counter;
247 
248  return r != 0;
249  }
250 };
251 
252 // Forward declarations for friends.
253 template <
254  typename DerivedT,
255  typename Deleter = std::default_delete<DerivedT>,
256  typename CounterPolicyT = UT_IntrusiveThreadSafeCounterPolicy
257 >
259 
260 template <typename DerivedT, typename Deleter, typename CounterPolicyT>
263 
264 template <typename DerivedT, typename Deleter, typename CounterPolicyT>
267 
268 template <typename DerivedT, typename Deleter, typename CounterPolicyT>
271  typename CounterPolicyT::pod_type refs_to_add) noexcept;
272 
273 template <typename DerivedT, typename Deleter, typename CounterPolicyT>
276  typename CounterPolicyT::pod_type refs_to_remove) noexcept;
277 
278 /// @brief A reference counter base class for use with UT_IntrusivePtr
279 ///
280 /// This base class can be used with user-defined classes to add support for
281 /// @c UT_IntrusivePtr. The class contains a reference counter defined by the
282 /// @c CounterPolicyT. Upon releasing the last @c UT_IntrusivePtr referencing
283 /// the object derived from the @c UT_IntrusiveRefCounter class, operator
284 /// @c delete is automatically called on the pointer to the object.
285 ///
286 /// The other template parameter, @c DerivedT, is the user's class that
287 /// derives from @c UT_IntrusiveRefCounter.
288 ///
289 /// Example: @code
290 /// class MyClass : public UT_IntrusiveRefCounter<MyClass>
291 /// { ... };
292 /// using MyClassPtr = UT_IntrusivePtr<MyClass>;
293 /// @endcode
294 template <
295  typename DerivedT,
296  typename Deleter,
297  typename CounterPolicyT
298 >
300 {
301 public:
302  /// Default constructor: Sets counter to 0.
305  : myRefCount(0)
306  {
307  }
308  /// Copy constructor: Sets counter to 0.
311  : myRefCount(0)
312  {
313  }
314  /// Assignment operator: Does not modify counter.
316  {
317  return *this;
318  }
319  /// Return current counter
321  uint32 use_count() const noexcept
322  {
323  return CounterPolicyT::load(myRefCount);
324  }
325 
326  /// Adds a reference only if the reference count is not zero.
327  /// This can be used to implement an operation similar to weak_ptr::lock().
329  bool conditionalAddRef() noexcept
330  {
331  return CounterPolicyT::conditionalIncrement(myRefCount);
332  }
333 
334 protected:
335  /// Destructor: Only derived classes can destruct this.
338  {
339  }
340 
341 private:
342  mutable typename CounterPolicyT::type myRefCount;
343 
344  friend void intrusive_ptr_add_ref<DerivedT,Deleter,CounterPolicyT>(
346  ) noexcept;
347  friend void intrusive_ptr_release<DerivedT,Deleter,CounterPolicyT>(
349  ) noexcept;
350  friend void intrusive_ptr_add_ref<DerivedT,Deleter,CounterPolicyT>(
352  typename CounterPolicyT::pod_type refs_to_add) noexcept;
353  friend void intrusive_ptr_release<DerivedT,Deleter,CounterPolicyT>(
355  typename CounterPolicyT::pod_type refs_to_remove) noexcept;
356 
357 };
358 
359 template <typename DerivedT, typename Deleter, typename CounterPolicyT>
360 SYS_FORCE_INLINE void
363 {
364  CounterPolicyT::increment(p->myRefCount);
365 }
366 template <typename DerivedT, typename Deleter, typename CounterPolicyT>
367 SYS_FORCE_INLINE void
370 {
371  if (CounterPolicyT::decrement(p->myRefCount) == 0)
372  {
373  Deleter d;
374  d(SYSconst_cast(static_cast<const DerivedT *>(p)));
375  }
376 }
377 
378 template <typename DerivedT, typename Deleter, typename CounterPolicyT>
379 SYS_FORCE_INLINE void
382  typename CounterPolicyT::pod_type refs_to_add) noexcept
383 {
384  CounterPolicyT::increment(p->myRefCount, refs_to_add);
385 }
386 template <typename DerivedT, typename Deleter, typename CounterPolicyT>
387 SYS_FORCE_INLINE void
390  typename CounterPolicyT::pod_type refs_to_remove) noexcept
391 {
392  if (CounterPolicyT::decrement(p->myRefCount, refs_to_remove) == 0)
393  {
394  Deleter d;
395  d(SYSconst_cast(static_cast<const DerivedT *>(p)));
396  }
397 }
398 
399 // For UT::ArraySet.
400 namespace UT
401 {
402 template <typename T>
403 struct DefaultClearer;
404 
405 template <typename T>
407 {
408  static void clear(UT_IntrusivePtr<T> &v)
409  { v = UT_IntrusivePtr<T>(); }
410  static bool isClear(const UT_IntrusivePtr<T> &v)
411  { return v.get() == nullptr; }
413  { new ((void *)p) UT_IntrusivePtr<T>(nullptr); }
414  static const bool clearNeedsDestruction = false;
415 };
416 } // namespace UT
417 
418 #endif // __UT_INTRUSIVEPTR_H_INCLUDED__
type
Definition: core.h:556
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:96
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.
constexpr SYS_MemoryOrder SYS_MEMORY_ORDER_RELAXED
Any reordering the compiler or hardware chooses to do is okay.
SYS_FORCE_INLINE UT_IntrusivePtr< T > & operator=(UT_IntrusivePtr< Y > &&that)
static void clearConstruct(UT_IntrusivePtr< T > *p)
size_t operator()(const UT_IntrusivePtr< T > &p) const
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:618
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)
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