HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
refcnt.h
Go to the documentation of this file.
1 // Copyright 2008-present Contributors to the OpenImageIO project.
2 // SPDX-License-Identifier: BSD-3-Clause
3 // https://github.com/OpenImageIO/oiio
4 
5 
6 /////////////////////////////////////////////////////////////////////////
7 /// \file
8 ///
9 /// Wrappers and utilities for reference counting.
10 /////////////////////////////////////////////////////////////////////////
11 
12 
13 #pragma once
14 
15 #include <memory>
16 
17 #include <OpenImageIO/atomic.h>
18 #include <OpenImageIO/dassert.h>
19 
20 
22 
23 using std::shared_ptr; // DEPRECATED(1.8)
24 
25 
26 
27 /// A simple intrusive pointer, modeled after std::shared_ptr.
28 template<class T> class intrusive_ptr {
29 public:
30  typedef T element_type;
31 
32  /// Default ctr
33  intrusive_ptr() noexcept
34  : m_ptr(NULL)
35  {
36  }
37 
38  /// Construct from a raw pointer (presumed to be just now allocated,
39  /// and now owned by us).
41  : m_ptr(ptr)
42  {
43  if (m_ptr)
44  intrusive_ptr_add_ref(m_ptr);
45  }
46 
47  /// Construct from another intrusive_ptr.
49  : m_ptr(r.get())
50  {
51  if (m_ptr)
52  intrusive_ptr_add_ref(m_ptr);
53  }
54 
55  /// Move construct from another intrusive_ptr.
57  : m_ptr(r.get())
58  {
59  r.m_ptr = NULL;
60  }
61 
62  /// Destructor
64  {
65  if (m_ptr)
66  intrusive_ptr_release(m_ptr);
67  }
68 
69  /// Assign from intrusive_ptr
71  {
72  intrusive_ptr(r).swap(*this);
73  return *this;
74  }
75 
76  /// Move assignment from intrusive_ptr
78  {
79  intrusive_ptr(static_cast<intrusive_ptr&&>(r)).swap(*this);
80  return *this;
81  }
82 
83  /// Reset to null reference
84  void reset() noexcept
85  {
86  if (m_ptr) {
87  intrusive_ptr_release(m_ptr);
88  m_ptr = NULL;
89  }
90  }
91 
92  /// Reset to point to a pointer
93  void reset(T* r)
94  {
95  if (r != m_ptr) {
96  if (r)
98  if (m_ptr)
99  intrusive_ptr_release(m_ptr);
100  m_ptr = r;
101  }
102  }
103 
104  /// Set this smart pointer to null, decrement the object's reference
105  /// count, return the original raw pointer, but do NOT delete the object
106  /// even if the ref count goes to zero. The only safe use case is to
107  /// convert the sole managed pointer to an object into a raw pointer.
108  /// DANGER -- use with caution! This is only safe to do if no other
109  /// intrusive_ptr refers to the object (such a pointer may subsequently
110  /// reset, decrementing the count to 0, and incorrectly free the
111  /// object), and it can cause a memory leak if the caller isn't careful
112  /// to either reassign the returned pointer to another managed pointer
113  /// or delete it manually.
115  {
116  T* p = m_ptr;
117  if (p) {
118  if (!p->_decref())
119  OIIO_DASSERT(0 && "release() when you aren't the sole owner");
120  m_ptr = nullptr;
121  }
122  return p;
123  }
124 
125  /// Swap intrusive pointers
126  void swap(intrusive_ptr& r) noexcept
127  {
128  T* tmp = m_ptr;
129  m_ptr = r.m_ptr;
130  r.m_ptr = tmp;
131  }
132 
133  /// Dereference
134  T& operator*() const
135  {
136  OIIO_DASSERT(m_ptr);
137  return *m_ptr;
138  }
139 
140  /// Dereference
141  T* operator->() const
142  {
143  OIIO_DASSERT(m_ptr);
144  return m_ptr;
145  }
146 
147  /// Get raw pointer
148  T* get() const noexcept { return m_ptr; }
149 
150  /// Cast to bool to detect whether it points to anything
151  operator bool() const noexcept { return m_ptr != NULL; }
152 
153  friend bool operator==(const intrusive_ptr& a, const T* b)
154  {
155  return a.get() == b;
156  }
157  friend bool operator==(const T* b, const intrusive_ptr& a)
158  {
159  return a.get() == b;
160  }
161 
162 private:
163  T* m_ptr; // the raw pointer
164 };
165 
166 
167 
168 /// Mix-in class that adds a reference count, implemented as an atomic
169 /// counter.
170 class RefCnt {
171 protected:
172  // Declare RefCnt constructors and destructors protected because they
173  // should only be called implicitly from within child class constructors or
174  // destructors. In particular, this prevents users from deleting a RefCnt*
175  // which is important because the destructor is non-virtual.
176 
177  RefCnt() { m_refcnt = 0; }
178 
179  /// Define copy constructor to NOT COPY reference counts! Copying a
180  /// struct doesn't change how many other things point to it.
181  RefCnt(RefCnt&) { m_refcnt = 0; }
182 
183  ~RefCnt() {}
184 
185 public:
186  /// Add a reference
187  ///
188  void _incref() const { ++m_refcnt; }
189 
190  /// Delete a reference, return true if that was the last reference.
191  ///
192  bool _decref() const { return (--m_refcnt) == 0; }
193 
194  /// Define operator= to NOT COPY reference counts! Assigning a struct
195  /// doesn't change how many other things point to it.
196  const RefCnt& operator=(const RefCnt&) const { return *this; }
197 
198 private:
199  mutable atomic_int m_refcnt;
200 };
201 
202 
203 
204 /// Implementation of intrusive_ptr_add_ref, which is needed for
205 /// any class that you use with intrusive_ptr.
206 template<class T>
207 inline void
209 {
210  x->_incref();
211 }
212 
213 /// Implementation of intrusive_ptr_release, which is needed for
214 /// any class that you use with intrusive_ptr.
215 template<class T>
216 inline void
218 {
219  if (x->_decref())
220  delete x;
221 }
222 
223 // Note that intrusive_ptr_add_ref and intrusive_ptr_release MUST be a
224 // templated on the full type, so that they pass the right address to
225 // 'delete' and destroy the right type. If you try to just
226 // 'inline void intrusive_ptr_release (RefCnt *x)', that might seem
227 // clever, but it will end up getting the address of (and destroying)
228 // just the inherited RefCnt sub-object, not the full subclass you
229 // meant to delete and destroy.
230 
231 
232 
233 // Preprocessor flags for some capabilities added incrementally.
234 #define OIIO_REFCNT_HAS_RELEASE 1 /* intrusive_ptr::release() */
235 
236 
intrusive_ptr(T *ptr)
Definition: refcnt.h:40
~intrusive_ptr()
Destructor.
Definition: refcnt.h:63
~RefCnt()
Definition: refcnt.h:183
T * operator->() const
Dereference.
Definition: refcnt.h:141
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1222
intrusive_ptr(const intrusive_ptr &r)
Construct from another intrusive_ptr.
Definition: refcnt.h:48
void reset() noexcept
Reset to null reference.
Definition: refcnt.h:84
void swap(intrusive_ptr &r) noexcept
Swap intrusive pointers.
Definition: refcnt.h:126
void _incref() const
Definition: refcnt.h:188
friend bool operator==(const intrusive_ptr &a, const T *b)
Definition: refcnt.h:153
atomic< int > atomic_int
Definition: atomic.h:25
intrusive_ptr(intrusive_ptr &&r) noexcept
Move construct from another intrusive_ptr.
Definition: refcnt.h:56
Definition: refcnt.h:170
void intrusive_ptr_release(T *x)
Definition: refcnt.h:217
#define OIIO_DASSERT
Definition: dassert.h:55
intrusive_ptr() noexcept
Default ctr.
Definition: refcnt.h:33
T * get() const noexcept
Get raw pointer.
Definition: refcnt.h:148
T * release()
Definition: refcnt.h:114
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1222
GLint GLenum GLint x
Definition: glcorearb.h:409
Wrappers and utilities for atomics.
void reset(T *r)
Reset to point to a pointer.
Definition: refcnt.h:93
T & operator*() const
Dereference.
Definition: refcnt.h:134
RefCnt()
Definition: refcnt.h:177
void intrusive_ptr_add_ref(T *x)
Definition: refcnt.h:208
intrusive_ptr & operator=(const intrusive_ptr &r)
Assign from intrusive_ptr.
Definition: refcnt.h:70
auto ptr(T p) -> const void *
Definition: format.h:2448
friend bool operator==(const T *b, const intrusive_ptr &a)
Definition: refcnt.h:157
intrusive_ptr & operator=(intrusive_ptr &&r) noexcept
Move assignment from intrusive_ptr.
Definition: refcnt.h:77
GLboolean r
Definition: glcorearb.h:1222
#define OIIO_NAMESPACE_END
Definition: oiioversion.h:94
bool _decref() const
Definition: refcnt.h:192
RefCnt(RefCnt &)
Definition: refcnt.h:181
T element_type
Definition: refcnt.h:30
const RefCnt & operator=(const RefCnt &) const
Definition: refcnt.h:196
#define OIIO_NAMESPACE_BEGIN
Definition: oiioversion.h:93
A simple intrusive pointer, modeled after std::shared_ptr.
Definition: refcnt.h:28