RPNX::DataStructures
Header-only C++ data structures and supporting utilities.
Loading...
Searching...
No Matches
annex.hpp
1// Copyright (c) 2026 Ryan P. Nicholl <rnicholl@protonmail.com>
2
3#ifndef RPNXDATASTRUCTURES_ANNEX_HPP
4#define RPNXDATASTRUCTURES_ANNEX_HPP
5
6#include <compare>
7#include <initializer_list>
8#include <memory>
9#include <optional>
10#include <type_traits>
11#include <utility>
12
13namespace rpnx
14{
30 template < typename T, typename Alloc = std::allocator< T > >
31 class annex
32 {
33 static_assert(!std::is_reference_v< T >, "rpnx::annex does not support reference types");
34 static_assert(!std::is_void_v< T >, "rpnx::annex does not support void");
35
36 public:
40 using value_type = T;
41
45 using allocator_type = typename std::allocator_traits< Alloc >::template rebind_alloc< T >;
46
47 private:
48 using alloc_traits = std::allocator_traits< allocator_type >;
49
50 T* m_value = nullptr;
51 [[no_unique_address]] allocator_type m_alloc;
52
53 template < typename... Args >
54 T* allocate_construct(Args&&... args)
55 {
56 T* ptr = alloc_traits::allocate(m_alloc, 1);
57
58 try
59 {
60 alloc_traits::construct(m_alloc, ptr, std::forward< Args >(args)...);
61 }
62 catch (...)
63 {
64 alloc_traits::deallocate(m_alloc, ptr, 1);
65 throw;
66 }
67
68 return ptr;
69 }
70
71 void destroy_deallocate() noexcept
72 {
73 if (m_value == nullptr)
74 {
75 return;
76 }
77
78 alloc_traits::destroy(m_alloc, m_value);
79 alloc_traits::deallocate(m_alloc, m_value, 1);
80 m_value = nullptr;
81 }
82
83 template < typename U >
84 void assign_value(U&& value)
85 {
86 if (m_value != nullptr)
87 {
88 **this = std::forward< U >(value);
89 }
90 else
91 {
92 m_value = allocate_construct(std::forward< U >(value));
93 }
94 }
95
96 public:
100 constexpr annex() noexcept(std::is_nothrow_default_constructible_v< allocator_type >) = default;
101
105 constexpr annex(std::nullopt_t) noexcept(std::is_nothrow_default_constructible_v< allocator_type >)
106 {
107 }
108
113 explicit annex(allocator_type const& alloc) noexcept : m_alloc(alloc)
114 {
115 }
116
121 annex(std::allocator_arg_t, allocator_type const& alloc) noexcept : m_alloc(alloc)
122 {
123 }
124
133 annex(annex const& other) : m_alloc(alloc_traits::select_on_container_copy_construction(other.m_alloc))
134 {
135 if (other.has_value())
136 {
137 m_value = allocate_construct(*other);
138 }
139 }
140
148 annex(annex&& other) noexcept(std::is_nothrow_move_constructible_v< allocator_type >) : m_value(other.m_value), m_alloc(std::move(other.m_alloc))
149 {
150 other.m_value = nullptr;
151 }
152
158 template < typename U = T, typename = std::enable_if_t< std::is_constructible_v< T, U&& > && !std::is_same_v< std::decay_t< U >, annex > && !std::is_same_v< std::decay_t< U >, std::in_place_t > && !std::is_same_v< std::decay_t< U >, std::nullopt_t > && !std::is_same_v< std::decay_t< U >, allocator_type > > >
160 {
161 m_value = allocate_construct(std::forward< U >(value));
162 }
163
169 template < typename... Args >
170 explicit annex(std::in_place_t, Args&&... args)
171 {
172 m_value = allocate_construct(std::forward< Args >(args)...);
173 }
174
182 template < typename U, typename... Args >
183 explicit annex(std::in_place_t, std::initializer_list< U > init, Args&&... args)
184 {
185 m_value = allocate_construct(init, std::forward< Args >(args)...);
186 }
187
194 template < typename... Args >
195 annex(std::allocator_arg_t, allocator_type const& alloc, std::in_place_t, Args&&... args) : m_alloc(alloc)
196 {
197 m_value = allocate_construct(std::forward< Args >(args)...);
198 }
199
208 template < typename U, typename... Args >
209 annex(std::allocator_arg_t, allocator_type const& alloc, std::in_place_t, std::initializer_list< U > init, Args&&... args) : m_alloc(alloc)
210 {
211 m_value = allocate_construct(init, std::forward< Args >(args)...);
212 }
213
218 {
219 destroy_deallocate();
220 }
221
226 annex& operator=(std::nullopt_t) noexcept
227 {
228 reset();
229 return *this;
230 }
231
237 annex& operator=(annex const& other)
238 {
239 if (this == &other)
240 {
241 return *this;
242 }
243
244 if constexpr (alloc_traits::propagate_on_container_copy_assignment::value)
245 {
246 if (m_alloc != other.m_alloc)
247 {
248 reset();
249 }
250
251 m_alloc = other.m_alloc;
252 }
253
254 if (other.has_value())
255 {
256 assign_value(*other);
257 }
258 else
259 {
260 reset();
261 }
262
263 return *this;
264 }
265
276 annex& operator=(annex&& other) noexcept(alloc_traits::propagate_on_container_move_assignment::value && std::is_nothrow_move_assignable_v< allocator_type >)
277 {
278 if (this == &other)
279 {
280 return *this;
281 }
282
283 if constexpr (alloc_traits::propagate_on_container_move_assignment::value)
284 {
285 reset();
286 m_alloc = std::move(other.m_alloc);
287 m_value = other.m_value;
288 other.m_value = nullptr;
289 }
290 else
291 {
292 if (m_alloc == other.m_alloc)
293 {
294 reset();
295 m_value = other.m_value;
296 other.m_value = nullptr;
297 }
298 else if (other.has_value())
299 {
300 assign_value(std::move(*other));
301 }
302 else
303 {
304 reset();
305 }
306 }
307
308 return *this;
309 }
310
321 template < typename U = T, typename = std::enable_if_t< std::is_constructible_v< T, U&& > && std::is_assignable_v< T&, U&& > && !std::is_same_v< std::decay_t< U >, annex > && !std::is_same_v< std::decay_t< U >, std::nullopt_t > > >
323 {
324 assign_value(std::forward< U >(value));
325 return *this;
326 }
327
333 constexpr T const* operator->() const noexcept
334 {
335 return m_value;
336 }
337
343 constexpr T* operator->() noexcept
344 {
345 return m_value;
346 }
347
353 constexpr T const& operator*() const& noexcept
354 {
355 return *m_value;
356 }
357
363 constexpr T& operator*() & noexcept
364 {
365 return *m_value;
366 }
367
373 constexpr T const&& operator*() const&& noexcept
374 {
375 return std::move(*m_value);
376 }
377
383 constexpr T&& operator*() && noexcept
384 {
385 return std::move(*m_value);
386 }
387
392 constexpr explicit operator bool() const noexcept
393 {
394 return has_value();
395 }
396
401 constexpr bool has_value() const noexcept
402 {
403 return m_value != nullptr;
404 }
405
411 T& value() &
412 {
413 if (!has_value())
414 {
415 throw std::bad_optional_access();
416 }
417
418 return **this;
419 }
420
426 T const& value() const&
427 {
428 if (!has_value())
429 {
430 throw std::bad_optional_access();
431 }
432
433 return **this;
434 }
435
441 T&& value() &&
442 {
443 if (!has_value())
444 {
445 throw std::bad_optional_access();
446 }
447
448 return std::move(**this);
449 }
450
456 T const&& value() const&&
457 {
458 if (!has_value())
459 {
460 throw std::bad_optional_access();
461 }
462
463 return std::move(**this);
464 }
465
472 template < typename U >
473 constexpr T value_or(U&& default_value) const&
474 {
475 static_assert(std::is_copy_constructible_v< T >);
476 static_assert(std::is_convertible_v< U&&, T >);
477 return has_value() ? **this : static_cast< T >(std::forward< U >(default_value));
478 }
479
486 template < typename U >
487 constexpr T value_or(U&& default_value) &&
488 {
489 static_assert(std::is_move_constructible_v< T >);
490 static_assert(std::is_convertible_v< U&&, T >);
491 return has_value() ? std::move(**this) : static_cast< T >(std::forward< U >(default_value));
492 }
493
498 void swap(annex& other) noexcept(alloc_traits::propagate_on_container_swap::value && std::is_nothrow_swappable_v< allocator_type > && std::is_nothrow_swappable_v< T >)
499 {
500 using std::swap;
501
502 if constexpr (alloc_traits::propagate_on_container_swap::value)
503 {
504 swap(m_alloc, other.m_alloc);
505 swap(m_value, other.m_value);
506 }
507 else if (has_value() && other.has_value())
508 {
509 swap(**this, *other);
510 }
511 else if (has_value())
512 {
513 other.m_value = other.allocate_construct(std::move(**this));
514 reset();
515 }
516 else if (other.has_value())
517 {
518 m_value = allocate_construct(std::move(*other));
519 other.reset();
520 }
521 }
522
526 void reset() noexcept
527 {
528 destroy_deallocate();
529 }
530
537 template < typename... Args >
538 T& emplace(Args&&... args)
539 {
540 reset();
541 m_value = allocate_construct(std::forward< Args >(args)...);
542 return **this;
543 }
544
553 template < typename U, typename... Args >
554 T& emplace(std::initializer_list< U > init, Args&&... args)
555 {
556 reset();
557 m_value = allocate_construct(init, std::forward< Args >(args)...);
558 return **this;
559 }
560
566 {
567 return m_alloc;
568 }
569 };
570
576 template < typename T, typename Alloc >
577 void swap(annex< T, Alloc >& lhs, annex< T, Alloc >& rhs) noexcept(noexcept(lhs.swap(rhs)))
578 {
579 lhs.swap(rhs);
580 }
581
590
597 template < typename T, typename Alloc >
598 bool operator==(annex< T, Alloc > const& lhs, annex< T, Alloc > const& rhs)
599 {
600 if (lhs.has_value() != rhs.has_value())
601 {
602 return false;
603 }
604
605 return !lhs.has_value() || *lhs == *rhs;
606 }
607
614 template < typename T, typename Alloc >
615 bool operator!=(annex< T, Alloc > const& lhs, annex< T, Alloc > const& rhs)
616 {
617 return !(lhs == rhs);
618 }
619
626 template < typename T, typename Alloc >
627 bool operator<(annex< T, Alloc > const& lhs, annex< T, Alloc > const& rhs)
628 {
629 return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs);
630 }
631
638 template < typename T, typename Alloc >
639 bool operator>(annex< T, Alloc > const& lhs, annex< T, Alloc > const& rhs)
640 {
641 return rhs < lhs;
642 }
643
650 template < typename T, typename Alloc >
651 bool operator<=(annex< T, Alloc > const& lhs, annex< T, Alloc > const& rhs)
652 {
653 return !(rhs < lhs);
654 }
655
662 template < typename T, typename Alloc >
663 bool operator>=(annex< T, Alloc > const& lhs, annex< T, Alloc > const& rhs)
664 {
665 return !(lhs < rhs);
666 }
667
674 template < typename T, typename Alloc >
675 requires requires(T const& lhs, T const& rhs) { lhs <=> rhs; }
676 auto operator<=>(annex< T, Alloc > const& lhs, annex< T, Alloc > const& rhs) -> decltype(*lhs <=> *rhs)
677 {
678 if (lhs.has_value() && rhs.has_value())
679 {
680 return *lhs <=> *rhs;
681 }
682
683 if (lhs.has_value())
684 {
685 return std::strong_ordering::greater;
686 }
687
688 if (rhs.has_value())
689 {
690 return std::strong_ordering::less;
691 }
692
693 return std::strong_ordering::equal;
694 }
695
697
705
711 template < typename T, typename Alloc >
712 bool operator==(annex< T, Alloc > const& lhs, std::nullopt_t) noexcept
713 {
714 return !lhs.has_value();
715 }
716
722 template < typename T, typename Alloc >
723 bool operator==(std::nullopt_t, annex< T, Alloc > const& rhs) noexcept
724 {
725 return !rhs.has_value();
726 }
727
733 template < typename T, typename Alloc >
734 bool operator!=(annex< T, Alloc > const& lhs, std::nullopt_t) noexcept
735 {
736 return lhs.has_value();
737 }
738
744 template < typename T, typename Alloc >
745 bool operator!=(std::nullopt_t, annex< T, Alloc > const& rhs) noexcept
746 {
747 return rhs.has_value();
748 }
749
754 template < typename T, typename Alloc >
755 bool operator<(annex< T, Alloc > const&, std::nullopt_t) noexcept
756 {
757 return false;
758 }
759
765 template < typename T, typename Alloc >
766 bool operator<(std::nullopt_t, annex< T, Alloc > const& rhs) noexcept
767 {
768 return rhs.has_value();
769 }
770
776 template < typename T, typename Alloc >
777 bool operator<=(annex< T, Alloc > const& lhs, std::nullopt_t) noexcept
778 {
779 return !lhs.has_value();
780 }
781
786 template < typename T, typename Alloc >
787 bool operator<=(std::nullopt_t, annex< T, Alloc > const&) noexcept
788 {
789 return true;
790 }
791
797 template < typename T, typename Alloc >
798 bool operator>(annex< T, Alloc > const& lhs, std::nullopt_t) noexcept
799 {
800 return lhs.has_value();
801 }
802
807 template < typename T, typename Alloc >
808 bool operator>(std::nullopt_t, annex< T, Alloc > const&) noexcept
809 {
810 return false;
811 }
812
817 template < typename T, typename Alloc >
818 bool operator>=(annex< T, Alloc > const&, std::nullopt_t) noexcept
819 {
820 return true;
821 }
822
828 template < typename T, typename Alloc >
829 bool operator>=(std::nullopt_t, annex< T, Alloc > const& rhs) noexcept
830 {
831 return !rhs.has_value();
832 }
833
839 template < typename T, typename Alloc >
840 std::strong_ordering operator<=>(annex< T, Alloc > const& lhs, std::nullopt_t) noexcept
841 {
842 return lhs.has_value() ? std::strong_ordering::greater : std::strong_ordering::equal;
843 }
844
850 template < typename T, typename Alloc >
851 std::strong_ordering operator<=>(std::nullopt_t, annex< T, Alloc > const& rhs) noexcept
852 {
853 return rhs.has_value() ? std::strong_ordering::less : std::strong_ordering::equal;
854 }
855
857
865
872 template < typename T, typename Alloc, typename U >
873 requires(!requires { typename U::value_type; typename U::allocator_type; } || !std::is_same_v< U, annex< typename U::value_type, typename U::allocator_type > >)
874 bool operator==(annex< T, Alloc > const& lhs, U const& rhs)
875 {
876 return lhs.has_value() ? *lhs == rhs : false;
877 }
878
885 template < typename T, typename Alloc, typename U >
886 requires(!requires { typename U::value_type; typename U::allocator_type; } || !std::is_same_v< U, annex< typename U::value_type, typename U::allocator_type > >)
887 bool operator==(U const& lhs, annex< T, Alloc > const& rhs)
888 {
889 return rhs.has_value() ? lhs == *rhs : false;
890 }
891
898 template < typename T, typename Alloc, typename U >
899 requires(!requires { typename U::value_type; typename U::allocator_type; } || !std::is_same_v< U, annex< typename U::value_type, typename U::allocator_type > >)
900 bool operator!=(annex< T, Alloc > const& lhs, U const& rhs)
901 {
902 return !(lhs == rhs);
903 }
904
911 template < typename T, typename Alloc, typename U >
912 requires(!requires { typename U::value_type; typename U::allocator_type; } || !std::is_same_v< U, annex< typename U::value_type, typename U::allocator_type > >)
913 bool operator!=(U const& lhs, annex< T, Alloc > const& rhs)
914 {
915 return !(lhs == rhs);
916 }
917
924 template < typename T, typename Alloc, typename U >
925 requires(!requires { typename U::value_type; typename U::allocator_type; } || !std::is_same_v< U, annex< typename U::value_type, typename U::allocator_type > >)
926 bool operator<(annex< T, Alloc > const& lhs, U const& rhs)
927 {
928 return lhs.has_value() ? *lhs < rhs : true;
929 }
930
937 template < typename T, typename Alloc, typename U >
938 requires(!requires { typename U::value_type; typename U::allocator_type; } || !std::is_same_v< U, annex< typename U::value_type, typename U::allocator_type > >)
939 bool operator<(U const& lhs, annex< T, Alloc > const& rhs)
940 {
941 return rhs.has_value() ? lhs < *rhs : false;
942 }
943
950 template < typename T, typename Alloc, typename U >
951 requires(!requires { typename U::value_type; typename U::allocator_type; } || !std::is_same_v< U, annex< typename U::value_type, typename U::allocator_type > >)
952 bool operator<=(annex< T, Alloc > const& lhs, U const& rhs)
953 {
954 return lhs.has_value() ? *lhs <= rhs : true;
955 }
956
963 template < typename T, typename Alloc, typename U >
964 requires(!requires { typename U::value_type; typename U::allocator_type; } || !std::is_same_v< U, annex< typename U::value_type, typename U::allocator_type > >)
965 bool operator<=(U const& lhs, annex< T, Alloc > const& rhs)
966 {
967 return rhs.has_value() ? lhs <= *rhs : false;
968 }
969
976 template < typename T, typename Alloc, typename U >
977 requires(!requires { typename U::value_type; typename U::allocator_type; } || !std::is_same_v< U, annex< typename U::value_type, typename U::allocator_type > >)
978 bool operator>(annex< T, Alloc > const& lhs, U const& rhs)
979 {
980 return lhs.has_value() ? *lhs > rhs : false;
981 }
982
989 template < typename T, typename Alloc, typename U >
990 requires(!requires { typename U::value_type; typename U::allocator_type; } || !std::is_same_v< U, annex< typename U::value_type, typename U::allocator_type > >)
991 bool operator>(U const& lhs, annex< T, Alloc > const& rhs)
992 {
993 return rhs.has_value() ? lhs > *rhs : true;
994 }
995
1002 template < typename T, typename Alloc, typename U >
1003 requires(!requires { typename U::value_type; typename U::allocator_type; } || !std::is_same_v< U, annex< typename U::value_type, typename U::allocator_type > >)
1004 bool operator>=(annex< T, Alloc > const& lhs, U const& rhs)
1005 {
1006 return lhs.has_value() ? *lhs >= rhs : false;
1007 }
1008
1015 template < typename T, typename Alloc, typename U >
1016 requires(!requires { typename U::value_type; typename U::allocator_type; } || !std::is_same_v< U, annex< typename U::value_type, typename U::allocator_type > >)
1017 bool operator>=(U const& lhs, annex< T, Alloc > const& rhs)
1018 {
1019 return rhs.has_value() ? lhs >= *rhs : true;
1020 }
1021
1028 template < typename T, typename Alloc, typename U >
1029 requires(!requires { typename U::value_type; typename U::allocator_type; } || !std::is_same_v< U, annex< typename U::value_type, typename U::allocator_type > >) && requires(T const& lhs, U const& rhs) { lhs <=> rhs; }
1030 auto operator<=>(annex< T, Alloc > const& lhs, U const& rhs) -> decltype(*lhs <=> rhs)
1031 {
1032 if (lhs.has_value())
1033 {
1034 return *lhs <=> rhs;
1035 }
1036
1037 return std::strong_ordering::less;
1038 }
1039
1046 template < typename T, typename Alloc, typename U >
1047 requires(!requires { typename U::value_type; typename U::allocator_type; } || !std::is_same_v< U, annex< typename U::value_type, typename U::allocator_type > >) && requires(U const& lhs, T const& rhs) { lhs <=> rhs; }
1048 auto operator<=>(U const& lhs, annex< T, Alloc > const& rhs) -> decltype(lhs <=> *rhs)
1049 {
1050 if (rhs.has_value())
1051 {
1052 return lhs <=> *rhs;
1053 }
1054
1055 return std::strong_ordering::greater;
1056 }
1057
1059
1066 template < typename T >
1068 {
1069 return annex< std::decay_t< T > >(std::forward< T >(value));
1070 }
1071
1079 template < typename T, typename... Args >
1080 annex< T > make_annex(Args&&... args)
1081 {
1082 return annex< T >(std::in_place, std::forward< Args >(args)...);
1083 }
1084
1094 template < typename T, typename U, typename... Args >
1095 annex< T > make_annex(std::initializer_list< U > init, Args&&... args)
1096 {
1097 return annex< T >(std::in_place, init, std::forward< Args >(args)...);
1098 }
1099} // namespace rpnx
1100
1101#endif // RPNXDATASTRUCTURES_ANNEX_HPP
Optional-like value container that stores its payload out of line.
Definition annex.hpp:32
constexpr T && operator*() &&noexcept
Returns an rvalue reference to the contained value.
Definition annex.hpp:383
T && value() &&
Returns the contained value as an rvalue reference.
Definition annex.hpp:441
annex(allocator_type const &alloc) noexcept
Constructs an empty annex using the specified allocator.
Definition annex.hpp:113
allocator_type get_allocator() const
Returns a copy of the allocator.
Definition annex.hpp:565
typename std::allocator_traits< Alloc >::template rebind_alloc< T > allocator_type
Allocator rebound to T.
Definition annex.hpp:45
annex & operator=(annex &&other) noexcept(alloc_traits::propagate_on_container_move_assignment::value &&std::is_nothrow_move_assignable_v< allocator_type >)
Move-assigns another annex.
Definition annex.hpp:276
annex(std::allocator_arg_t, allocator_type const &alloc, std::in_place_t, Args &&... args)
Constructs the contained value in place using the specified allocator.
Definition annex.hpp:195
annex & operator=(std::nullopt_t) noexcept
Assigns the empty state.
Definition annex.hpp:226
constexpr T value_or(U &&default_value) &&
Returns the contained value or a fallback.
Definition annex.hpp:487
constexpr T const & operator*() const &noexcept
Returns a const lvalue reference to the contained value.
Definition annex.hpp:353
void reset() noexcept
Destroys the contained value and makes the annex empty.
Definition annex.hpp:526
T & emplace(Args &&... args)
Replaces the contained value by constructing a new value in place.
Definition annex.hpp:538
constexpr T const * operator->() const noexcept
Returns a pointer to the contained value.
Definition annex.hpp:333
annex(std::allocator_arg_t, allocator_type const &alloc) noexcept
Constructs an empty annex using allocator-argument syntax.
Definition annex.hpp:121
annex & operator=(U &&value)
Assigns a value to the annex.
Definition annex.hpp:322
constexpr T const && operator*() const &&noexcept
Returns a const rvalue reference to the contained value.
Definition annex.hpp:373
~annex()
Destroys the contained value, if any, and releases its storage.
Definition annex.hpp:217
annex(std::in_place_t, Args &&... args)
Constructs the contained value in place.
Definition annex.hpp:170
constexpr bool has_value() const noexcept
Tests whether the annex contains a value.
Definition annex.hpp:401
annex(std::in_place_t, std::initializer_list< U > init, Args &&... args)
Constructs the contained value in place with an initializer list.
Definition annex.hpp:183
T const & value() const &
Returns the contained value.
Definition annex.hpp:426
annex & operator=(annex const &other)
Copy-assigns another annex.
Definition annex.hpp:237
constexpr T value_or(U &&default_value) const &
Returns the contained value or a fallback.
Definition annex.hpp:473
T & value() &
Returns the contained value.
Definition annex.hpp:411
annex(annex &&other) noexcept(std::is_nothrow_move_constructible_v< allocator_type >)
Move-constructs an annex by transferring its backing pointer.
Definition annex.hpp:148
constexpr T * operator->() noexcept
Returns a pointer to the contained value.
Definition annex.hpp:343
annex(U &&value)
Constructs an annex containing a value.
Definition annex.hpp:159
T & emplace(std::initializer_list< U > init, Args &&... args)
Replaces the contained value using an initializer list.
Definition annex.hpp:554
T value_type
The contained value type.
Definition annex.hpp:40
constexpr annex() noexcept(std::is_nothrow_default_constructible_v< allocator_type >)=default
Constructs an empty annex.
constexpr T & operator*() &noexcept
Returns an lvalue reference to the contained value.
Definition annex.hpp:363
annex(std::allocator_arg_t, allocator_type const &alloc, std::in_place_t, std::initializer_list< U > init, Args &&... args)
Constructs the contained value in place with an initializer list and allocator.
Definition annex.hpp:209
T const && value() const &&
Returns the contained value as a const rvalue reference.
Definition annex.hpp:456
void swap(annex &other) noexcept(alloc_traits::propagate_on_container_swap::value &&std::is_nothrow_swappable_v< allocator_type > &&std::is_nothrow_swappable_v< T >)
Swaps this annex with another annex.
Definition annex.hpp:498
annex(annex const &other)
Copy-constructs an annex.
Definition annex.hpp:133
Containers, iterator adapters, callable wrappers, and value utilities.
Definition annex.hpp:14
void swap(annex< T, Alloc > &lhs, annex< T, Alloc > &rhs) noexcept(noexcept(lhs.swap(rhs)))
Swaps two annex objects.
Definition annex.hpp:577
bool operator<=(annex< T, Alloc > const &lhs, annex< T, Alloc > const &rhs)
Orders two annex objects.
Definition annex.hpp:651
bool operator>=(annex< T, Alloc > const &lhs, annex< T, Alloc > const &rhs)
Orders two annex objects.
Definition annex.hpp:663
annex< std::decay_t< T > > make_annex(T &&value)
Constructs an annex containing a decayed copy of a value.
Definition annex.hpp:1067
bool operator<(annex< T, Alloc > const &lhs, annex< T, Alloc > const &rhs)
Orders two annex objects.
Definition annex.hpp:627
bool operator!=(annex< T, Alloc > const &lhs, annex< T, Alloc > const &rhs)
Compares two annex objects for inequality.
Definition annex.hpp:615
bool operator>(annex< T, Alloc > const &lhs, annex< T, Alloc > const &rhs)
Orders two annex objects.
Definition annex.hpp:639
auto operator<=>(annex< T, Alloc > const &lhs, annex< T, Alloc > const &rhs) -> decltype(*lhs<=> *rhs)
Three-way compares two annex objects when T supports <=>.
Definition annex.hpp:676
bool operator==(annex< T, Alloc > const &lhs, annex< T, Alloc > const &rhs)
Compares two annex objects for equality.
Definition annex.hpp:598