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

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

cpp: moved addressof to an internal header to avoid circular dependencies, added temporary buffers and raw storage iterator

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