HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
refcnt.h
Go to the documentation of this file.
1 /*
2  Copyright 2008 Larry Gritz and the other authors and contributors.
3  All Rights Reserved.
4 
5  Redistribution and use in source and binary forms, with or without
6  modification, are permitted provided that the following conditions are
7  met:
8  * Redistributions of source code must retain the above copyright
9  notice, this list of conditions and the following disclaimer.
10  * Redistributions in binary form must reproduce the above copyright
11  notice, this list of conditions and the following disclaimer in the
12  documentation and/or other materials provided with the distribution.
13  * Neither the name of the software's owners nor the names of its
14  contributors may be used to endorse or promote products derived from
15  this software without specific prior written permission.
16  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28  (This is the Modified BSD License)
29 */
30 
31 
32 /////////////////////////////////////////////////////////////////////////
33 /// \file
34 ///
35 /// Wrappers and utilities for reference counting.
36 /////////////////////////////////////////////////////////////////////////
37 
38 
39 #pragma once
40 
41 #include <memory>
42 
43 #include <OpenImageIO/atomic.h>
44 
45 
47 
48 using std::shared_ptr; // DEPRECATED(1.8)
49 
50 
51 
52 /// A simple intrusive pointer, modeled after std::shared_ptr.
53 template<class T> class intrusive_ptr {
54 public:
55  typedef T element_type;
56 
57  /// Default ctr
58  intrusive_ptr() noexcept
59  : m_ptr(NULL)
60  {
61  }
62 
63  /// Construct from a raw pointer (presumed to be just now allocated,
64  /// and now owned by us).
66  : m_ptr(ptr)
67  {
68  if (m_ptr)
69  intrusive_ptr_add_ref(m_ptr);
70  }
71 
72  /// Construct from another intrusive_ptr.
74  : m_ptr(r.get())
75  {
76  if (m_ptr)
77  intrusive_ptr_add_ref(m_ptr);
78  }
79 
80  /// Move construct from another intrusive_ptr.
82  : m_ptr(r.get())
83  {
84  r.m_ptr = NULL;
85  }
86 
87  /// Destructor
89  {
90  if (m_ptr)
91  intrusive_ptr_release(m_ptr);
92  }
93 
94  /// Assign from intrusive_ptr
96  {
97  intrusive_ptr(r).swap(*this);
98  return *this;
99  }
100 
101  /// Move assignment from intrusive_ptr
103  {
104  intrusive_ptr(static_cast<intrusive_ptr&&>(r)).swap(*this);
105  return *this;
106  }
107 
108  /// Reset to null reference
109  void reset() noexcept
110  {
111  if (m_ptr) {
112  intrusive_ptr_release(m_ptr);
113  m_ptr = NULL;
114  }
115  }
116 
117  /// Reset to point to a pointer
118  void reset(T* r)
119  {
120  if (r != m_ptr) {
121  if (r)
123  if (m_ptr)
124  intrusive_ptr_release(m_ptr);
125  m_ptr = r;
126  }
127  }
128 
129  /// Set this smart pointer to null, decrement the object's reference
130  /// count, return the original raw pointer, but do NOT delete the object
131  /// even if the ref count goes to zero. The only safe use case is to
132  /// convert the sole managed pointer to an object into a raw pointer.
133  /// DANGER -- use with caution! This is only safe to do if no other
134  /// intrusive_ptr refers to the object (such a pointer may subsequently
135  /// reset, decrementing the count to 0, and incorrectly free the
136  /// object), and it can cause a memory leak if the caller isn't careful
137  /// to either reassign the returned pointer to another managed pointer
138  /// or delete it manually.
140  {
141  T* p = m_ptr;
142  if (p) {
143  if (!p->_decref())
144  DASSERT(0 && "release() when you aren't the sole owner");
145  m_ptr = nullptr;
146  }
147  return p;
148  }
149 
150  /// Swap intrusive pointers
151  void swap(intrusive_ptr& r) noexcept
152  {
153  T* tmp = m_ptr;
154  m_ptr = r.m_ptr;
155  r.m_ptr = tmp;
156  }
157 
158  /// Dereference
159  T& operator*() const
160  {
161  DASSERT(m_ptr);
162  return *m_ptr;
163  }
164 
165  /// Dereference
166  T* operator->() const
167  {
168  DASSERT(m_ptr);
169  return m_ptr;
170  }
171 
172  /// Get raw pointer
173  T* get() const noexcept { return m_ptr; }
174 
175  /// Cast to bool to detect whether it points to anything
176  operator bool() const noexcept { return m_ptr != NULL; }
177 
178 private:
179  T* m_ptr; // the raw pointer
180 };
181 
182 
183 
184 /// Mix-in class that adds a reference count, implemented as an atomic
185 /// counter.
186 class RefCnt {
187 protected:
188  // Declare RefCnt constructors and destructors protected because they
189  // should only be called implicitly from within child class constructors or
190  // destructors. In particular, this prevents users from deleting a RefCnt*
191  // which is important because the destructor is non-virtual.
192 
193  RefCnt() { m_refcnt = 0; }
194 
195  /// Define copy constructor to NOT COPY reference counts! Copying a
196  /// struct doesn't change how many other things point to it.
197  RefCnt(RefCnt&) { m_refcnt = 0; }
198 
199  ~RefCnt() {}
200 
201 public:
202  /// Add a reference
203  ///
204  void _incref() const { ++m_refcnt; }
205 
206  /// Delete a reference, return true if that was the last reference.
207  ///
208  bool _decref() const { return (--m_refcnt) == 0; }
209 
210  /// Define operator= to NOT COPY reference counts! Assigning a struct
211  /// doesn't change how many other things point to it.
212  const RefCnt& operator=(const RefCnt&) const { return *this; }
213 
214 private:
215  mutable atomic_int m_refcnt;
216 };
217 
218 
219 
220 /// Implementation of intrusive_ptr_add_ref, which is needed for
221 /// any class that you use with intrusive_ptr.
222 template<class T>
223 inline void
225 {
226  x->_incref();
227 }
228 
229 /// Implementation of intrusive_ptr_release, which is needed for
230 /// any class that you use with intrusive_ptr.
231 template<class T>
232 inline void
234 {
235  if (x->_decref())
236  delete x;
237 }
238 
239 // Note that intrusive_ptr_add_ref and intrusive_ptr_release MUST be a
240 // templated on the full type, so that they pass the right address to
241 // 'delete' and destroy the right type. If you try to just
242 // 'inline void intrusive_ptr_release (RefCnt *x)', that might seem
243 // clever, but it will end up getting the address of (and destroying)
244 // just the inherited RefCnt sub-object, not the full subclass you
245 // meant to delete and destroy.
246 
247 
248 
249 // Preprocessor flags for some capabilities added incrementally.
250 #define OIIO_REFCNT_HAS_RELEASE 1 /* intrusive_ptr::release() */
251 
252 
intrusive_ptr(T *ptr)
Definition: refcnt.h:65
~intrusive_ptr()
Destructor.
Definition: refcnt.h:88
~RefCnt()
Definition: refcnt.h:199
T * operator->() const
Dereference.
Definition: refcnt.h:166
intrusive_ptr(const intrusive_ptr &r)
Construct from another intrusive_ptr.
Definition: refcnt.h:73
void reset() noexcept
Reset to null reference.
Definition: refcnt.h:109
void swap(intrusive_ptr &r) noexcept
Swap intrusive pointers.
Definition: refcnt.h:151
void _incref() const
Definition: refcnt.h:204
atomic< int > atomic_int
Definition: atomic.h:51
intrusive_ptr(intrusive_ptr &&r) noexcept
Move construct from another intrusive_ptr.
Definition: refcnt.h:81
Definition: refcnt.h:186
void intrusive_ptr_release(T *x)
Definition: refcnt.h:233
#define DASSERT(x)
Definition: dassert.h:99
GLint GLint GLint GLint GLint x
Definition: glew.h:1252
intrusive_ptr() noexcept
Default ctr.
Definition: refcnt.h:58
T * get() const noexcept
Get raw pointer.
Definition: refcnt.h:173
T * release()
Definition: refcnt.h:139
Wrappers and utilities for atomics.
void reset(T *r)
Reset to point to a pointer.
Definition: refcnt.h:118
T & operator*() const
Dereference.
Definition: refcnt.h:159
GLfloat GLfloat p
Definition: glew.h:16321
RefCnt()
Definition: refcnt.h:193
void intrusive_ptr_add_ref(T *x)
Definition: refcnt.h:224
const void * ptr(const T *p)
Definition: format.h:3292
intrusive_ptr & operator=(const intrusive_ptr &r)
Assign from intrusive_ptr.
Definition: refcnt.h:95
GLdouble GLdouble GLdouble r
Definition: glew.h:1406
intrusive_ptr & operator=(intrusive_ptr &&r) noexcept
Move assignment from intrusive_ptr.
Definition: refcnt.h:102
#define const
Definition: zconf.h:214
#define OIIO_NAMESPACE_END
Definition: oiioversion.h:66
bool _decref() const
Definition: refcnt.h:208
RefCnt(RefCnt &)
Definition: refcnt.h:197
T element_type
Definition: refcnt.h:55
const RefCnt & operator=(const RefCnt &) const
Definition: refcnt.h:212
#define OIIO_NAMESPACE_BEGIN
Definition: oiioversion.h:65
A simple intrusive pointer, modeled after std::shared_ptr.
Definition: refcnt.h:53