The Pedigree Project 0.1
SharedPointer.h
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#ifndef SHAREDPOINTER_H
21#define SHAREDPOINTER_H
22
23#include "pedigree/kernel/processor/types.h"
24#include "pedigree/kernel/utilities/utility.h"
25
30template <class T>
32 public:
37
42
49
53 virtual ~SharedPointer();
54
59
63 void reset();
68 void reset(T* ptr);
69
73 T* get() const;
74
78 T* operator->() const;
79
83 T& operator*() const;
84
90
95
99 explicit operator bool() const;
100
104 bool unique() const;
105
109 size_t refcount() const;
110
114 template <class... Args>
115 static SharedPointer<T> allocate(Args...);
116
118 template <class... Args>
120
123
128 bool operator==(const SharedPointer& p) const;
129 bool operator!=(const SharedPointer& p) const;
130 bool operator<(const SharedPointer& p) const;
131 bool operator<=(const SharedPointer& p) const;
132 bool operator>(const SharedPointer& p) const;
133 bool operator>=(const SharedPointer& p) const;
134
135 private:
139 void release() noexcept;
140
145 struct Control {
146 T* ptr;
147 size_t refcount;
148 }* m_Control;
149};
150
151template <class T>
153
154template <class T>
155SharedPointer<T>::SharedPointer(T* ptr) : m_Control(0) {
156 reset(ptr);
157}
158
159template <class T>
161 m_Control = other.m_Control;
162
163 other.m_Control = nullptr;
164}
165
166template <class T>
168 release();
169}
170
171template <class T>
173 if (p.m_Control) {
174 __atomic_add_fetch(&p.m_Control->refcount, 1, __ATOMIC_SEQ_CST);
175 }
176
177 release();
178
179 m_Control = p.m_Control;
180}
181
182template <class T>
184 release();
185}
186
187template <class T>
189 release();
190
191 m_Control = new Control;
192 m_Control->refcount = 1;
193 m_Control->ptr = ptr;
194}
195
196template <class T>
198 if (!m_Control)
199 return 0;
200
201 return m_Control->ptr;
202}
203
204template <class T>
206 return get();
207}
208
209template <class T>
211 return *(get());
212}
213
214template <class T>
216 if (this == &p) {
217 return *this;
218 }
219
220 // If the other is assigned, boost its refcount before we release. If it
221 // happens that the other is in fact pointing to the same place, the counts
222 // will not potentially drop to zero then back to one this way (causing a
223 // bad pointer).
224 if (p.m_Control) {
225 __atomic_add_fetch(&p.m_Control->refcount, 1, __ATOMIC_SEQ_CST);
226 }
227
228 release();
229
230 m_Control = p.m_Control;
231
232 return *this;
233}
234
235template <class T>
237 release();
238 m_Control = p.m_Control;
239 p.m_Control = nullptr;
240
241 return *this;
242}
243
244template <class T>
246 return get() != 0;
247}
248
249template <class T>
251 return refcount() == 1;
252}
253
254template <class T>
256 if (!m_Control)
257 return 0;
258
259 return __atomic_load_n(&m_Control->refcount, __ATOMIC_SEQ_CST);
260}
261
262template <class T>
263template <class... Args>
265 SharedPointer<T> result;
266 result.reset(new T(args...));
267 return pedigree_std::move(result);
268}
269
270template <class T>
271template <class... Args>
273 SharedPointer<T> result;
274 result.m_Control = new Control{nullptr, 1};
275 if (!result.m_Control)
276 return result;
277 // Enrol the control block before constructing T, so hosted exceptions also
278 // release it without publishing a partially constructed shared object.
279 result.m_Control->ptr = new T(args...);
280 if (!result.m_Control->ptr)
281 result.reset();
282 return result;
283}
284
285template <class T>
287 SharedPointer<T> result;
288 if (!ptr)
289 return result;
290 result.m_Control = new Control{ptr, 1};
291 if (!result.m_Control)
292 delete ptr;
293 return result;
294}
295
296template <class T>
298 if (!m_Control)
299 return;
300
301 size_t rc = __atomic_sub_fetch(&m_Control->refcount, 1, __ATOMIC_SEQ_CST);
302 if (!rc) {
304 delete m_Control->ptr;
305 m_Control->ptr = 0;
306
307 delete m_Control;
308 }
309
310 // We don't care about the control structure anymore. Someone else will
311 // free it if we did not.
312 m_Control = 0;
313}
314
315template <class T>
317 return get() == p.get();
318}
319
320template <class T>
321bool SharedPointer<T>::operator!=(const SharedPointer& p) const {
322 return get() != p.get();
323}
324
325template <class T>
326bool SharedPointer<T>::operator<(const SharedPointer& p) const {
327 return get() < p.get();
328}
329
330template <class T>
331bool SharedPointer<T>::operator<=(const SharedPointer& p) const {
332 return get() <= p.get();
333}
334
335template <class T>
336bool SharedPointer<T>::operator>(const SharedPointer& p) const {
337 return get() > p.get();
338}
339
340template <class T>
341bool SharedPointer<T>::operator>=(const SharedPointer& p) const {
342 return get() >= p.get();
343}
344
345#endif
T & operator*() const
size_t refcount() const
static SharedPointer< T > tryAdopt(T *ptr)
SharedPointer< T > & operator=(SharedPointer< T > &&p) noexcept
static SharedPointer< T > tryAllocate(Args...)
T * operator->() const
bool unique() const
T * get() const
SharedPointer(SharedPointer< T > &&other) noexcept
void release() noexcept
void reset(T *ptr)
SharedPointer< T > & operator=(const SharedPointer< T > &p)
bool operator==(const SharedPointer &p) const
SharedPointer(const SharedPointer< T > &p)
static SharedPointer< T > allocate(Args...)
virtual ~SharedPointer()
SharedPointer(T *ptr)