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

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

cpp: added missing uses_allocator metafunction and deleted redundant (and wrong) forward declaration of uses_allocator in the tuple header

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