]> git.saurik.com Git - apple/xnu.git/blob - libkern/os/smart_ptr.h
xnu-6153.11.26.tar.gz
[apple/xnu.git] / libkern / os / smart_ptr.h
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
29 namespace os {
30 static struct no_retain_t {} no_retain;
31
32 template<class T, class Policy>
33 class OS_TRIVIAL_ABI smart_ptr
34 {
35 template<class U, class OtherPolicy> friend class smart_ptr;
36
37 public:
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
399 private:
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
428 template<class T, class Policy>
429 inline bool
430 operator==(smart_ptr<T, Policy> const &a, smart_ptr<T, Policy> const &b)
431 {
432 return a.get() == b.get();
433 }
434
435 template<class T, class Policy>
436 inline bool
437 operator!=(smart_ptr<T, Policy> const &a, smart_ptr<T, Policy> const &b)
438 {
439 return a.get() != b.get();
440 }
441
442 template<class A, class A_policy, class B, class B_policy>
443 inline bool
444 operator==(smart_ptr<A, A_policy> const &a, smart_ptr<B, B_policy> const &b)
445 {
446 return a.get() == b.get();
447 }
448
449 template<class A, class A_policy, class B, class B_policy>
450 inline bool
451 operator!=(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
461 template<class T, class Policy>
462 inline bool
463 operator==(smart_ptr<T, Policy> const &p, os::nullptr_t)
464 {
465 return p.get() == nullptr;
466 }
467
468 template<class T, class Policy> inline bool
469 operator==(os::nullptr_t, smart_ptr<T, Policy> const &p)
470 {
471 return p.get() == nullptr;
472 }
473
474 template<class T, class Policy>
475 inline bool
476 operator!=(smart_ptr<T, Policy> const &p, os::nullptr_t)
477 {
478 return p.get() != nullptr;
479 }
480
481 template<class T, class Policy>
482 inline bool
483 operator!=(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
493 template<class T, class Policy>
494 inline bool
495 operator==(smart_ptr<T, Policy> const &p, const os::remove_const_t<T> *other)
496 {
497 return p.get() == other;
498 }
499
500 template<class T, class Policy>
501 inline bool
502 operator==(const os::remove_const_t<T> *other, smart_ptr<T, Policy> const &p)
503 {
504 return other == p.get();
505 }
506
507 template<class T, class Policy>
508 inline bool
509 operator!=(smart_ptr<T, Policy> const &p, const os::remove_const_t<T> *other)
510 {
511 return p.get() != other;
512 }
513
514 template<class T, class Policy>
515 inline bool
516 operator!=(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 */