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

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

cpp: added allocator argument tag

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