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

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

cpp: added hash support for smart pointers

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