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

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

cpp: added missing construct to allocator traits

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