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

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

cpp: added unique_ptr

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