]> git.saurik.com Git - apple/xnu.git/blame - libkern/os/smart_ptr.h
xnu-6153.141.1.tar.gz
[apple/xnu.git] / libkern / os / smart_ptr.h
CommitLineData
cb323159
A
1#ifndef _OS_SMART_POINTER_H
2#define _OS_SMART_POINTER_H
3
4#include <sys/cdefs.h>
5#include <os/cpp_util.h>
6
7#pragma clang diagnostic push
8#pragma clang diagnostic ignored "-Wc++11-extensions"
9
10#if __has_attribute(trivial_abi)
11# define OS_TRIVIAL_ABI __attribute__((trivial_abi))
12#else
13# error Smart pointers depend on trivial_abi attribute
14#endif
15
16#if !OS_HAS_RVALUE_REFERENCES
17# error Smart pointers depend on rvalue references
18#endif
19
20/* C++98 compatibility */
21#if !OS_HAS_NULLPTR && !defined(nullptr)
22# define nullptr NULL
23#endif
24
25#ifndef OSPTR_LOG
26# define OSPTR_LOG(x, ...) do {} while(0)
27#endif
28
29namespace os {
30static struct no_retain_t {} no_retain;
31
32template<class T, class Policy>
33class OS_TRIVIAL_ABI smart_ptr
34{
35 template<class U, class OtherPolicy> friend class smart_ptr;
36
37public:
38
39/*
40 * Default constructor, creates a null pointer
41 */
42 smart_ptr() : pointer(nullptr)
43 {
44 OSPTR_LOG("Default construct smart_ptr\n");
45 }
46
47#if OS_HAS_NULLPTR
48/*
49 * Construction from a nullptr
50 */
51 smart_ptr(os::nullptr_t) : pointer(nullptr)
52 {
53 OSPTR_LOG("Construct smart_ptr from null\n");
54 }
55#endif
56
57/*
58 * Construct from a raw pointer, taking a reference to the object
59 */
60 explicit smart_ptr(T *&p) : pointer(p)
61 {
62 OSPTR_LOG("Construct smart_ptr from raw %p\n", pointer);
63 if (pointer != nullptr) {
64 _retain(pointer);
65 }
66 }
67
68/*
69 * Construct from a raw pointer, without bumping the refcount
70 */
71 explicit smart_ptr(T *&p, no_retain_t) : pointer(p)
72 {
73 OSPTR_LOG("Construct smart_ptr from raw %p no retain\n", pointer);
74 }
75
76/*
77 * Copy constructor from the same smart_ptr type
78 */
79 smart_ptr(smart_ptr const &rhs) : pointer(rhs.pointer)
80 {
81 OSPTR_LOG("Copy construct smart_ptr with %p\n", rhs.pointer);
82 if (pointer != nullptr) {
83 _retain(pointer);
84 }
85 }
86
87#if !LIBKERN_NO_MEMBER_TEMPLATES
88/*
89 * Allows copy of a smart_ptr<T> from a smart_ptr<U>
90 * if U is convertible to T. For example, if T is a base class of U
91 */
92 template<class U>
93 smart_ptr(smart_ptr<U, Policy> const &rhs) : pointer(rhs.get())
94 {
95 OSPTR_LOG("Copy construct smart_ptr with compatible %p\n", rhs.pointer);
96 if (pointer != nullptr) {
97 _retain(pointer);
98 }
99 }
100#endif
101
102/*
103 * Assign to an OSPointer from a raw pointer
104 */
105 smart_ptr &
106 operator=(T *&rhs)
107 {
108 OSPTR_LOG("Assign smart_ptr with replacing %p with raw %p\n", pointer, rhs);
109 smart_ptr(rhs).swap(*this);
110 return *this;
111 }
112
113#if OS_HAS_NULLPTR
114/*
115 * Assign to an OSPointer from a null pointer
116 */
117 smart_ptr &
118 operator=(os::nullptr_t)
119 {
120 OSPTR_LOG("Assign smart_ptr to null replacing %p\n", pointer);
121 smart_ptr().swap(*this);
122 return *this;
123 }
124#endif
125
126/*
127 * Assign to a smart_ptr from a smart_ptr of the same type
128 */
129 smart_ptr &
130 operator=(smart_ptr &rhs)
131 {
132 OSPTR_LOG("Assign smart_ptr replacing %p with %p\n", pointer, rhs.pointer);
133 smart_ptr(rhs).swap(*this);
134 return *this;
135 }
136
137#if !LIBKERN_NO_MEMBER_TEMPLATES
138/*
139 * Allows assignment of a smart_ptr<T> from a smart_ptr<U>
140 * if U is convertible to T. For example, if T is a base class of U.
141 */
142 template <class U>
143 smart_ptr &
144 operator=(smart_ptr<U, Policy> const &rhs)
145 {
146 OSPTR_LOG("Assign smart_ptr to compatible replacing %p with %p\n", pointer, rhs.pointer);
147 smart_ptr(rhs.get()).swap(*this);
148 return *this;
149 }
150#endif
151
152/*
153 * Move support
154 */
155
156#if OS_HAS_RVALUE_REFERENCES
157/*
158 * Move-construct from a different smart_ptr of the same pointer type
159 */
160 smart_ptr(smart_ptr &&rhs) : pointer(rhs.pointer)
161 {
162 OSPTR_LOG("Move construct smart_ptr with %p\n", rhs.pointer);
163 rhs.pointer = nullptr;
164 }
165
166/*
167 * Move-construct from a raw pointer
168 */
169 smart_ptr(T *&&p) : pointer(p)
170 {
171 OSPTR_LOG("Move construct smart_ptr with %p\n", pointer);
172 if (pointer != nullptr) {
173 _retain(pointer);
174 }
175 p = nullptr;
176 }
177
178/*
179 * Move-construct from a raw pointer without bumping the refcount
180 */
181 smart_ptr(T *&&p, no_retain_t) : pointer(p)
182 {
183 OSPTR_LOG("Move construct smart_ptr with %p no retain\n", pointer);
184 p = nullptr;
185 }
186
187/*
188 * Move-assign to a smart_ptr from a raw pointer
189 */
190 smart_ptr &
191 operator=(T *&&rhs)
192 {
193 OSPTR_LOG("Move assign smart_ptr replacing %p with raw %p\n", pointer, rhs);
194 smart_ptr(os::move(rhs)).swap(*this);
195 rhs = nullptr;
196 return *this;
197 }
198
199/*
200 * Move-assign from a different smart_ptr of the same type
201 */
202 smart_ptr &
203 operator=(smart_ptr &&rhs)
204 {
205 OSPTR_LOG("Move assign smart_ptr replacing %p with %p\n", pointer, rhs.pointer);
206 smart_ptr(os::move(rhs)).swap(*this);
207 return *this;
208 }
209
210/*
211 * Move from a different smart_ptr with a compatible pointer type
212 */
213 template<class U>
214 smart_ptr(smart_ptr<U, Policy> &&rhs) : pointer(rhs.pointer)
215 {
216 OSPTR_LOG("Move construct smart_ptr with compatible %p\n", rhs.pointer);
217 rhs.pointer = nullptr;
218 }
219
220 template<class U>
221 smart_ptr &
222 operator=(smart_ptr<U, Policy> &&rhs)
223 {
224 OSPTR_LOG("Move assign smart_ptr replacing %p with compatible %p\n", pointer, rhs.pointer);
225 smart_ptr(os::move(rhs)).swap(*this);
226 return *this;
227 }
228#endif
229
230/*
231 * Destructor - decreases the object's reference count
232 */
233 ~smart_ptr()
234 {
235 OSPTR_LOG("Destroy smart_ptr with %p\n", pointer);
236 if (pointer) {
237 _release(pointer);
238 }
239 }
240
241/*
242 * Create a new object of type T and wrap it in a smart_ptr. The object will have
243 * a reference count of 1, so destruction of the smart_ptr will result in the
244 * object being freed if the smart_ptr wasn't copied first.
245 */
246 static inline smart_ptr
247 alloc()
248 {
249 return smart_ptr(_alloc(), no_retain);
250 }
251
252 void
253 reset()
254 {
255 smart_ptr().swap(*this);
256 }
257
258 T *
259 get() const
260 {
261 return pointer;
262 }
263
264 T **
265 get_for_out_param()
266 {
267 reset();
268 return &pointer;
269 }
270
271/*
272 * Take ownership of object from raw pointer
273 */
274 void
275 attach(T *&p)
276 {
277 OSPTR_LOG("Attach smart_ptr with %p\n", p);
278 smart_ptr(p, no_retain).swap(*this);
279 }
280
281 void
282 attach(T *&&p)
283 {
284 OSPTR_LOG("Move attach smart_ptr with %p\n", p);
285 smart_ptr(os::move(p), no_retain).swap(*this);
286 }
287
288/* Return and drop ownership of pointer with NO release() */
289 T *
290 detach()
291 {
292 OSPTR_LOG("Detach smart_ptr with %p\n", pointer);
293 T *ret = pointer;
294 pointer = nullptr;
295 return ret;
296 }
297
298 T *
299 operator->() const
300 {
301 OSPTR_LOG("Dereference smart_ptr with %p\n", pointer);
302 return pointer;
303 }
304
305 explicit
306 operator bool() const
307 {
308 return pointer != nullptr;
309 }
310
311 inline void
312 swap(smart_ptr &p)
313 {
314 T *temp = pointer;
315 pointer = p.pointer;
316 p.pointer = temp;
317 }
318
319/* swap pointers to the same type but with different policies */
320 template<class OtherPolicy>
321 void
322 swap(smart_ptr<T, OtherPolicy> &p)
323 {
324 if (p.pointer) {
325 _retain(p.pointer);
326 }
327 if (pointer) {
328 smart_ptr<T, OtherPolicy>::_retain(pointer);
329 }
330
331 T *temp = pointer;
332 pointer = p.pointer;
333 p.pointer = temp;
334
335 if (p.pointer) {
336 _release(p.pointer);
337 }
338 if (pointer) {
339 smart_ptr<T, OtherPolicy>::_release(pointer);
340 }
341 }
342
343 template<class U>
344 smart_ptr<U, Policy>
345 const_pointer_cast() const &
346 {
347 OSPTR_LOG("const_pointer_cast smart_ptr with %p\n", pointer);
348 return smart_ptr<U, Policy>(const_cast<U *>(pointer));
349 }
350
351 template <class U>
352 smart_ptr<U, Policy>
353 const_pointer_cast() &&
354 {
355 OSPTR_LOG("const_pointer_cast move smart_ptr with %p\n", pointer);
356 U *newPointer = const_cast<U *>(detach());
357 return smart_ptr<U, Policy>(os::move(newPointer), no_retain);
358 }
359
360 template <class U>
361 smart_ptr<U, Policy>
362 static_pointer_cast() const &
363 {
364 OSPTR_LOG("static_pointer_cast smart_ptr with %p\n", pointer);
365 return smart_ptr<U, Policy>(static_cast<U *>(pointer));
366 }
367
368 template <class U>
369 smart_ptr<U, Policy>
370 static_pointer_cast() &&
371 {
372 OSPTR_LOG("static_pointer_cast move smart_ptr with %p\n", pointer);
373 return smart_ptr<U, Policy>(static_cast<U *>(detach()), no_retain);
374 }
375
376 template <class U>
377 smart_ptr<U, Policy>
378 dynamic_pointer_cast() const &
379 {
380 OSPTR_LOG("dynamic_pointer_cast smart_ptr with %p\n", pointer);
381 return smart_ptr<U, Policy>(Policy::template dyn_cast<T, U>(pointer));
382 }
383
384 template <class U>
385 smart_ptr<U, Policy>
386 dynamic_pointer_cast() &&
387 {
388 OSPTR_LOG("dynamic_pointer_cast move smart_ptr with %p\n", pointer);
389 U *newPointer = Policy::template dyn_cast<T, U>(pointer);
390
391 if (newPointer != nullptr) {
392 detach();
393 } else {
394 reset();
395 }
396 return smart_ptr<U, Policy>(os::move(newPointer), no_retain);
397 }
398
399private:
400 static inline void
401 _retain(T *obj)
402 {
403 OSPTR_LOG(" %s with %p\n", __FUNCTION__, obj);
404 Policy::retain(obj);
405 }
406
407 static inline void
408 _release(T *obj)
409 {
410 OSPTR_LOG(" %s with %p\n", __FUNCTION__, obj);
411 Policy::release(obj);
412 }
413
414 static inline T *
415 _alloc()
416 {
417 OSPTR_LOG(" %s\n", __FUNCTION__);
418 return Policy::template alloc<T>();
419 }
420
421 T *pointer;
422};
423
424/*
425 * Comparison
426 */
427
428template<class T, class Policy>
429inline bool
430operator==(smart_ptr<T, Policy> const &a, smart_ptr<T, Policy> const &b)
431{
432 return a.get() == b.get();
433}
434
435template<class T, class Policy>
436inline bool
437operator!=(smart_ptr<T, Policy> const &a, smart_ptr<T, Policy> const &b)
438{
439 return a.get() != b.get();
440}
441
442template<class A, class A_policy, class B, class B_policy>
443inline bool
444operator==(smart_ptr<A, A_policy> const &a, smart_ptr<B, B_policy> const &b)
445{
446 return a.get() == b.get();
447}
448
449template<class A, class A_policy, class B, class B_policy>
450inline bool
451operator!=(smart_ptr<A, A_policy> const &a, smart_ptr<B, B_policy> const &b)
452{
453 return a.get() != b.get();
454}
455
456/*
457 * Comparison with nullptr
458 */
459
460#if OS_HAS_NULLPTR
461template<class T, class Policy>
462inline bool
463operator==(smart_ptr<T, Policy> const &p, os::nullptr_t)
464{
465 return p.get() == nullptr;
466}
467
468template<class T, class Policy> inline bool
469operator==(os::nullptr_t, smart_ptr<T, Policy> const &p)
470{
471 return p.get() == nullptr;
472}
473
474template<class T, class Policy>
475inline bool
476operator!=(smart_ptr<T, Policy> const &p, os::nullptr_t)
477{
478 return p.get() != nullptr;
479}
480
481template<class T, class Policy>
482inline bool
483operator!=(os::nullptr_t, smart_ptr<T, Policy> const &p)
484{
485 return p.get() != nullptr;
486}
487#endif
488
489/*
490 * Comparison with raw pointer
491 */
492
493template<class T, class Policy>
494inline bool
495operator==(smart_ptr<T, Policy> const &p, const os::remove_const_t<T> *other)
496{
497 return p.get() == other;
498}
499
500template<class T, class Policy>
501inline bool
502operator==(const os::remove_const_t<T> *other, smart_ptr<T, Policy> const &p)
503{
504 return other == p.get();
505}
506
507template<class T, class Policy>
508inline bool
509operator!=(smart_ptr<T, Policy> const &p, const os::remove_const_t<T> *other)
510{
511 return p.get() != other;
512}
513
514template<class T, class Policy>
515inline bool
516operator!=(const os::remove_const_t<T> *other, smart_ptr<T, Policy> const &p)
517{
518 return other != p.get();
519}
520};
521
522#pragma clang diagnostic pop
523#endif /* _OS_SMART_POINTER_H */