tetl 0.1.0
Embedded Template Library
Loading...
Searching...
No Matches
expected.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: BSL-1.0
2// SPDX-FileCopyrightText: Copyright (C) 2024 Tobias Hienzsch
3
4#ifndef TETL_EXPECTED_EXPECTED_HPP
5#define TETL_EXPECTED_EXPECTED_HPP
6
7#include <etl/_concepts/same_as.hpp>
8#include <etl/_contracts/check.hpp>
9#include <etl/_expected/unexpect.hpp>
10#include <etl/_expected/unexpected.hpp>
11#include <etl/_functional/invoke.hpp>
12#include <etl/_type_traits/invoke_result.hpp>
13#include <etl/_type_traits/is_constructible.hpp>
14#include <etl/_type_traits/is_copy_constructible.hpp>
15#include <etl/_type_traits/is_default_constructible.hpp>
16#include <etl/_type_traits/is_move_constructible.hpp>
17#include <etl/_type_traits/is_nothrow_constructible.hpp>
18#include <etl/_type_traits/is_nothrow_copy_constructible.hpp>
19#include <etl/_type_traits/is_nothrow_default_constructible.hpp>
20#include <etl/_type_traits/is_nothrow_move_constructible.hpp>
21#include <etl/_type_traits/is_trivially_copy_constructible.hpp>
22#include <etl/_type_traits/is_trivially_move_constructible.hpp>
23#include <etl/_type_traits/remove_cvref.hpp>
24#include <etl/_utility/forward.hpp>
25#include <etl/_utility/in_place.hpp>
26#include <etl/_utility/in_place_index.hpp>
27#include <etl/_utility/move.hpp>
28#include <etl/_variant/monostate.hpp>
29#include <etl/_variant/variant.hpp>
30
31namespace etl {
32
33/// \ingroup expected
34template <typename T, typename E>
35struct expected {
36 using value_type = T;
37 using error_type = E;
38 using unexpected_type = etl::unexpected<E>;
39
40 template <typename U>
41 using rebind = etl::expected<U, error_type>;
42
43 /// Value-initializes member of type T.
44 /// \post has_value() == true
45 constexpr explicit expected() noexcept(is_nothrow_default_constructible_v<T>)
46 requires(is_default_constructible_v<T>)
47 : _u(in_place_index<1>)
48 {
49 }
50
51 /// \post rhs.has_value() == this->has_value()
52 constexpr expected(expected const& rhs) = default;
53
54 /// \post rhs.has_value() == this->has_value()
55 constexpr expected(
56 expected const& rhs
57 ) noexcept(etl::is_nothrow_copy_constructible_v<T> and etl::is_nothrow_copy_constructible_v<E>)
58 requires(
59 etl::is_copy_constructible_v<T>
60 and etl::is_copy_constructible_v<E>
61 and (not etl::is_trivially_copy_constructible_v<T> or not etl::is_trivially_copy_constructible_v<E>)
62 )
63 : _u(in_place_index<0>, etl::monostate{})
64 {
65 if (rhs.has_value()) {
66 _u.template emplace<1>(*rhs);
67 } else {
68 _u.template emplace<2>(rhs.error());
69 }
70 }
71
72 /// \post rhs.has_value() == this->has_value()
73 constexpr expected(expected&& rhs) = default;
74
75 /// \post rhs.has_value() == this->has_value()
76 constexpr expected(
77 expected&& rhs
78 ) noexcept(etl::is_nothrow_move_constructible_v<T> and etl::is_nothrow_move_constructible_v<E>)
79 requires(
80 etl::is_move_constructible_v<T>
81 and etl::is_move_constructible_v<E>
82 and (not etl::is_trivially_move_constructible_v<T> or not etl::is_trivially_move_constructible_v<E>)
83 )
84 : _u(in_place_index<0>, etl::monostate{})
85 {
86 if (rhs.has_value()) {
87 _u.template emplace<1>(etl::move(*rhs));
88 } else {
89 _u.template emplace<2>(etl::move(rhs.error()));
90 }
91 }
92
93 ///
94 template <typename... Args>
95 requires is_constructible_v<T, Args...>
96 constexpr explicit expected(in_place_t /*tag*/, Args&&... args) noexcept(is_nothrow_constructible_v<T, Args...>)
97 : _u(in_place_index<1>, etl::forward<Args>(args)...)
98 {
99 }
100
101 template <typename... Args>
102 requires is_constructible_v<E, Args...>
103 constexpr explicit expected(unexpect_t /*tag*/, Args&&... args) noexcept(is_nothrow_constructible_v<E, Args...>)
104 : _u(in_place_index<2>, etl::forward<Args>(args)...)
105 {
106 }
107
108 [[nodiscard]] constexpr explicit operator bool() const noexcept
109 {
110 return has_value();
111 }
112
113 [[nodiscard]] constexpr auto has_value() const noexcept -> bool
114 {
115 return _u.index() == 1;
116 }
117
118 [[nodiscard]] constexpr auto operator->() const noexcept -> T const*
119 {
120 return etl::get_if<1>(&_u);
121 }
122
123 [[nodiscard]] constexpr auto operator->() noexcept -> T*
124 {
125 return etl::get_if<1>(&_u);
126 }
127
128 [[nodiscard]] constexpr auto operator*() const& noexcept -> T const&
129 {
130 TETL_PRECONDITION(has_value());
131 return _u[index_v<1>];
132 }
133
134 [[nodiscard]] constexpr auto operator*() & noexcept -> T&
135 {
136 TETL_PRECONDITION(has_value());
137 return _u[index_v<1>];
138 }
139
140 [[nodiscard]] constexpr auto operator*() const&& noexcept -> T const&&
141 {
142 TETL_PRECONDITION(has_value());
143 return etl::move(_u[index_v<1>]);
144 }
145
146 [[nodiscard]] constexpr auto operator*() && noexcept -> T&&
147 {
148 TETL_PRECONDITION(has_value());
149 return etl::move(_u[index_v<1>]);
150 }
151
152 [[nodiscard]] constexpr auto error() & -> E&
153 {
154 TETL_PRECONDITION(not has_value());
155 return _u[index_v<2>];
156 }
157
158 [[nodiscard]] constexpr auto error() const& -> E const&
159 {
160 TETL_PRECONDITION(not has_value());
161 return _u[index_v<2>];
162 }
163
164 [[nodiscard]] constexpr auto error() && -> E&&
165 {
166 TETL_PRECONDITION(not has_value());
167 return etl::move(_u[index_v<2>]);
168 }
169
170 [[nodiscard]] constexpr auto error() const&& -> E const&&
171 {
172 TETL_PRECONDITION(not has_value());
173 return etl::move(_u[index_v<2>]);
174 }
175
176 template <typename... Args>
177 requires is_nothrow_constructible_v<T, Args...>
178 constexpr auto emplace(Args&&... args) noexcept -> T&
179 {
180 _u.template emplace<1>(etl::forward<Args>(args)...);
181 return **this;
182 }
183
184 template <typename U>
185 [[nodiscard]] constexpr auto value_or(U&& fallback) const& -> T
186 {
187 return static_cast<bool>(*this) ? **this : static_cast<T>(etl::forward<U>(fallback));
188 }
189
190 template <typename U>
191 [[nodiscard]] constexpr auto value_or(U&& fallback) && -> T
192 {
193 return static_cast<bool>(*this) ? etl::move(**this) : static_cast<T>(etl::forward<U>(fallback));
194 }
195
196 template <typename F>
197 [[nodiscard]] constexpr auto and_then(F&& f) &
198 requires(is_constructible_v<E, decltype(error())>)
199 {
200 if (has_value()) {
201 return etl::invoke(etl::forward<F>(f), **this);
202 }
203 using U = remove_cvref_t<invoke_result_t<F, decltype(**this)>>;
204 return U(unexpect, error());
205 }
206
207 template <typename F>
208 [[nodiscard]] constexpr auto and_then(F&& f) &&
209 requires(is_constructible_v<E, decltype(error())>)
210 {
211 if (has_value()) {
212 return etl::invoke(etl::forward<F>(f), **this);
213 }
214 using U = remove_cvref_t<invoke_result_t<F, decltype(**this)>>;
215 return U(unexpect, error());
216 }
217
218 template <typename F>
219 [[nodiscard]] constexpr auto and_then(F&& f) const&
220 requires(is_constructible_v<E, decltype(etl::move(error()))>)
221 {
222 if (has_value()) {
223 return etl::invoke(etl::forward<F>(f), etl::move(**this));
224 }
225 using U = remove_cvref_t<invoke_result_t<F, decltype(etl::move(**this))>>;
226 return U(unexpect, etl::move(error()));
227 }
228
229 template <typename F>
230 [[nodiscard]] constexpr auto and_then(F&& f) const&&
231 requires(is_constructible_v<E, decltype(etl::move(error()))>)
232 {
233 if (has_value()) {
234 return etl::invoke(etl::forward<F>(f), etl::move(**this));
235 }
236 using U = remove_cvref_t<invoke_result_t<F, decltype(etl::move(**this))>>;
237 return U(unexpect, etl::move(error()));
238 }
239
240 template <typename F>
241 [[nodiscard]] constexpr auto or_else(F&& f) &
242 requires(is_constructible_v<T, decltype(**this)>)
243 {
244 using G = remove_cvref_t<invoke_result_t<F, decltype(error())>>;
245 if (has_value()) {
246 return G(etl::in_place, **this);
247 }
248 return etl::invoke(etl::forward<F>(f), error());
249 }
250
251 template <typename F>
252 [[nodiscard]] constexpr auto or_else(F&& f) &&
253 requires(is_constructible_v<T, decltype(**this)>)
254 {
255 using G = remove_cvref_t<invoke_result_t<F, decltype(error())>>;
256 if (has_value()) {
257 return G(etl::in_place, **this);
258 }
259 return etl::invoke(etl::forward<F>(f), error());
260 }
261
262 template <typename F>
263 [[nodiscard]] constexpr auto or_else(F&& f) const&
264 requires(is_constructible_v<T, decltype(etl::move(**this))>)
265 {
266 using G = remove_cvref_t<invoke_result_t<F, decltype(etl::move(error()))>>;
267 if (has_value()) {
268 return G(etl::in_place, etl::move(**this));
269 }
270 return etl::invoke(etl::forward<F>(f), etl::move(error()));
271 }
272
273 template <typename F>
274 [[nodiscard]] constexpr auto or_else(F&& f) const&&
275 requires(is_constructible_v<T, decltype(etl::move(**this))>)
276 {
277 using G = remove_cvref_t<invoke_result_t<F, decltype(etl::move(error()))>>;
278 if (has_value()) {
279 return G(etl::in_place, etl::move(**this));
280 }
281 return etl::invoke(etl::forward<F>(f), etl::move(error()));
282 }
283
284private:
285 etl::variant<etl::monostate, T, E> _u;
286};
287
288} // namespace etl
289
290#endif // TETL_EXPECTED_EXPECTED_HPP
constexpr auto unexpect
Definition unexpect.hpp:16
Definition adjacent_find.hpp:9
Definition expected.hpp:35
constexpr auto operator*() &noexcept -> T &
Definition expected.hpp:134
constexpr auto and_then(F &&f) &
Definition expected.hpp:197
constexpr auto or_else(F &&f) const &&
Definition expected.hpp:274
constexpr auto emplace(Args &&... args) noexcept -> T &
Definition expected.hpp:178
constexpr auto operator->() const noexcept -> T const *
Definition expected.hpp:118
constexpr auto error() &&-> E &&
Definition expected.hpp:164
constexpr auto operator*() &&noexcept -> T &&
Definition expected.hpp:146
constexpr auto error() &-> E &
Definition expected.hpp:152
constexpr auto and_then(F &&f) &&
Definition expected.hpp:208
constexpr expected(unexpect_t, Args &&... args) noexcept(is_nothrow_constructible_v< E, Args... >)
Definition expected.hpp:103
constexpr auto and_then(F &&f) const &
Definition expected.hpp:219
constexpr auto or_else(F &&f) &&
Definition expected.hpp:252
constexpr auto value_or(U &&fallback) &&-> T
Definition expected.hpp:191
constexpr expected(in_place_t, Args &&... args) noexcept(is_nothrow_constructible_v< T, Args... >)
Definition expected.hpp:96
constexpr auto error() const &&-> E const &&
Definition expected.hpp:170
constexpr auto or_else(F &&f) const &
Definition expected.hpp:263
constexpr operator bool() const noexcept
Definition expected.hpp:108
constexpr auto operator->() noexcept -> T *
Definition expected.hpp:123
constexpr auto error() const &-> E const &
Definition expected.hpp:158
constexpr auto operator*() const &noexcept -> T const &
Definition expected.hpp:128
constexpr auto operator*() const &&noexcept -> T const &&
Definition expected.hpp:140
constexpr auto has_value() const noexcept -> bool
Definition expected.hpp:113
constexpr auto or_else(F &&f) &
Definition expected.hpp:241
constexpr auto and_then(F &&f) const &&
Definition expected.hpp:230
constexpr expected(expected const &rhs)=default
constexpr expected(expected &&rhs)=default
constexpr auto value_or(U &&fallback) const &-> T
Definition expected.hpp:185
Disambiguation tags that can be passed to the constructors of optional, variant, and any to indicate ...
Definition in_place.hpp:21
constexpr auto in_place
Definition in_place.hpp:26
Unit type intended for use as a well-behaved empty alternative in etl::variant. In particular,...
Definition monostate.hpp:17
Definition unexpect.hpp:10
Definition unexpected.hpp:22
Definition variant.hpp:99