source: mainline/uspace/lib/cpp/include/impl/memory.hpp@ 5735b111

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

cpp: moved allocator arg outside of memory.hpp to avoid circular dependencies in shared_ptr

  • Property mode set to 100644
File size: 31.0 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_MEMORY
30#define LIBCPP_MEMORY
31
32#include <internal/aux.hpp>
33#include <internal/memory/allocator_arg.hpp>
34#include <internal/memory/addressof.hpp>
35#include <iterator>
36#include <new>
37#include <type_traits>
38#include <utility>
39
40namespace std
41{
42 /**
43 * 20.7.3, pointer traits:
44 */
45
46 template<class Ptr>
47 struct pointer_traits
48 {
49 using pointer = Ptr;
50 // TODO: element type, difference type
51
52 // TODO: this is conditional, see standard
53 template<class U>
54 using rebind = typename Ptr::template rebind<U>;
55 };
56
57 /**
58 * 20.7.7, uses_allocator:
59 */
60
61 namespace aux
62 {
63 template<class T, class = void>
64 struct has_allocator_type: false_type
65 { /* DUMMY BODY */ };
66
67 template<class T>
68 struct has_allocator_type<T, void_t<typename T::allocator_type>>
69 : true_type
70 { /* DUMMY BODY */ };
71 }
72
73 template<class T, class Alloc, class = void>
74 struct uses_allocator
75 : aux::value_is<
76 bool, aux::has_allocator_type<T>::value && is_convertible_v<
77 Alloc, typename T::allocator_type
78 >
79 >
80 { /* DUMMY BODY */ };
81
82 /**
83 * 20.7.8, allocator traits:
84 */
85
86 namespace aux
87 {
88 /**
89 * The standard mandates that we reuse type from allocators
90 * *if* they are defined or that we use something different.
91 * These structures help us alternate between those by
92 * using SFINAE.
93 * TODO: Create tests for these!
94 */
95
96 template<class T, class = void>
97 struct get_pointer: aux::type_is<typename T::value_type*>
98 { /* DUMMY BODY */ };
99
100 template<class T>
101 struct get_pointer<T, void_t<typename T::pointer>>
102 : aux::type_is<typename T::pointer>
103 { /* DUMMY BODY */ };
104
105 template<class T, class Ptr, class = void>
106 struct get_const_pointer
107 : aux::type_is<typename pointer_traits<Ptr>::template rebind<const typename T::value_type>>
108 { /* DUMMY BODY */ };
109
110 template<class T, class Ptr>
111 struct get_const_pointer<T, Ptr, void_t<typename T::const_pointer>>
112 : aux::type_is<typename T::const_pointer>
113 { /* DUMMY BODY */ };
114
115 template<class T, class Ptr, class = void>
116 struct get_void_pointer
117 : aux::type_is<typename pointer_traits<Ptr>::template rebind<void>>
118 { /* DUMMY BODY */ };
119
120 template<class T, class Ptr>
121 struct get_void_pointer<T, Ptr, void_t<typename T::void_pointer>>
122 : aux::type_is<typename T::void_pointer>
123 { /* DUMMY BODY */ };
124
125 template<class T, class Ptr, class = void>
126 struct get_const_void_pointer
127 : aux::type_is<typename pointer_traits<Ptr>::template rebind<const void>>
128 { /* DUMMY BODY */ };
129
130 template<class T, class Ptr>
131 struct get_const_void_pointer<T, Ptr, void_t<typename T::const_void_pointer>>
132 : aux::type_is<typename T::const_void_pointer>
133 { /* DUMMY BODY */ };
134
135 template<class T, class Ptr, class = void>
136 struct get_difference_type
137 : aux::type_is<typename pointer_traits<Ptr>::difference_type>
138 { /* DUMMY BODY */ };
139
140 template<class T, class Ptr>
141 struct get_difference_type<T, Ptr, void_t<typename T::difference_type>>
142 : aux::type_is<typename T::difference_type>
143 { /* DUMMY BODY */ };
144
145 template<class T, class Difference, class = void>
146 struct get_size_type: aux::type_is<make_unsigned_t<Difference>>
147 { /* DUMMY BODY */ };
148
149 template<class T, class Difference>
150 struct get_size_type<T, Difference, void_t<typename T::size_type>>
151 : aux::type_is<typename T::size_type>
152 { /* DUMMY BODY */ };
153
154 template<class T, class = void>
155 struct get_copy_propagate: aux::type_is<false_type>
156 { /* DUMMY BODY */ };
157
158 template<class T>
159 struct get_copy_propagate<T, void_t<typename T::propagate_on_container_copy_assignment>>
160 : aux::type_is<typename T::propagate_on_container_copy_assignment>
161 { /* DUMMY BODY */ };
162
163 template<class T, class = void>
164 struct get_move_propagate: aux::type_is<false_type>
165 { /* DUMMY BODY */ };
166
167 template<class T>
168 struct get_move_propagate<T, void_t<typename T::propagate_on_container_move_assignment>>
169 : aux::type_is<typename T::propagate_on_container_move_assignment>
170 { /* DUMMY BODY */ };
171
172 template<class T, class = void>
173 struct get_swap_propagate: aux::type_is<false_type>
174 { /* DUMMY BODY */ };
175
176 template<class T>
177 struct get_swap_propagate<T, void_t<typename T::propagate_on_container_swap>>
178 : aux::type_is<typename T::propagate_on_container_swap>
179 { /* DUMMY BODY */ };
180
181 template<class T, class = void>
182 struct get_always_equal: aux::type_is<typename is_empty<T>::type>
183 { /* DUMMY BODY */ };
184
185 template<class T>
186 struct get_always_equal<T, void_t<typename T::is_always_equal>>
187 : aux::type_is<typename T::is_always_equal>
188 { /* DUMMY BODY */ };
189
190 template<class Alloc, class T, class = void>
191 struct get_rebind_other
192 { /* DUMMY BODY */ };
193
194 template<class Alloc, class T>
195 struct get_rebind_other<Alloc, T, void_t<typename Alloc::template rebind<T>::other>>
196 : aux::type_is<typename Alloc::template rebind<T>::other>
197 { /* DUMMY BODY */ };
198
199 /* TODO: How am I suppose to do this?!
200 template<template<class T, class... Args> class Alloc>
201 struct get_rebind_args;
202 */
203
204 template<class Alloc, class T>
205 struct get_rebind_args: aux::type_is<typename get_rebind_other<Alloc, T>::type>
206 { /* DUMMY BODY */ };
207 }
208
209 template<class Alloc>
210 struct allocator_traits
211 {
212 using allocator_type = Alloc;
213
214 using value_type = typename Alloc::value_type;
215 using pointer = typename aux::get_pointer<Alloc>::type;
216 using const_pointer = typename aux::get_const_pointer<Alloc, pointer>::type;
217 // TODO: fix void pointer typedefs
218 /* using void_pointer = typename aux::get_void_pointer<Alloc, pointer>::type; */
219 /* using const_void_pointer = typename aux::get_const_void_pointer<Alloc, pointer>::type; */
220 using void_pointer = void*;
221 using const_void_pointer = const void*;
222 using difference_type = typename aux::get_difference_type<Alloc, pointer>::type;
223 using size_type = typename aux::get_size_type<Alloc, difference_type>::type;
224
225 using propagate_on_container_copy_assignment = typename aux::get_copy_propagate<Alloc>::type;
226 using propagate_on_container_move_assignment = typename aux::get_move_propagate<Alloc>::type;
227 using propagate_on_container_swap = typename aux::get_swap_propagate<Alloc>::type;
228 using is_always_equal = typename aux::get_always_equal<Alloc>::type;
229
230 template<class T>
231 using rebind_alloc = typename aux::get_rebind_args<Alloc, T>;
232
233 template<class T>
234 using rebind_traits = allocator_traits<rebind_alloc<T>>;
235
236 static pointer allocate(Alloc& alloc, size_type n)
237 {
238 return alloc.allocate(n);
239 }
240
241 static pointer allocate(Alloc& alloc, size_type n, const_void_pointer hint)
242 { // TODO: this when it's well formed, otherwise alloc.allocate(n)
243 return alloc.allocate(n, hint);
244 }
245
246 static void deallocate(Alloc& alloc, pointer ptr, size_type n)
247 {
248 alloc.deallocate(ptr, n);
249 }
250
251 template<class T, class... Args>
252 static void construct(Alloc& alloc, T* ptr, Args&&... args)
253 {
254 // TODO: why wasn't this implemented? check standard for remarks
255 alloc.construct(ptr, forward<Args>(args)...);
256 }
257
258 template<class T>
259 static void destroy(Alloc& alloc, T* ptr)
260 {
261 // TODO: implement
262 }
263
264 static size_type max_size(const Alloc& alloc) noexcept
265 {
266 // TODO: implement
267 return 0;
268 }
269
270 static Alloc select_on_container_copy_construction(const Alloc& alloc)
271 {
272 // TODO: implement
273 return Alloc{};
274 }
275 };
276
277 /**
278 * 20.7.9, the default allocator
279 */
280
281 template<class T>
282 class allocator;
283
284 template<>
285 class allocator<void>
286 {
287 public:
288 using pointer = void*;
289 using const_pointer = const void*;
290 using value_type = void;
291
292 template<class U>
293 struct rebind
294 {
295 using other = allocator<U>;
296 };
297 };
298
299 template<class T>
300 T* addressof(T& x) noexcept;
301
302 template<class T>
303 class allocator
304 {
305 public:
306 using size_type = size_t;
307 using difference_type = ptrdiff_t;
308 using pointer = T*;
309 using const_pointer = const T*;
310 using reference = T&;
311 using const_reference = const T&;
312 using value_type = T;
313
314 template<class U>
315 struct rebind
316 {
317 using other = allocator<U>;
318 };
319
320 using propagate_on_container_move_assignment = true_type;
321 using is_always_equal = true_type;
322
323 allocator() noexcept = default;
324
325 allocator(const allocator&) noexcept = default;
326
327 template<class U>
328 allocator(const allocator<U>&) noexcept
329 {
330 // TODO: implement
331 }
332
333 ~allocator() = default;
334
335 pointer address(reference x) const noexcept
336 {
337 return addressof(x);
338 }
339
340 const_pointer address(const_reference x) const noexcept
341 {
342 return addressof(x);
343 }
344
345 pointer allocate(size_type n, allocator<void>::const_pointer hint = 0)
346 {
347 /**
348 * Note: The usage of hint is unspecified.
349 * TODO: Check HelenOS hint allocation capabilities.
350 * TODO: assert that n < max_size()
351 */
352 return static_cast<pointer>(::operator new(n * sizeof(value_type)));
353 }
354
355 void deallocate(pointer ptr, size_type n)
356 {
357 ::operator delete(ptr, n);
358 }
359
360 size_type max_size() const noexcept
361 { // TODO: implement, max argument to allocate
362 return 0xFFFFFFFF;
363 }
364
365 template<class U, class... Args>
366 void construct(U* ptr, Args&&... args)
367 {
368 ::new((void*)ptr) U(forward<Args>(args)...);
369 }
370
371 template<class U>
372 void destroy(U* ptr)
373 {
374 ptr->~U();
375 }
376 };
377
378 template<class T1, class T2>
379 bool operator==(const allocator<T1>&, const allocator<T2>&) noexcept
380 {
381 return true;
382 }
383
384 template<class T1, class T2>
385 bool operator!=(const allocator<T1>&, const allocator<T2>&) noexcept
386 {
387 return false;
388 }
389
390 /**
391 * 20.7.10, raw storage iterator:
392 */
393
394 template<class OutputIterator, class T>
395 class raw_storage_iterator: public iterator<output_iterator_tag, void, void, void, void>
396 {
397 public:
398 explicit raw_storage_iterator(OutputIterator it)
399 : it_{it}
400 { /* DUMMY BODY */ }
401
402 raw_storage_iterator& operator*()
403 {
404 return *this;
405 }
406
407 raw_storage_iterator& operator=(const T& element)
408 {
409 new(it_) T{element};
410
411 return *this;
412 }
413
414 raw_storage_iterator& operator++()
415 {
416 ++it_;
417
418 return *this;
419 }
420
421 raw_storage_iterator operator++(int)
422 {
423 return raw_storage_iterator{it_++};
424 }
425
426 private:
427 OutputIterator it_;
428 };
429
430 /**
431 * 20.7.11, temporary buffers:
432 */
433
434 template<class T>
435 pair<T*, ptrdiff_t> get_temporary_buffer(ptrdiff_t n) noexcept
436 {
437 T* res{};
438
439 while (n > 0)
440 {
441 res = (T*)malloc(n * sizeof(T));
442
443 if (res)
444 return make_pair(res, n);
445
446 --n;
447 }
448
449 return make_pair(nullptr, ptrdiff_t{});
450 }
451
452 template<class T>
453 void return_temporary_buffer(T* ptr)
454 {
455 free(ptr);
456 }
457
458 /**
459 * 20.7.12, specialized algorithms:
460 */
461
462 template<class Iterator>
463 struct iterator_traits;
464
465 template<class InputIterator, class ForwardIterator>
466 ForwardIterator unitialized_copy(
467 InputIterator first, InputIterator last,
468 ForwardIterator result
469 )
470 {
471 for (; first != last; ++first, ++result)
472 ::new (static_cast<void*>(&*result)) typename iterator_traits<ForwardIterator>::value_type(*first);
473
474 return result;
475 }
476
477 template<class InputIterator, class Size, class ForwardIterator>
478 ForwardIterator unitialized_copy_n(
479 InputIterator first, Size n, ForwardIterator result
480 )
481 {
482 for (; n > 0; ++first, --n, ++result)
483 ::new (static_cast<void*>(&*result)) typename iterator_traits<ForwardIterator>::value_type(*first);
484
485 return result;
486 }
487
488 template<class ForwardIterator, class T>
489 void unitialized_fill(
490 ForwardIterator first, ForwardIterator last, const T& x
491 )
492 {
493 for (; first != last; ++first)
494 ::new (static_cast<void*>(&*first)) typename iterator_traits<ForwardIterator>::value_type(x);
495 }
496
497 template<class ForwardIterator, class Size, class T>
498 ForwardIterator unitialized_fill_n(
499 ForwardIterator first, Size n, const T& x
500 )
501 {
502 for (; n > 0; ++first, --n)
503 ::new (static_cast<void*>(&*first)) typename iterator_traits<ForwardIterator>::value_type(x);
504
505 return first;
506 }
507
508 /**
509 * 20.8, smart pointers:
510 */
511
512 template<class T>
513 struct default_delete
514 {
515 default_delete() noexcept = default;
516
517 template<class U, class = enable_if_t<is_convertible_v<U*, T*>, void>>
518 default_delete(const default_delete<U>&) noexcept
519 { /* DUMMY BODY */ }
520
521 template<class U>
522 void operator()(U* ptr)
523 {
524 delete ptr;
525 }
526 };
527
528 template<class T>
529 struct default_delete<T[]>
530 {
531 default_delete() noexcept = default;
532
533 template<class U, class = enable_if_t<is_convertible_v<U(*)[], T(*)[]>, void>>
534 default_delete(const default_delete<U[]>&) noexcept
535 { /* DUMMY BODY */ }
536
537 template<class U, class = enable_if_t<is_convertible_v<U(*)[], T(*)[]>, void>>
538 void operator()(U* ptr)
539 {
540 delete[] ptr;
541 }
542 };
543
544 template<class T, class D = default_delete<T>>
545 class unique_ptr;
546
547 namespace aux
548 {
549 template<class P, class D, class = void>
550 struct get_unique_pointer: type_is<typename P::element_type*>
551 { /* DUMMY BODY */ };
552
553 template<class P, class D>
554 struct get_unique_pointer<P, D, void_t<typename remove_reference_t<D>::pointer>>
555 : type_is<typename remove_reference_t<D>::pointer>
556 { /* DUMMY BODY */ };
557 }
558
559 template<class T, class D>
560 class unique_ptr
561 {
562 public:
563 using element_type = T;
564 using deleter_type = D;
565 using pointer = typename aux::get_unique_pointer<unique_ptr<T, D>, D>::type;
566
567 /**
568 * 20.8.1.2.1, constructors:
569 */
570
571 constexpr unique_ptr() noexcept
572 : ptr_{}, deleter_{}
573 { /* DUMMY BODY */ }
574
575 explicit unique_ptr(pointer ptr) noexcept
576 : ptr_{ptr}, deleter_{}
577 { /* DUMMY BODY */ }
578
579 unique_ptr(pointer ptr, /* TODO */ int d) noexcept;
580
581 unique_ptr(pointer ptr, /* TODO */ char d) noexcept;
582
583 unique_ptr(unique_ptr&& other)
584 : ptr_{move(other.ptr_)}, deleter_{forward<deleter_type>(other.deleter_)}
585 {
586 other.ptr_ = nullptr;
587 }
588
589 constexpr unique_ptr(nullptr_t)
590 : unique_ptr{}
591 { /* DUMMY BODY */ }
592
593 template<
594 class U, class E,
595 class = enable_if_t<
596 is_convertible_v<
597 typename unique_ptr<U, E>::pointer,
598 pointer
599 >, void
600 >
601 >
602 unique_ptr(unique_ptr<U, E>&& other) noexcept
603 : ptr_{move(other.ptr_)}, deleter_{forward<D>(other.deleter_)}
604 {
605 other.ptr_ = nullptr;
606 }
607
608 /**
609 * 20.8.1.2.2, destructor:
610 */
611
612 ~unique_ptr()
613 {
614 if (ptr_)
615 deleter_(ptr_);
616 }
617
618 /**
619 * 20.8.1.2.3, assignment:
620 */
621
622 unique_ptr& operator=(unique_ptr&& rhs) noexcept
623 {
624 reset(rhs.release());
625 deleter_ = forward<deleter_type>(rhs.get_deleter());
626
627 return *this;
628 }
629
630 template<
631 class U, class E,
632 class = enable_if_t<
633 is_convertible_v<
634 typename unique_ptr<U, E>::pointer,
635 pointer
636 > && !is_array_v<U>, void
637 >
638 >
639 unique_ptr& operator=(unique_ptr<U, E>&& rhs) noexcept
640 {
641 reset(rhs.release());
642 deleter_ = forward<E>(rhs.get_deleter());
643
644 return *this;
645 }
646
647 unique_ptr& operator=(nullptr_t) noexcept
648 {
649 reset();
650
651 return *this;
652 }
653
654 /**
655 * 20.8.1.2.4, observers:
656 */
657
658 add_lvalue_reference_t<element_type> operator*() const
659 {
660 return *ptr_;
661 }
662
663 pointer operator->() const noexcept
664 {
665 return ptr_;
666 }
667
668 pointer get() const noexcept
669 {
670 return ptr_;
671 }
672
673 deleter_type& get_deleter() noexcept
674 {
675 return deleter_;
676 }
677
678 const deleter_type& get_deleter() const noexcept
679 {
680 return deleter_;
681 }
682
683 explicit operator bool() const noexcept
684 {
685 return ptr_ != nullptr;
686 }
687
688 /**
689 * 20.8.1.2.5, modifiers:
690 */
691
692 pointer release() noexcept
693 {
694 auto ret = ptr_;
695 ptr_ = nullptr;
696
697 return ret;
698 }
699
700 void reset(pointer ptr = pointer{}) noexcept
701 {
702 /**
703 * Note: Order is significant, deleter may delete
704 * *this.
705 */
706 auto old = ptr_;
707 ptr_ = ptr;
708
709 if (old)
710 deleter_(old);
711 }
712
713 void swap(unique_ptr& other) noexcept
714 {
715 std::swap(ptr_, other.ptr_);
716 std::swap(deleter_, other.deleter_);
717 }
718
719 unique_ptr(const unique_ptr&) = delete;
720 unique_ptr& operator=(const unique_ptr&) = delete;
721
722 private:
723 pointer ptr_;
724 deleter_type deleter_;
725 };
726
727 namespace aux
728 {
729 template<class From, class To>
730 struct is_convertible_array: is_convertible<From(*)[], To(*)[]>
731 { /* DUMMY BODY */ };
732
733 template<class From, class To>
734 inline constexpr bool is_convertible_array_v = is_convertible_array<From, To>::value;
735
736 template<class T, class D, class U, class E>
737 struct compatible_ptrs: integral_constant<
738 bool,
739 is_array_v<U> && is_same_v<
740 typename unique_ptr<T, D>::pointer,
741 typename unique_ptr<T, D>::element_type*
742 > && is_same_v<
743 typename unique_ptr<U, E>::pointer,
744 typename unique_ptr<U, E>::element_type*
745 > && is_convertible_array_v<
746 typename unique_ptr<T, D>::element_type,
747 typename unique_ptr<U, E>::element_type
748 > && ((is_reference_v<D> && is_same_v<D, E>) ||
749 (!is_reference_v<D> && is_convertible_v<E, D>))
750 >
751 { /* DUMMY BODY */ };
752
753 template<class T, class D, class U, class E>
754 inline constexpr bool compatible_ptrs_v = compatible_ptrs<T, D, U, E>::value;
755 }
756
757 template<class T, class D>
758 class unique_ptr<T[], D>
759 {
760 public:
761 using element_type = T;
762 using deleter_type = D;
763 using pointer = typename aux::get_unique_pointer<unique_ptr<T[], D>, D>::type;
764
765 /**
766 * 20.8.1.3.1, constructors:
767 */
768
769 constexpr unique_ptr() noexcept
770 : ptr_{}, deleter_{}
771 { /* DUMMY BODY */ }
772
773 template<
774 class U,
775 class = enable_if_t<
776 is_same_v<U, T> || aux::is_convertible_array_v<U, T>, void
777 >
778 >
779 explicit unique_ptr(U ptr) noexcept
780 : ptr_{ptr}, deleter_{}
781 { /* DUMMY BODY */ }
782
783 template<
784 class U, class E,
785 class = enable_if_t<aux::compatible_ptrs_v<T, D, U, E>, void>
786 >
787 unique_ptr(U ptr, /* TODO */ int d) noexcept;
788
789 template<
790 class U, class E,
791 class = enable_if_t<aux::compatible_ptrs_v<T, D, U, E>, void>
792 >
793 unique_ptr(U ptr, /* TODO */ char d) noexcept;
794
795 unique_ptr(unique_ptr&& other) noexcept
796 : ptr_{move(other.ptr_)}, deleter_{forward<deleter_type>(other.deleter_)}
797 {
798 other.ptr_ = nullptr;
799 }
800
801 template<
802 class U, class E,
803 class = enable_if_t<
804 is_same_v<U, pointer> ||
805 (is_same_v<pointer, element_type*> && is_pointer_v<U> &&
806 aux::is_convertible_array_v<remove_pointer_t<U>, element_type>),
807 void
808 >
809 >
810 unique_ptr(unique_ptr<U, E>&& other) noexcept
811 : ptr_{move(other.ptr_)}, deleter_{forward<D>(other.deleter_)}
812 {
813 other.ptr_ = nullptr;
814 }
815
816 constexpr unique_ptr(nullptr_t) noexcept
817 : unique_ptr{}
818 { /* DUMMY BODY */ }
819
820 ~unique_ptr()
821 {
822 if (ptr_)
823 deleter_(ptr_);
824 }
825
826 /**
827 * 20.8.1.3.2, assignment:
828 */
829
830 unique_ptr& operator=(unique_ptr&& rhs) noexcept
831 {
832 reset(rhs.release());
833 deleter_ = forward<deleter_type>(rhs.get_deleter());
834
835 return *this;
836 }
837
838 template<
839 class U, class E,
840 class = enable_if_t<aux::compatible_ptrs_v<T, D, U, E>, void>
841 >
842 unique_ptr& operator=(unique_ptr<U, E>&& rhs) noexcept
843 {
844 reset(rhs.release());
845 deleter_ = forward<E>(rhs.get_deleter());
846
847 return *this;
848 }
849
850 unique_ptr& operator=(nullptr_t) noexcept
851 {
852 reset();
853
854 return *this;
855 }
856
857 /**
858 * 20.8.1.3.3, observers:
859 */
860
861 element_type& operator[](size_t idx) const
862 {
863 return ptr_[idx];
864 }
865
866 pointer get() const noexcept
867 {
868 return ptr_;
869 }
870
871 deleter_type& get_deleter() noexcept
872 {
873 return deleter_;
874 }
875
876 const deleter_type& get_deleter() const noexcept
877 {
878 return deleter_;
879 }
880
881 explicit operator bool() const noexcept
882 {
883 return ptr_ != nullptr;
884 }
885
886 /**
887 * 20.8.1.3.4, modifiers:
888 */
889
890 pointer release() noexcept
891 {
892 auto ret = ptr_;
893 ptr_ = nullptr;
894
895 return ret;
896 }
897
898 template<
899 class U,
900 class = enable_if_t<
901 is_same_v<U, pointer> ||
902 (is_same_v<pointer, element_type*> && is_pointer_v<U> &&
903 aux::is_convertible_array_v<remove_pointer_t<U>, element_type>),
904 void
905 >
906 >
907 void reset(U ptr) noexcept
908 {
909 /**
910 * Note: Order is significant, deleter may delete
911 * *this.
912 */
913 auto old = ptr_;
914 ptr_ = ptr;
915
916 if (old)
917 deleter_(old);
918 }
919
920 void reset(nullptr_t = nullptr) noexcept
921 {
922 reset(pointer{});
923 }
924
925 void swap(unique_ptr& other) noexcept
926 {
927 std::swap(ptr_, other.ptr_);
928 std::swap(deleter_, other.deleter_);
929 }
930
931 unique_ptr(const unique_ptr&) = delete;
932 unique_ptr& operator=(const unique_ptr&) = delete;
933
934 private:
935 pointer ptr_;
936 deleter_type deleter_;
937 };
938
939 namespace aux
940 {
941 template<class T>
942 struct is_unbound_array: false_type
943 { /* DUMMY BODY */ };
944
945 template<class T>
946 struct is_unbound_array<T[]>: true_type
947 { /* DUMMY BODY */ };
948
949 template<class T>
950 struct is_bound_array: false_type
951 { /* DUMMY BODY */ };
952
953 template<class T, size_t N>
954 struct is_bound_array<T[N]>: true_type
955 { /* DUMMY BODY */ };
956 }
957
958 template<
959 class T, class... Args,
960 class = enable_if_t<!is_array_v<T>, void>
961 >
962 unique_ptr<T> make_unique(Args&&... args)
963 {
964 return unique_ptr<T>(new T(forward<Args>(args)...));
965 }
966
967 template<
968 class T, class = enable_if_t<aux::is_unbound_array<T>::value, void>
969 >
970 unique_ptr<T> make_unique(size_t n)
971 {
972 return unique_ptr<T>(new remove_extent_t<T>[n]());
973 }
974
975 template<
976 class T, class... Args,
977 class = enable_if_t<aux::is_bound_array<T>::value, void>
978 >
979 void make_unique(Args&&...) = delete;
980
981 template<class T, class D>
982 void swap(unique_ptr<T, D>& lhs, unique_ptr<T, D>& rhs) noexcept
983 {
984 lhs.swap(rhs);
985 }
986
987 template<class T1, class D1, class T2, class D2>
988 bool operator==(const unique_ptr<T1, D1>& lhs,
989 const unique_ptr<T2, D2>& rhs)
990 {
991 return lhs.get() == rhs.get();
992 }
993
994 template<class T1, class D1, class T2, class D2>
995 bool operator!=(const unique_ptr<T1, D1>& lhs,
996 const unique_ptr<T2, D2>& rhs)
997 {
998 return lhs.get() != rhs.get();
999 }
1000
1001 template<class T1, class D1, class T2, class D2>
1002 bool operator<(const unique_ptr<T1, D1>& lhs,
1003 const unique_ptr<T2, D2>& rhs)
1004 {
1005 return lhs.get() < rhs.get();
1006 }
1007
1008 template<class T1, class D1, class T2, class D2>
1009 bool operator<=(const unique_ptr<T1, D1>& lhs,
1010 const unique_ptr<T2, D2>& rhs)
1011 {
1012 return !(rhs < lhs);
1013 }
1014
1015 template<class T1, class D1, class T2, class D2>
1016 bool operator>(const unique_ptr<T1, D1>& lhs,
1017 const unique_ptr<T2, D2>& rhs)
1018 {
1019 return rhs < lhs;
1020 }
1021
1022 template<class T1, class D1, class T2, class D2>
1023 bool operator>=(const unique_ptr<T1, D1>& lhs,
1024 const unique_ptr<T2, D2>& rhs)
1025 {
1026 return !(lhs < rhs);
1027 }
1028
1029 template<class T, class D>
1030 bool operator==(const unique_ptr<T, D>& ptr, nullptr_t) noexcept
1031 {
1032 return !ptr;
1033 }
1034
1035 template<class T, class D>
1036 bool operator==(nullptr_t, const unique_ptr<T, D>& ptr) noexcept
1037 {
1038 return !ptr;
1039 }
1040
1041 template<class T, class D>
1042 bool operator!=(const unique_ptr<T, D>& ptr, nullptr_t) noexcept
1043 {
1044 return static_cast<bool>(ptr);
1045 }
1046
1047 template<class T, class D>
1048 bool operator!=(nullptr_t, const unique_ptr<T, D>& ptr) noexcept
1049 {
1050 return static_cast<bool>(ptr);
1051 }
1052
1053 template<class T, class D>
1054 bool operator<(const unique_ptr<T, D>& ptr, nullptr_t)
1055 {
1056 return ptr.get() < nullptr;
1057 }
1058
1059 template<class T, class D>
1060 bool operator<(nullptr_t, const unique_ptr<T, D>& ptr)
1061 {
1062 return nullptr < ptr.get();
1063 }
1064
1065 template<class T, class D>
1066 bool operator<=(const unique_ptr<T, D>& ptr, nullptr_t)
1067 {
1068 return !(nullptr < ptr);
1069 }
1070
1071 template<class T, class D>
1072 bool operator<=(nullptr_t, const unique_ptr<T, D>& ptr)
1073 {
1074 return !(ptr < nullptr);
1075 }
1076
1077 template<class T, class D>
1078 bool operator>(const unique_ptr<T, D>& ptr, nullptr_t)
1079 {
1080 return nullptr < ptr;
1081 }
1082
1083 template<class T, class D>
1084 bool operator>(nullptr_t, const unique_ptr<T, D>& ptr)
1085 {
1086 return ptr < nullptr;
1087 }
1088
1089 template<class T, class D>
1090 bool operator>=(const unique_ptr<T, D>& ptr, nullptr_t)
1091 {
1092 return !(ptr < nullptr);
1093 }
1094
1095 template<class T, class D>
1096 bool operator>=(nullptr_t, const unique_ptr<T, D>& ptr)
1097 {
1098 return !(nullptr < ptr);
1099 }
1100}
1101
1102#endif
Note: See TracBrowser for help on using the repository browser.