source: mainline/uspace/lib/cpp/include/internal/memory/unique_ptr.hpp@ 032565d

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 032565d was 032565d, checked in by Dzejrou <dzejrou@…>, 7 years ago

cpp: remove impl/memory.hpp and moved its contents to internal/memory/

  • Property mode set to 100644
File size: 17.6 KB
Line 
1/*
2 * Copyright (c) 2018 Jaroslav Jindrak
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#ifndef LIBCPP_INTERNAL_MEMORY_UNIQUE_PTR
30#define LIBCPP_INTERNAL_MEMORY_UNIQUE_PTR
31
32#include <internal/aux.hpp>
33#include <internal/functional/hash.hpp>
34#include <type_traits>
35#include <utility>
36
37namespace std
38{
39 /**
40 * 20.8, smart pointers:
41 */
42
43 template<class T>
44 struct default_delete
45 {
46 default_delete() noexcept = default;
47
48 template<class U, class = enable_if_t<is_convertible_v<U*, T*>, void>>
49 default_delete(const default_delete<U>&) noexcept
50 { /* DUMMY BODY */ }
51
52 template<class U>
53 void operator()(U* ptr)
54 {
55 delete ptr;
56 }
57 };
58
59 template<class T>
60 struct default_delete<T[]>
61 {
62 default_delete() noexcept = default;
63
64 template<class U, class = enable_if_t<is_convertible_v<U(*)[], T(*)[]>, void>>
65 default_delete(const default_delete<U[]>&) noexcept
66 { /* DUMMY BODY */ }
67
68 template<class U, class = enable_if_t<is_convertible_v<U(*)[], T(*)[]>, void>>
69 void operator()(U* ptr)
70 {
71 delete[] ptr;
72 }
73 };
74
75 template<class T, class D = default_delete<T>>
76 class unique_ptr;
77
78 namespace aux
79 {
80 template<class P, class D, class = void>
81 struct get_unique_pointer: type_is<typename P::element_type*>
82 { /* DUMMY BODY */ };
83
84 template<class P, class D>
85 struct get_unique_pointer<P, D, void_t<typename remove_reference_t<D>::pointer>>
86 : type_is<typename remove_reference_t<D>::pointer>
87 { /* DUMMY BODY */ };
88 }
89
90 template<class T, class D>
91 class unique_ptr
92 {
93 public:
94 using element_type = T;
95 using deleter_type = D;
96 using pointer = typename aux::get_unique_pointer<unique_ptr<T, D>, D>::type;
97
98 /**
99 * 20.8.1.2.1, constructors:
100 */
101
102 constexpr unique_ptr() noexcept
103 : ptr_{}, deleter_{}
104 { /* DUMMY BODY */ }
105
106 explicit unique_ptr(pointer ptr) noexcept
107 : ptr_{ptr}, deleter_{}
108 { /* DUMMY BODY */ }
109
110 unique_ptr(pointer ptr, /* TODO */ int d) noexcept;
111
112 unique_ptr(pointer ptr, /* TODO */ char d) noexcept;
113
114 unique_ptr(unique_ptr&& other)
115 : ptr_{move(other.ptr_)}, deleter_{forward<deleter_type>(other.deleter_)}
116 {
117 other.ptr_ = nullptr;
118 }
119
120 constexpr unique_ptr(nullptr_t)
121 : unique_ptr{}
122 { /* DUMMY BODY */ }
123
124 template<
125 class U, class E,
126 class = enable_if_t<
127 is_convertible_v<
128 typename unique_ptr<U, E>::pointer,
129 pointer
130 >, void
131 >
132 >
133 unique_ptr(unique_ptr<U, E>&& other) noexcept
134 : ptr_{move(other.ptr_)}, deleter_{forward<D>(other.deleter_)}
135 {
136 other.ptr_ = nullptr;
137 }
138
139 /**
140 * 20.8.1.2.2, destructor:
141 */
142
143 ~unique_ptr()
144 {
145 if (ptr_)
146 deleter_(ptr_);
147 }
148
149 /**
150 * 20.8.1.2.3, assignment:
151 */
152
153 unique_ptr& operator=(unique_ptr&& rhs) noexcept
154 {
155 reset(rhs.release());
156 deleter_ = forward<deleter_type>(rhs.get_deleter());
157
158 return *this;
159 }
160
161 template<
162 class U, class E,
163 class = enable_if_t<
164 is_convertible_v<
165 typename unique_ptr<U, E>::pointer,
166 pointer
167 > && !is_array_v<U>, void
168 >
169 >
170 unique_ptr& operator=(unique_ptr<U, E>&& rhs) noexcept
171 {
172 reset(rhs.release());
173 deleter_ = forward<E>(rhs.get_deleter());
174
175 return *this;
176 }
177
178 unique_ptr& operator=(nullptr_t) noexcept
179 {
180 reset();
181
182 return *this;
183 }
184
185 /**
186 * 20.8.1.2.4, observers:
187 */
188
189 add_lvalue_reference_t<element_type> operator*() const
190 {
191 return *ptr_;
192 }
193
194 pointer operator->() const noexcept
195 {
196 return ptr_;
197 }
198
199 pointer get() const noexcept
200 {
201 return ptr_;
202 }
203
204 deleter_type& get_deleter() noexcept
205 {
206 return deleter_;
207 }
208
209 const deleter_type& get_deleter() const noexcept
210 {
211 return deleter_;
212 }
213
214 explicit operator bool() const noexcept
215 {
216 return ptr_ != nullptr;
217 }
218
219 /**
220 * 20.8.1.2.5, modifiers:
221 */
222
223 pointer release() noexcept
224 {
225 auto ret = ptr_;
226 ptr_ = nullptr;
227
228 return ret;
229 }
230
231 void reset(pointer ptr = pointer{}) noexcept
232 {
233 /**
234 * Note: Order is significant, deleter may delete
235 * *this.
236 */
237 auto old = ptr_;
238 ptr_ = ptr;
239
240 if (old)
241 deleter_(old);
242 }
243
244 void swap(unique_ptr& other) noexcept
245 {
246 std::swap(ptr_, other.ptr_);
247 std::swap(deleter_, other.deleter_);
248 }
249
250 unique_ptr(const unique_ptr&) = delete;
251 unique_ptr& operator=(const unique_ptr&) = delete;
252
253 private:
254 pointer ptr_;
255 deleter_type deleter_;
256 };
257
258 namespace aux
259 {
260 template<class From, class To>
261 struct is_convertible_array: is_convertible<From(*)[], To(*)[]>
262 { /* DUMMY BODY */ };
263
264 template<class From, class To>
265 inline constexpr bool is_convertible_array_v = is_convertible_array<From, To>::value;
266
267 template<class T, class D, class U, class E>
268 struct compatible_ptrs: integral_constant<
269 bool,
270 is_array_v<U> && is_same_v<
271 typename unique_ptr<T, D>::pointer,
272 typename unique_ptr<T, D>::element_type*
273 > && is_same_v<
274 typename unique_ptr<U, E>::pointer,
275 typename unique_ptr<U, E>::element_type*
276 > && is_convertible_array_v<
277 typename unique_ptr<T, D>::element_type,
278 typename unique_ptr<U, E>::element_type
279 > && ((is_reference_v<D> && is_same_v<D, E>) ||
280 (!is_reference_v<D> && is_convertible_v<E, D>))
281 >
282 { /* DUMMY BODY */ };
283
284 template<class T, class D, class U, class E>
285 inline constexpr bool compatible_ptrs_v = compatible_ptrs<T, D, U, E>::value;
286 }
287
288 template<class T, class D>
289 class unique_ptr<T[], D>
290 {
291 public:
292 using element_type = T;
293 using deleter_type = D;
294 using pointer = typename aux::get_unique_pointer<unique_ptr<T[], D>, D>::type;
295
296 /**
297 * 20.8.1.3.1, constructors:
298 */
299
300 constexpr unique_ptr() noexcept
301 : ptr_{}, deleter_{}
302 { /* DUMMY BODY */ }
303
304 template<
305 class U,
306 class = enable_if_t<
307 is_same_v<U, T> || aux::is_convertible_array_v<U, T>, void
308 >
309 >
310 explicit unique_ptr(U ptr) noexcept
311 : ptr_{ptr}, deleter_{}
312 { /* DUMMY BODY */ }
313
314 template<
315 class U, class E,
316 class = enable_if_t<aux::compatible_ptrs_v<T, D, U, E>, void>
317 >
318 unique_ptr(U ptr, /* TODO */ int d) noexcept;
319
320 template<
321 class U, class E,
322 class = enable_if_t<aux::compatible_ptrs_v<T, D, U, E>, void>
323 >
324 unique_ptr(U ptr, /* TODO */ char d) noexcept;
325
326 unique_ptr(unique_ptr&& other) noexcept
327 : ptr_{move(other.ptr_)}, deleter_{forward<deleter_type>(other.deleter_)}
328 {
329 other.ptr_ = nullptr;
330 }
331
332 template<
333 class U, class E,
334 class = enable_if_t<
335 is_same_v<U, pointer> ||
336 (is_same_v<pointer, element_type*> && is_pointer_v<U> &&
337 aux::is_convertible_array_v<remove_pointer_t<U>, element_type>),
338 void
339 >
340 >
341 unique_ptr(unique_ptr<U, E>&& other) noexcept
342 : ptr_{move(other.ptr_)}, deleter_{forward<D>(other.deleter_)}
343 {
344 other.ptr_ = nullptr;
345 }
346
347 constexpr unique_ptr(nullptr_t) noexcept
348 : unique_ptr{}
349 { /* DUMMY BODY */ }
350
351 ~unique_ptr()
352 {
353 if (ptr_)
354 deleter_(ptr_);
355 }
356
357 /**
358 * 20.8.1.3.2, assignment:
359 */
360
361 unique_ptr& operator=(unique_ptr&& rhs) noexcept
362 {
363 reset(rhs.release());
364 deleter_ = forward<deleter_type>(rhs.get_deleter());
365
366 return *this;
367 }
368
369 template<
370 class U, class E,
371 class = enable_if_t<aux::compatible_ptrs_v<T, D, U, E>, void>
372 >
373 unique_ptr& operator=(unique_ptr<U, E>&& rhs) noexcept
374 {
375 reset(rhs.release());
376 deleter_ = forward<E>(rhs.get_deleter());
377
378 return *this;
379 }
380
381 unique_ptr& operator=(nullptr_t) noexcept
382 {
383 reset();
384
385 return *this;
386 }
387
388 /**
389 * 20.8.1.3.3, observers:
390 */
391
392 element_type& operator[](size_t idx) const
393 {
394 return ptr_[idx];
395 }
396
397 pointer get() const noexcept
398 {
399 return ptr_;
400 }
401
402 deleter_type& get_deleter() noexcept
403 {
404 return deleter_;
405 }
406
407 const deleter_type& get_deleter() const noexcept
408 {
409 return deleter_;
410 }
411
412 explicit operator bool() const noexcept
413 {
414 return ptr_ != nullptr;
415 }
416
417 /**
418 * 20.8.1.3.4, modifiers:
419 */
420
421 pointer release() noexcept
422 {
423 auto ret = ptr_;
424 ptr_ = nullptr;
425
426 return ret;
427 }
428
429 template<
430 class U,
431 class = enable_if_t<
432 is_same_v<U, pointer> ||
433 (is_same_v<pointer, element_type*> && is_pointer_v<U> &&
434 aux::is_convertible_array_v<remove_pointer_t<U>, element_type>),
435 void
436 >
437 >
438 void reset(U ptr) noexcept
439 {
440 /**
441 * Note: Order is significant, deleter may delete
442 * *this.
443 */
444 auto old = ptr_;
445 ptr_ = ptr;
446
447 if (old)
448 deleter_(old);
449 }
450
451 void reset(nullptr_t = nullptr) noexcept
452 {
453 reset(pointer{});
454 }
455
456 void swap(unique_ptr& other) noexcept
457 {
458 std::swap(ptr_, other.ptr_);
459 std::swap(deleter_, other.deleter_);
460 }
461
462 unique_ptr(const unique_ptr&) = delete;
463 unique_ptr& operator=(const unique_ptr&) = delete;
464
465 private:
466 pointer ptr_;
467 deleter_type deleter_;
468 };
469
470 namespace aux
471 {
472 template<class T>
473 struct is_unbound_array: false_type
474 { /* DUMMY BODY */ };
475
476 template<class T>
477 struct is_unbound_array<T[]>: true_type
478 { /* DUMMY BODY */ };
479
480 template<class T>
481 struct is_bound_array: false_type
482 { /* DUMMY BODY */ };
483
484 template<class T, size_t N>
485 struct is_bound_array<T[N]>: true_type
486 { /* DUMMY BODY */ };
487 }
488
489 template<
490 class T, class... Args,
491 class = enable_if_t<!is_array_v<T>, void>
492 >
493 unique_ptr<T> make_unique(Args&&... args)
494 {
495 return unique_ptr<T>(new T(forward<Args>(args)...));
496 }
497
498 template<
499 class T, class = enable_if_t<aux::is_unbound_array<T>::value, void>
500 >
501 unique_ptr<T> make_unique(size_t n)
502 {
503 return unique_ptr<T>(new remove_extent_t<T>[n]());
504 }
505
506 template<
507 class T, class... Args,
508 class = enable_if_t<aux::is_bound_array<T>::value, void>
509 >
510 void make_unique(Args&&...) = delete;
511
512 template<class T, class D>
513 void swap(unique_ptr<T, D>& lhs, unique_ptr<T, D>& rhs) noexcept
514 {
515 lhs.swap(rhs);
516 }
517
518 template<class T1, class D1, class T2, class D2>
519 bool operator==(const unique_ptr<T1, D1>& lhs,
520 const unique_ptr<T2, D2>& rhs)
521 {
522 return lhs.get() == rhs.get();
523 }
524
525 template<class T1, class D1, class T2, class D2>
526 bool operator!=(const unique_ptr<T1, D1>& lhs,
527 const unique_ptr<T2, D2>& rhs)
528 {
529 return lhs.get() != rhs.get();
530 }
531
532 template<class T1, class D1, class T2, class D2>
533 bool operator<(const unique_ptr<T1, D1>& lhs,
534 const unique_ptr<T2, D2>& rhs)
535 {
536 return lhs.get() < rhs.get();
537 }
538
539 template<class T1, class D1, class T2, class D2>
540 bool operator<=(const unique_ptr<T1, D1>& lhs,
541 const unique_ptr<T2, D2>& rhs)
542 {
543 return !(rhs < lhs);
544 }
545
546 template<class T1, class D1, class T2, class D2>
547 bool operator>(const unique_ptr<T1, D1>& lhs,
548 const unique_ptr<T2, D2>& rhs)
549 {
550 return rhs < lhs;
551 }
552
553 template<class T1, class D1, class T2, class D2>
554 bool operator>=(const unique_ptr<T1, D1>& lhs,
555 const unique_ptr<T2, D2>& rhs)
556 {
557 return !(lhs < rhs);
558 }
559
560 template<class T, class D>
561 bool operator==(const unique_ptr<T, D>& ptr, nullptr_t) noexcept
562 {
563 return !ptr;
564 }
565
566 template<class T, class D>
567 bool operator==(nullptr_t, const unique_ptr<T, D>& ptr) noexcept
568 {
569 return !ptr;
570 }
571
572 template<class T, class D>
573 bool operator!=(const unique_ptr<T, D>& ptr, nullptr_t) noexcept
574 {
575 return static_cast<bool>(ptr);
576 }
577
578 template<class T, class D>
579 bool operator!=(nullptr_t, const unique_ptr<T, D>& ptr) noexcept
580 {
581 return static_cast<bool>(ptr);
582 }
583
584 template<class T, class D>
585 bool operator<(const unique_ptr<T, D>& ptr, nullptr_t)
586 {
587 return ptr.get() < nullptr;
588 }
589
590 template<class T, class D>
591 bool operator<(nullptr_t, const unique_ptr<T, D>& ptr)
592 {
593 return nullptr < ptr.get();
594 }
595
596 template<class T, class D>
597 bool operator<=(const unique_ptr<T, D>& ptr, nullptr_t)
598 {
599 return !(nullptr < ptr);
600 }
601
602 template<class T, class D>
603 bool operator<=(nullptr_t, const unique_ptr<T, D>& ptr)
604 {
605 return !(ptr < nullptr);
606 }
607
608 template<class T, class D>
609 bool operator>(const unique_ptr<T, D>& ptr, nullptr_t)
610 {
611 return nullptr < ptr;
612 }
613
614 template<class T, class D>
615 bool operator>(nullptr_t, const unique_ptr<T, D>& ptr)
616 {
617 return ptr < nullptr;
618 }
619
620 template<class T, class D>
621 bool operator>=(const unique_ptr<T, D>& ptr, nullptr_t)
622 {
623 return !(ptr < nullptr);
624 }
625
626 template<class T, class D>
627 bool operator>=(nullptr_t, const unique_ptr<T, D>& ptr)
628 {
629 return !(nullptr < ptr);
630 }
631
632 /**
633 * 20.8.2.7, smart pointer hash support:
634 */
635
636 template<class T, class D>
637 struct hash<unique_ptr<T, D>>
638 {
639 size_t operator()(const unique_ptr<T, D>& ptr) const noexcept
640 {
641 return hash<typename unique_ptr<T, D>::pointer>{}(ptr.get());
642 }
643
644 using argument_type = unique_ptr<T, D>;
645 using result_type = size_t;
646 };
647}
648
649#endif
Note: See TracBrowser for help on using the repository browser.