header_utils
Loading...
Searching...
No Matches
soptional.h
1
4
5#pragma once
6
7#include <optional>
8#include "cpp20.h"
9
10namespace ghassanpl
11{
12
13 template <typename T, T SENTINEL = T{}>
14 struct sentinel_optional
15 {
16 constexpr sentinel_optional() noexcept {}
17 constexpr sentinel_optional(std::nullopt_t) noexcept {}
18
19 template <class... TYPES, std::enable_if_t<std::is_constructible_v<T, TYPES...>, int> = 0>
20 constexpr explicit sentinel_optional(std::in_place_t, TYPES&&... args) noexcept(std::is_nothrow_constructible_v<T, TYPES...>)
21 : m_value(std::forward<TYPES>(args)...)
22 {
23 }
24
25 template <class U = T, std::enable_if_t<
26 !std::is_same_v<remove_cvref_t<U>, sentinel_optional> &&
27 !std::is_same_v<remove_cvref_t<U>, std::in_place_t> &&
28 !std::is_same_v<std::remove_cv_t<U>, bool> &&
29 std::is_constructible_v<T, U>
30 , int> = 0>
31 constexpr sentinel_optional(U&& right) noexcept(std::is_nothrow_constructible_v<T, U>)
32 : m_value(std::forward<U>(right))
33 {
34 }
35
36 template <class U, std::enable_if_t<std::is_constructible_v<T, const U&>, int> = 0>
37 constexpr explicit sentinel_optional(const sentinel_optional<U>& right) noexcept(std::is_nothrow_constructible_v<T, const U&>)
38 {
39 if (right)
40 this->m_value = *right;
41 }
42
43 template <class U, std::enable_if_t<std::is_constructible_v<T, U>, int> = 0>
44 constexpr explicit sentinel_optional(sentinel_optional<U>&& right) noexcept(std::is_nothrow_constructible_v<T, U>)
45 {
46 if (right)
47 this->m_value = std::move(*right);
48 }
49
50 constexpr sentinel_optional& operator=(std::nullopt_t) noexcept {
51 reset();
52 return *this;
53 }
54
55 template <class U = T, std::enable_if_t<
56 !std::is_same_v<sentinel_optional, remove_cvref_t<U>> &&
57 std::is_constructible_v<T, U> &&
58 std::is_assignable_v<T&, U>,
59 int> = 0>
60 constexpr sentinel_optional& operator=(U&& right) noexcept(std::is_nothrow_assignable_v<T&, U> && std::is_nothrow_constructible_v<T, U>)
61 {
62 this->m_value = std::forward<U>(right);
63 return *this;
64 }
65
66 template <class U, std::enable_if_t<
67 !(
68 std::is_same_v<T, U> ||
69 std::is_assignable_v<T&, sentinel_optional<U>&> ||
70 std::is_assignable_v<T&, const sentinel_optional<U>&> ||
71 std::is_assignable_v<T&, const sentinel_optional<U>> ||
72 std::is_assignable_v<T&, sentinel_optional<U>>
73 ) &&
74 std::is_constructible_v<T, const U&> &&
75 std::is_assignable_v<T&, const U&>,
76 int> = 0>
77 constexpr sentinel_optional& operator=(const sentinel_optional<U>& right) noexcept(std::is_nothrow_assignable_v<T&, const U&> && std::is_nothrow_constructible_v<T, const U&>)
78 {
79 if (right)
80 this->m_value = *right;
81 else
82 reset();
83
84 return *this;
85 }
86
87 template <class U, std::enable_if_t<
88 !(
89 std::is_same_v<T, U> ||
90 std::is_assignable_v<T&, sentinel_optional<U>&> ||
91 std::is_assignable_v<T&, const sentinel_optional<U>&> ||
92 std::is_assignable_v<T&, const sentinel_optional<U>> ||
93 std::is_assignable_v<T&, sentinel_optional<U>>
94 ) &&
95 std::is_constructible_v<T, U> &&
96 std::is_assignable_v<T&, U>,
97 int> = 0>
98 constexpr sentinel_optional& operator=(sentinel_optional<U>&& right) noexcept(std::is_nothrow_assignable_v<T&, U>&& std::is_nothrow_constructible_v<T, U>)
99 {
100 if (right)
101 this->m_value = std::move(*right);
102 else
103 reset();
104
105 return *this;
106 }
107
108 template <class... TYPES>
109 constexpr T& emplace(TYPES&&... args) noexcept(std::is_nothrow_constructible_v<T, TYPES...>)
110 {
111 reset();
112 return this->m_value = T(std::forward<TYPES>(args)...);
113 }
114
115 inline constexpr void assert_value() const { if (this->m_value == SENTINEL) throw std::bad_optional_access(); }
116
117 [[nodiscard]] constexpr const T* operator->() const
118 {
119 this->assert_value();
120 return std::addressof(this->m_value);
121 }
122 [[nodiscard]] constexpr T* operator->()
123 {
124 this->assert_value();
125 return std::addressof(this->m_value);
126 }
127
128 [[nodiscard]] constexpr T& operator*() &
129 {
130 this->assert_value();
131 return this->m_value;
132 }
133
134 [[nodiscard]] constexpr const T& operator*() const&
135 {
136 this->assert_value();
137 return this->m_value;
138 }
139
140 [[nodiscard]] constexpr T&& operator*() &&
141 {
142 this->assert_value();
143 return std::move(this->m_value);
144 }
145
146 [[nodiscard]] constexpr const T&& operator*() const&&
147 {
148 this->assert_value();
149 return std::move(this->m_value);
150 }
151
152 constexpr explicit operator bool() const noexcept { return this->m_value != SENTINEL; }
153 [[nodiscard]] constexpr bool has_value() const noexcept { return this->m_value != SENTINEL; }
154
155 [[nodiscard]] constexpr const T& value() const& {
156 this->assert_value();
157 return this->m_value;
158 }
159 [[nodiscard]] constexpr T& value()& {
160 this->assert_value();
161 return this->m_value;
162 }
163 [[nodiscard]] constexpr T&& value()&& {
164 this->assert_value();
165 return std::move(this->m_value);
166 }
167 [[nodiscard]] constexpr const T&& value() const&& {
168 this->assert_value();
169 return std::move(this->m_value);
170 }
171
172 [[nodiscard]] constexpr const T& raw_value() const & {
173 return this->m_value;
174 }
175 [[nodiscard]] constexpr T& raw_value() & {
176 return this->m_value;
177 }
178 [[nodiscard]] constexpr T&& raw_value() && {
179 return std::move(this->m_value);
180 }
181 [[nodiscard]] constexpr const T&& raw_value() const && {
182 return std::move(this->m_value);
183 }
184
185 /*
186 template <class _Ty2>
187 [[nodiscard]] constexpr remove_cv_t<T> value_or(_Ty2&& _Right) const& {
188 static_assert(is_convertible_v<const T&, remove_cv_t<T>>,
189 "The const overload of optional<T>::value_or requires const T& to be convertible to remove_cv_t<T> "
190 "(N4950 [optional.observe]/15 as modified by LWG-3424).");
191 static_assert(is_convertible_v<_Ty2, T>,
192 "optional<T>::value_or(U) requires U to be convertible to T (N4950 [optional.observe]/15).");
193
194 if (this->has_value()) {
195 return static_cast<const T&>(this->m_value);
196 }
197
198 return static_cast<remove_cv_t<T>>(std::forward<_Ty2>(_Right));
199 }
200 template <class _Ty2>
201 [[nodiscard]] constexpr remove_cv_t<T> value_or(_Ty2&& _Right)&& {
202 static_assert(is_convertible_v<T, remove_cv_t<T>>,
203 "The rvalue overload of optional<T>::value_or requires T to be convertible to remove_cv_t<T> "
204 "(N4950 [optional.observe]/17 as modified by LWG-3424).");
205 static_assert(is_convertible_v<_Ty2, T>,
206 "optional<T>::value_or(U) requires U to be convertible to T (N4950 [optional.observe]/17).");
207
208 if (this->has_value()) {
209 return static_cast<T&&>(this->m_value);
210 }
211
212 return static_cast<remove_cv_t<T>>(std::forward<_Ty2>(_Right));
213 }
214 */
215
216 constexpr void reset() noexcept { this->m_value = SENTINEL; }
217
218 [[nodiscard]] constexpr bool operator==(const sentinel_optional& other) const { return this->m_value == other.m_value; }
219 [[nodiscard]] constexpr bool operator!=(const sentinel_optional& other) const { return this->m_value != other.m_value; }
220 [[nodiscard]] constexpr bool operator>=(const sentinel_optional& other) const { return this->m_value >= other.m_value; }
221 [[nodiscard]] constexpr bool operator>(const sentinel_optional& other) const { return this->m_value > other.m_value; }
222 [[nodiscard]] constexpr bool operator<=(const sentinel_optional& other) const { return this->m_value <= other.m_value; }
223 [[nodiscard]] constexpr bool operator<(const sentinel_optional& other) const { return this->m_value < other.m_value; }
224
225 private:
226
227 T m_value = SENTINEL;
228 };
229
230 template <class T>
231 constexpr bool operator==(const sentinel_optional<T>& left, std::nullopt_t) noexcept { return !left.has_value(); }
232
233 template <class T, std::enable_if_t<std::is_constructible_v<std::decay_t<T>, T>, int> = 0>
234 [[nodiscard]] constexpr sentinel_optional<std::decay_t<T>> make_sentinel_optional(T&& value) noexcept(noexcept(sentinel_optional<std::decay_t<T>>{std::forward<T>(value)}))
235 {
236 return sentinel_optional<std::decay_t<T>>{std::forward<T>(value)};
237 }
238 template <class T, class... TYPES, std::enable_if_t<std::is_constructible_v<T, TYPES...>, int> = 0>
239 [[nodiscard]] constexpr sentinel_optional<T> make_optional(TYPES&&... args) noexcept(noexcept(sentinel_optional<T>{std::in_place, std::forward<TYPES>(args)...}))
240 {
241 return sentinel_optional<T>{std::in_place, std::forward<TYPES>(args)...};
242 }
243}
constexpr auto bit_count
Equal to the number of bits in the type.
Definition bits.h:33
Primary namespace for everything in this library.
Definition align+rec2.h:10