HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
delegatedCountPtr.h
Go to the documentation of this file.
1 //
2 // Copyright 2024 Pixar
3 //
4 // Licensed under the terms set forth in the LICENSE.txt file available at
5 // https://openusd.org/license.
6 //
7 
8 #ifndef PXR_BASE_TF_DELEGATED_COUNT_PTR_H
9 #define PXR_BASE_TF_DELEGATED_COUNT_PTR_H
10 
11 #include "pxr/pxr.h"
12 #include "pxr/base/tf/tf.h"
13 #include "pxr/base/tf/api.h"
14 
16 
17 #include <memory>
18 #include <type_traits>
19 #include <utility>
20 
22 
23 /// When constructing a `TfDelegatedCountPtr` from a raw pointer, use the
24 /// `TfDelegatedCountIncrementTag` to explicitly signal that the pointer's
25 /// delegated count should be incremented on construction. This is the most
26 /// common tag.
29 
30 /// When constructing a `TfDelegatedCountPtr` from a raw pointer, use the
31 /// `TfDelegatedCountDoNotIncrementTag` to avoid incrementing the delegated
32 /// count on construction. This must be carefully used to avoid memory errors.
35 
36 /// Stores a pointer to a `ValueType` which uses `TfDelegatedCountIncrement` and
37 /// `TfDelegatedCountDecrement` to bookkeep. This class is most useful to adapt
38 /// existing types that have their own bespoke reference counting logic to a
39 /// common C++-style "smart pointer" interface.
40 ///
41 /// The `TfDelegatedCountPtr` calls `TfDelegatedCountIncrement` and
42 /// `TfDelegatedCountDecrement` as needed in construction, assignment, and
43 /// destruction operations. These functions are expected to be provided by
44 /// client code to do the specific resource management related to the pointed-to
45 /// object. These functions must have the following signatures:
46 ///
47 /// \code
48 /// void TfDelegatedCountIncrement(MyObject *obj);
49 /// void TfDelegatedCountDecrement(MyObject *obj);
50 /// \endcode
51 ///
52 /// For example if `MyObject` has a reference count member variable, the
53 /// overload `TfDelegatedCountIncrement(MyObject *obj)` could simply increment
54 /// that count. The `TfDelegatedCountDecrement(MyObject *obj)` might decrement
55 /// the count and check to see if it has gone to zero. If so, it can clean up
56 /// resources related to the object such as deleting it or freeing memory.
57 ///
58 /// These increment and decrement functions are never passed null pointers.
59 ///
60 /// A `TfDelegatedCountPtr` can be created by construction with a raw pointer,
61 /// or by `TfMakeDelegatedCountPtr` to create and manage an object on the heap.
62 template <typename ValueType>
64 public:
65  using RawPtrType = std::add_pointer_t<ValueType>;
66  using ReferenceType = std::add_lvalue_reference_t<ValueType>;
68 
69  static_assert(
70  std::is_same_v<
71  void,
72  decltype(TfDelegatedCountIncrement(std::declval<RawPtrType>()))>);
73  static_assert(
74  std::is_same_v<
75  void,
76  decltype(TfDelegatedCountDecrement(std::declval<RawPtrType>()))>);
77 
78  using IncrementIsNoExcept =
79  std::integral_constant<
80  bool,
81  noexcept(TfDelegatedCountIncrement(std::declval<RawPtrType>()))>;
82  using DecrementIsNoExcept =
83  std::integral_constant<
84  bool,
85  noexcept(TfDelegatedCountDecrement(std::declval<RawPtrType>()))>;
87  std::integral_constant<
89  using DereferenceIsNoExcept =
90  std::integral_constant<bool, noexcept(*std::declval<RawPtrType>())>;
91 
92 private:
93  template <typename ConvertibleType>
94  using _IsPtrConvertible = std::is_convertible<
95  std::add_pointer_t<ConvertibleType>, RawPtrType>;
96 
97 public:
98  /// Create a pointer storing `nullptr`
99  TfDelegatedCountPtr() noexcept = default;
100 
101  /// Create a new pointer storing `rawPointer` without calling
102  /// `TfDelegatedCountIncrement`.
103  /// \sa TfDelegatedCountDoNotIncrementTag
105  RawPtrType rawPointer) noexcept :
106  _pointer{rawPointer} {
107  }
108 
109  /// Create a new pointer storing `rawPointer` and call
110  /// `TfDelegatedCountIncrement` on it if it is not `nullptr`.
111  /// \sa TfDelegatedCountIncrementTag
113  RawPtrType rawPointer)
114  noexcept(IncrementIsNoExcept()) :
115  _pointer{rawPointer} {
116  _IncrementIfValid();
117  }
118 
119  /// Copy construct from `ptr`, calling `TfDelegatedCountIncrement` on the
120  /// held pointer if it is not `nullptr`.
122  noexcept(IncrementIsNoExcept()) :
123  _pointer{ptr.get()} {
124  _IncrementIfValid();
125  }
126 
127  /// Copy construct from `ptr` if it is convertible to this class's
128  /// `RawPtrType`. Call `TfDelegatedCountIncrement` on the held pointer if it
129  /// is not `nullptr`.
130  template <typename OtherType>
133  std::enable_if_t<_IsPtrConvertible<OtherType>::value, int> = 0)
134  noexcept(IncrementIsNoExcept()) :
135  _pointer(ptr.get()) {
136  _IncrementIfValid();
137  }
138 
139  /// Construct by moving from `ptr`.
140  ///
141  /// `ptr` is left in its default state (i.e. `nullptr`).
143  _pointer(ptr.get()) {
144  ptr._pointer = nullptr;
145  }
146 
147  /// Assign by copying from `ptr`.
148  ///
149  /// Call `TfDelegatedCountIncrement` on the held pointer if it is not
150  /// `nullptr`.
153  // Implement copy assigment in terms of move assignment
154  return (*this = TfDelegatedCountPtr{ptr});
155  }
156 
157  /// Assign by copying from `ptr` if it is convertible to this class's
158  /// `RawPtrType`. Call `TfDelegatedCountIncrement` on the held pointer if it
159  /// is not `nullptr`.
160  template <typename OtherType>
164  static_assert(_IsPtrConvertible<OtherType>::value);
165  // Implement copy assigment in terms of move assignment
166  return (*this = TfDelegatedCountPtr{ptr});
167  }
168 
169  /// Assign by moving from `ptr`.
170  ///
171  /// `ptr` is left in its default state (i.e. `nullptr`).
173  noexcept(DecrementIsNoExcept()) {
174  _DecrementIfValid();
175  _pointer = ptr.get();
176  ptr._pointer = nullptr;
177  return *this;
178  }
179 
180  /// Reset this pointer to its default state (i.e. `nullptr`)
182  noexcept(DecrementIsNoExcept()) {
183  reset();
184  return *this;
185  }
186 
187  /// Call `TfDelegatedCountDecrement` on the held pointer if it is not
188  /// nullptr`. A bug occurs in VS2017 where calling DecrementIsNoExcept()
189  /// may return void. The bug is possibly related to an issue with using
190  /// noexcept expressions in destructors.
192  _DecrementIfValid();
193  }
194 
195  /// Dereference the underlying pointer.
197  return *get();
198  }
199 
200  /// Arrow operator dispatch for the underlying pointer.
201  RawPtrType operator->() const noexcept {
202  return get();
203  }
204 
205  /// Return true if the underlying pointer is non-null, false otherwise.
206  explicit operator bool() const noexcept { return get(); }
207 
208  /// Return true if the underlying pointers are equivalent.
209  template <typename OtherType>
211  const TfDelegatedCountPtr<OtherType>& other) const noexcept {
212  return get() == other.get();
213  }
214 
215  /// Returns false if the underlying pointers are equivalent.
216  template <typename OtherType>
218  const TfDelegatedCountPtr<OtherType>& other) const noexcept {
219  return get() != other.get();
220  }
221 
222  /// Orders based on the underlying pointer.
223  template <typename OtherType>
224  bool operator<(
225  const TfDelegatedCountPtr<OtherType>& other) const noexcept {
226  return get() < other.get();
227  }
228 
229  /// Return the underlying pointer.
230  RawPtrType get() const noexcept { return _pointer; }
231 
232  /// Reset the pointer to its default state (`nullptr`), calling
233  /// `TfDelegatedCountDecrement` if the held pointer is not null.
234  void reset() noexcept(DecrementIsNoExcept()) {
235  _DecrementIfValid();
236  _pointer = nullptr;
237  }
238 
239  /// Swap this object's held pointer with other's.
240  void swap(TfDelegatedCountPtr& other) noexcept {
241  std::swap(other._pointer, _pointer);
242  }
243 
244 private:
245  void _IncrementIfValid() noexcept(IncrementIsNoExcept()) {
246  if (_pointer) {
247  TfDelegatedCountIncrement(_pointer);
248  }
249  }
250 
251  void _DecrementIfValid() noexcept(DecrementIsNoExcept()) {
252  if (_pointer) {
253  TfDelegatedCountDecrement(_pointer);
254  }
255  }
256 
257  ValueType* _pointer{nullptr};
258 };
259 
260 /// Construct a `ValueType` instance on the heap via `new`, passing `args`. Call
261 /// `TfDelegatedCountIncrement` on the resulting pointer and return a
262 /// `TfDelegatedCountPtr` holding that pointer.
263 template <typename ValueType, typename... Args>
268  new ValueType(std::forward<Args>(args)...)
269  );
270 }
271 
273 
274 #endif
typename std::enable_if< B, T >::type enable_if_t
Define Imath::enable_if_t to be std for C++14, equivalent for C++11.
TfDelegatedCountPtr & operator=(const TfDelegatedCountPtr &ptr) noexcept(IncrementAndDecrementAreNoExcept())
TfDelegatedCountPtr(const TfDelegatedCountPtr &ptr) noexcept(IncrementIsNoExcept())
std::integral_constant< bool, noexcept(TfDelegatedCountIncrement(std::declval< RawPtrType >()))> IncrementIsNoExcept
void swap(UT::ArraySet< Key, MULTI, MAX_LOAD_FACTOR_256, Clearer, Hash, KeyEqual > &a, UT::ArraySet< Key, MULTI, MAX_LOAD_FACTOR_256, Clearer, Hash, KeyEqual > &b)
Definition: UT_ArraySet.h:1699
GLsizei const GLfloat * value
Definition: glcorearb.h:824
bool operator!=(const TfDelegatedCountPtr< OtherType > &other) const noexcept
Returns false if the underlying pointers are equivalent.
TfDelegatedCountPtr(TfDelegatedCountPtr &&ptr) noexcept
void reset() noexcept(DecrementIsNoExcept())
bool operator==(const TfDelegatedCountPtr< OtherType > &other) const noexcept
Return true if the underlying pointers are equivalent.
std::integral_constant< bool, IncrementIsNoExcept()&&DecrementIsNoExcept()> IncrementAndDecrementAreNoExcept
std::integral_constant< bool, noexcept(*std::declval< RawPtrType >())> DereferenceIsNoExcept
OutGridT const XformOp bool bool
TfDelegatedCountPtr() noexcept=default
Create a pointer storing nullptr
TfDelegatedCountPtr & operator=(const TfDelegatedCountPtr< OtherType > &ptr) noexcept(IncrementAndDecrementAreNoExcept())
RawPtrType get() const noexcept
Return the underlying pointer.
RawPtrType operator->() const noexcept
Arrow operator dispatch for the underlying pointer.
TfDelegatedCountPtr(TfDelegatedCountIncrementTagType, RawPtrType rawPointer) noexcept(IncrementIsNoExcept())
std::add_pointer_t< Sdf_Identity > RawPtrType
TfDelegatedCountPtr & operator=(std::nullptr_t) noexcept(DecrementIsNoExcept())
Reset this pointer to its default state (i.e. nullptr)
ReferenceType operator*() const noexcept(DereferenceIsNoExcept())
Dereference the underlying pointer.
TfDelegatedCountPtr< ValueType > TfMakeDelegatedCountPtr(Args &&...args)
void TfDelegatedCountDecrement(PXR_NS::Sdf_Identity *p) noexcept
Definition: identity.h:68
constexpr struct TfDelegatedCountDoNotIncrementTagType TfDelegatedCountDoNotIncrementTag
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1425
auto ptr(T p) -> const void *
Definition: format.h:4331
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
**If you just want to fire and args
Definition: thread.h:618
TfDelegatedCountPtr(const TfDelegatedCountPtr< OtherType > &ptr, std::enable_if_t< _IsPtrConvertible< OtherType >::value, int >=0) noexcept(IncrementIsNoExcept())
bool operator<(const TfDelegatedCountPtr< OtherType > &other) const noexcept
Orders based on the underlying pointer.
std::integral_constant< bool, noexcept(TfDelegatedCountDecrement(std::declval< RawPtrType >()))> DecrementIsNoExcept
bool ValueType
Definition: NanoVDB.h:5729
PXR_NAMESPACE_OPEN_SCOPE constexpr struct TfDelegatedCountIncrementTagType TfDelegatedCountIncrementTag
TfDelegatedCountPtr & operator=(TfDelegatedCountPtr &&ptr) noexcept(DecrementIsNoExcept())
void TfDelegatedCountIncrement(PXR_NS::Sdf_Identity *p)
Definition: identity.h:65
std::add_lvalue_reference_t< Sdf_Identity > ReferenceType
~TfDelegatedCountPtr() noexcept(DecrementIsNoExcept::value)
void swap(TfDelegatedCountPtr &other) noexcept
Swap this object's held pointer with other's.