1
2//
3// This source file is part of appleseed.
4// Visit http://appleseedhq.net/ for additional information and resources.
5//
6// This software is released under the MIT license.
7//
8// Copyright (c) 2010-2013 Francois Beaune, Jupiter Jazz Limited
9// Copyright (c) 2014-2017 Francois Beaune, The appleseedhq Organization
10//
11// Permission is hereby granted, free of charge, to any person obtaining a copy
12// of this software and associated documentation files (the "Software"), to deal
13// in the Software without restriction, including without limitation the rights
14// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15// copies of the Software, and to permit persons to whom the Software is
16// furnished to do so, subject to the following conditions:
17//
18// The above copyright notice and this permission notice shall be included in
19// all copies or substantial portions of the Software.
20//
21// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27// THE SOFTWARE.
28//
29
30#ifndef APPLESEED_FOUNDATION_UTILITY_AUTORELEASEPTR_H
31#define APPLESEED_FOUNDATION_UTILITY_AUTORELEASEPTR_H
32
33// Standard headers.
34#include <cassert>
35
36namespace foundation
37{
38
39//
40// Similarly to std::auto_ptr, foundation::auto_release_ptr is a smart pointer
41// providing strict ownership semantics. The only difference with std::auto_ptr
42// is that the pointed object is deleted using foundation::IUnknown::release()
43// instead of the delete operator.
44//
45
46// A wrapper class to provide auto_release_ptr with reference semantics.
47template <typename T>
48struct auto_release_ptr_ref
49{
50 T* m_ptr;
51
52 explicit auto_release_ptr_ref(T* ptr)
53 : m_ptr(ptr)
54 {
55 }
56};
57
58template <typename T>
59class auto_release_ptr
60{
61 public:
62 typedef T element_type;
63
64 // Construct from a raw pointer.
65 explicit auto_release_ptr(T* ptr = 0) throw()
66 : m_ptr(ptr)
67 {
68 }
69
70 // Construct from another auto_release_ptr of the same type.
71 auto_release_ptr(auto_release_ptr& rhs) throw()
72 : m_ptr(rhs.release())
73 {
74 }
75
76 // Construct from another auto_release_ptr of a different but related type.
77 template <typename U>
78 auto_release_ptr(auto_release_ptr<U>& rhs) throw()
79 : m_ptr(rhs.release())
80 {
81 }
82
83 // Construct from an auto_release_ptr_ref.
84 auto_release_ptr(auto_release_ptr_ref<T> ref) throw()
85 : m_ptr(ref.m_ptr)
86 {
87 }
88
89 // Assign from another auto_release_ptr of the same type.
90 auto_release_ptr& operator=(auto_release_ptr& rhs) throw()
91 {
92 reset(rhs.release());
93 return *this;
94 }
95
96 // Assign from another auto_release_ptr of a different but related type.
97 template <typename U>
98 auto_release_ptr& operator=(auto_release_ptr<U>& rhs) throw()
99 {
100 reset(rhs.release());
101 return *this;
102 }
103
104 // Assign from an auto_release_ptr_ref.
105 auto_release_ptr<T>& operator=(auto_release_ptr_ref<T> ref) throw()
106 {
107 if (m_ptr != ref.m_ptr)
108 {
109 if (m_ptr)
110 m_ptr->release();
111
112 m_ptr = ref.m_ptr;
113 }
114
115 return *this;
116 }
117
118 // Delete the wrapped pointer.
119 ~auto_release_ptr()
120 {
121 if (m_ptr)
122 m_ptr->release();
123 }
124
125 // Automatic conversion to an auto_release_ptr_ref.
126 template <typename U>
127 operator auto_release_ptr_ref<U>() throw()
128 {
129 return auto_release_ptr_ref<U>(release());
130 }
131
132 // Automatic conversion to an auto_release_ptr of a different type.
133 template <typename U>
134 operator auto_release_ptr<U>() throw()
135 {
136 return auto_release_ptr<U>(release());
137 }
138
139 // Dereference the wrapped pointer.
140 T& operator*() const throw()
141 {
142 assert(m_ptr);
143 return *m_ptr;
144 }
145 T* operator->() const throw()
146 {
147 assert(m_ptr);
148 return m_ptr;
149 }
150
151 // Return the wrapped pointer.
152 T* get() const throw()
153 {
154 return m_ptr;
155 }
156 T& ref() const throw()
157 {
158 assert(m_ptr);
159 return *m_ptr;
160 }
161
162 // Return the wrapped pointer and give up ownership.
163 T* release() throw()
164 {
165 T* rv = m_ptr;
166 m_ptr = 0;
167 return rv;
168 }
169
170 // Delete the owned pointer and replace it with the provided raw pointer.
171 void reset(T* ptr = 0) throw()
172 {
173 if (m_ptr != ptr)
174 {
175 if (m_ptr)
176 m_ptr->release();
177
178 m_ptr = ptr;
179 }
180 }
181
182 private:
183 T* m_ptr;
184};
185
186} // namespace foundation
187
188#endif // !APPLESEED_FOUNDATION_UTILITY_AUTORELEASEPTR_H
189