]>
Commit | Line | Data |
---|---|---|
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 | ||
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 */ |