Line data Source code
1 : // clang-format off
2 : ///
3 : // expected - An implementation of std::expected with extensions
4 : // Written in 2017 by Sy Brand (tartanllama@gmail.com, @TartanLlama)
5 : //
6 : // Documentation available at http://tl.tartanllama.xyz/
7 : //
8 : // To the extent possible under law, the author(s) have dedicated all
9 : // copyright and related and neighboring rights to this software to the
10 : // public domain worldwide. This software is distributed without any warranty.
11 : //
12 : // You should have received a copy of the CC0 Public Domain Dedication
13 : // along with this software. If not, see
14 : // <http://creativecommons.org/publicdomain/zero/1.0/>.
15 : ///
16 :
17 : #ifndef TL_EXPECTED_HPP
18 : #define TL_EXPECTED_HPP
19 :
20 : #define TL_EXPECTED_VERSION_MAJOR 1
21 : #define TL_EXPECTED_VERSION_MINOR 1
22 : #define TL_EXPECTED_VERSION_PATCH 0
23 :
24 : #include "rust-system.h"
25 :
26 : #if defined(__EXCEPTIONS) || defined(_CPPUNWIND)
27 : #define TL_EXPECTED_EXCEPTIONS_ENABLED
28 : #endif
29 :
30 : #if (defined(_MSC_VER) && _MSC_VER == 1900)
31 : #define TL_EXPECTED_MSVC2015
32 : #define TL_EXPECTED_MSVC2015_CONSTEXPR
33 : #else
34 : #define TL_EXPECTED_MSVC2015_CONSTEXPR constexpr
35 : #endif
36 :
37 : #if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
38 : !defined(__clang__))
39 : #define TL_EXPECTED_GCC49
40 : #endif
41 :
42 : #if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \
43 : !defined(__clang__))
44 : #define TL_EXPECTED_GCC54
45 : #endif
46 :
47 : #if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && \
48 : !defined(__clang__))
49 : #define TL_EXPECTED_GCC55
50 : #endif
51 :
52 : #if !defined(TL_ASSERT)
53 : //can't have assert in constexpr in C++11 and GCC 4.9 has a compiler bug
54 : #if (__cplusplus > 201103L) && !defined(TL_EXPECTED_GCC49)
55 : #include <cassert>
56 : #define TL_ASSERT(x) assert(x)
57 : #else
58 : #define TL_ASSERT(x)
59 : #endif
60 : #endif
61 :
62 : #if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
63 : !defined(__clang__))
64 : // GCC < 5 doesn't support overloading on const&& for member functions
65 :
66 : #define TL_EXPECTED_NO_CONSTRR
67 : // GCC < 5 doesn't support some standard C++11 type traits
68 : #define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
69 : std::has_trivial_copy_constructor<T>
70 : #define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
71 : std::has_trivial_copy_assign<T>
72 :
73 : // This one will be different for GCC 5.7 if it's ever supported
74 : #define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
75 : std::is_trivially_destructible<T>
76 :
77 : // GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks
78 : // std::vector for non-copyable types
79 : #elif (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__))
80 : #ifndef TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
81 : #define TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
82 : namespace tl {
83 : namespace detail {
84 : template <class T>
85 : struct is_trivially_copy_constructible
86 : : std::is_trivially_copy_constructible<T> {};
87 : #ifdef _GLIBCXX_VECTOR
88 : template <class T, class A>
89 : struct is_trivially_copy_constructible<std::vector<T, A>> : std::false_type {};
90 : #endif
91 : } // namespace detail
92 : } // namespace tl
93 : #endif
94 :
95 : #define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
96 : tl::detail::is_trivially_copy_constructible<T>
97 : #define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
98 : std::is_trivially_copy_assignable<T>
99 : #define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
100 : std::is_trivially_destructible<T>
101 : #else
102 : #define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
103 : std::is_trivially_copy_constructible<T>
104 : #define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
105 : std::is_trivially_copy_assignable<T>
106 : #define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \
107 : std::is_trivially_destructible<T>
108 : #endif
109 :
110 : #if __cplusplus > 201103L
111 : #define TL_EXPECTED_CXX14
112 : #endif
113 :
114 : #ifdef TL_EXPECTED_GCC49
115 : #define TL_EXPECTED_GCC49_CONSTEXPR
116 : #else
117 : #define TL_EXPECTED_GCC49_CONSTEXPR constexpr
118 : #endif
119 :
120 : #if (__cplusplus == 201103L || defined(TL_EXPECTED_MSVC2015) || \
121 : defined(TL_EXPECTED_GCC49))
122 : #define TL_EXPECTED_11_CONSTEXPR
123 : #else
124 : #define TL_EXPECTED_11_CONSTEXPR constexpr
125 : #endif
126 :
127 : namespace tl {
128 : template <class T, class E> class expected;
129 :
130 : #ifndef TL_MONOSTATE_INPLACE_MUTEX
131 : #define TL_MONOSTATE_INPLACE_MUTEX
132 : class monostate {};
133 :
134 : struct in_place_t {
135 : explicit in_place_t() = default;
136 : };
137 : static constexpr in_place_t in_place{};
138 : #endif
139 :
140 322470 : template <class E> class unexpected {
141 : public:
142 : static_assert(!std::is_same<E, void>::value, "E must not be void");
143 :
144 : unexpected() = delete;
145 : constexpr explicit unexpected(const E &e) : m_val(e) {}
146 :
147 322696 : constexpr explicit unexpected(E &&e) : m_val(std::move(e)) {}
148 :
149 : template <class... Args, typename std::enable_if<std::is_constructible<
150 : E, Args &&...>::value>::type * = nullptr>
151 0 : constexpr explicit unexpected(Args &&...args)
152 0 : : m_val(std::forward<Args>(args)...) {}
153 : template <
154 : class U, class... Args,
155 : typename std::enable_if<std::is_constructible<
156 : E, std::initializer_list<U> &, Args &&...>::value>::type * = nullptr>
157 : constexpr explicit unexpected(std::initializer_list<U> l, Args &&...args)
158 : : m_val(l, std::forward<Args>(args)...) {}
159 :
160 : constexpr const E &value() const & { return m_val; }
161 327438 : TL_EXPECTED_11_CONSTEXPR E &value() & { return m_val; }
162 : TL_EXPECTED_11_CONSTEXPR E &&value() && { return std::move(m_val); }
163 : constexpr const E &&value() const && { return std::move(m_val); }
164 :
165 : private:
166 : E m_val;
167 : };
168 :
169 : #ifdef __cpp_deduction_guides
170 : template <class E> unexpected(E) -> unexpected<E>;
171 : #endif
172 :
173 : template <class E>
174 : constexpr bool operator==(const unexpected<E> &lhs, const unexpected<E> &rhs) {
175 : return lhs.value() == rhs.value();
176 : }
177 : template <class E>
178 : constexpr bool operator!=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
179 : return lhs.value() != rhs.value();
180 : }
181 : template <class E>
182 : constexpr bool operator<(const unexpected<E> &lhs, const unexpected<E> &rhs) {
183 : return lhs.value() < rhs.value();
184 : }
185 : template <class E>
186 : constexpr bool operator<=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
187 : return lhs.value() <= rhs.value();
188 : }
189 : template <class E>
190 : constexpr bool operator>(const unexpected<E> &lhs, const unexpected<E> &rhs) {
191 : return lhs.value() > rhs.value();
192 : }
193 : template <class E>
194 : constexpr bool operator>=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
195 : return lhs.value() >= rhs.value();
196 : }
197 :
198 : template <class E>
199 111212 : unexpected<typename std::decay<E>::type> make_unexpected(E &&e) {
200 111211 : return unexpected<typename std::decay<E>::type>(std::forward<E>(e));
201 : }
202 :
203 : struct unexpect_t {
204 : unexpect_t() = default;
205 : };
206 : static constexpr unexpect_t unexpect{};
207 :
208 : namespace detail {
209 : template <typename E>
210 0 : [[noreturn]] TL_EXPECTED_11_CONSTEXPR void throw_exception(E &&e) {
211 : #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
212 : throw std::forward<E>(e);
213 : #else
214 : (void)e;
215 0 : gcc_unreachable();
216 : #endif
217 : }
218 :
219 : #ifndef TL_TRAITS_MUTEX
220 : #define TL_TRAITS_MUTEX
221 : // C++14-style aliases for brevity
222 : template <class T> using remove_const_t = typename std::remove_const<T>::type;
223 : template <class T>
224 : using remove_reference_t = typename std::remove_reference<T>::type;
225 : template <class T> using decay_t = typename std::decay<T>::type;
226 : template <bool E, class T = void>
227 : using enable_if_t = typename std::enable_if<E, T>::type;
228 : template <bool B, class T, class F>
229 : using conditional_t = typename std::conditional<B, T, F>::type;
230 :
231 : // std::conjunction from C++17
232 : template <class...> struct conjunction : std::true_type {};
233 : template <class B> struct conjunction<B> : B {};
234 : template <class B, class... Bs>
235 : struct conjunction<B, Bs...>
236 : : std::conditional<bool(B::value), conjunction<Bs...>, B>::type {};
237 :
238 : #if defined(_LIBCPP_VERSION) && __cplusplus == 201103L
239 : #define TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
240 : #endif
241 :
242 : // In C++11 mode, there's an issue in libc++'s std::mem_fn
243 : // which results in a hard-error when using it in a noexcept expression
244 : // in some cases. This is a check to workaround the common failing case.
245 : #ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
246 : template <class T>
247 : struct is_pointer_to_non_const_member_func : std::false_type {};
248 : template <class T, class Ret, class... Args>
249 : struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...)>
250 : : std::true_type {};
251 : template <class T, class Ret, class... Args>
252 : struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &>
253 : : std::true_type {};
254 : template <class T, class Ret, class... Args>
255 : struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &&>
256 : : std::true_type {};
257 : template <class T, class Ret, class... Args>
258 : struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile>
259 : : std::true_type {};
260 : template <class T, class Ret, class... Args>
261 : struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile &>
262 : : std::true_type {};
263 : template <class T, class Ret, class... Args>
264 : struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile &&>
265 : : std::true_type {};
266 :
267 : template <class T> struct is_const_or_const_ref : std::false_type {};
268 : template <class T> struct is_const_or_const_ref<T const &> : std::true_type {};
269 : template <class T> struct is_const_or_const_ref<T const> : std::true_type {};
270 : #endif
271 :
272 : // std::invoke from C++17
273 : // https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
274 : template <
275 : typename Fn, typename... Args,
276 : #ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
277 : typename = enable_if_t<!(is_pointer_to_non_const_member_func<Fn>::value &&
278 : is_const_or_const_ref<Args...>::value)>,
279 : #endif
280 : typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>::value>, int = 0>
281 : constexpr auto invoke(Fn &&f, Args &&...args) noexcept(
282 : noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
283 : -> decltype(std::mem_fn(f)(std::forward<Args>(args)...)) {
284 : return std::mem_fn(f)(std::forward<Args>(args)...);
285 : }
286 :
287 : template <typename Fn, typename... Args,
288 : typename = enable_if_t<!std::is_member_pointer<decay_t<Fn>>::value>>
289 323 : constexpr auto invoke(Fn &&f, Args &&...args) noexcept(
290 : noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...)))
291 : -> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...)) {
292 323 : return std::forward<Fn>(f)(std::forward<Args>(args)...);
293 : }
294 :
295 : // std::invoke_result from C++17
296 : template <class F, class, class... Us> struct invoke_result_impl;
297 :
298 : template <class F, class... Us>
299 : struct invoke_result_impl<
300 : F,
301 : decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...), void()),
302 : Us...> {
303 : using type =
304 : decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...));
305 : };
306 :
307 : template <class F, class... Us>
308 : using invoke_result = invoke_result_impl<F, void, Us...>;
309 :
310 : template <class F, class... Us>
311 : using invoke_result_t = typename invoke_result<F, Us...>::type;
312 :
313 : #if defined(_MSC_VER) && _MSC_VER <= 1900
314 : // TODO make a version which works with MSVC 2015
315 : template <class T, class U = T> struct is_swappable : std::true_type {};
316 :
317 : template <class T, class U = T> struct is_nothrow_swappable : std::true_type {};
318 : #else
319 : // https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept
320 : namespace swap_adl_tests {
321 : // if swap ADL finds this then it would call std::swap otherwise (same
322 : // signature)
323 : struct tag {};
324 :
325 : template <class T> tag swap(T &, T &);
326 : template <class T, std::size_t N> tag swap(T (&a)[N], T (&b)[N]);
327 :
328 : // helper functions to test if an unqualified swap is possible, and if it
329 : // becomes std::swap
330 : template <class, class> std::false_type can_swap(...) noexcept(false);
331 : template <class T, class U,
332 : class = decltype(swap(std::declval<T &>(), std::declval<U &>()))>
333 : std::true_type can_swap(int) noexcept(noexcept(swap(std::declval<T &>(),
334 : std::declval<U &>())));
335 :
336 : template <class, class> std::false_type uses_std(...);
337 : template <class T, class U>
338 : std::is_same<decltype(swap(std::declval<T &>(), std::declval<U &>())), tag>
339 : uses_std(int);
340 :
341 : template <class T>
342 : struct is_std_swap_noexcept
343 : : std::integral_constant<bool,
344 : std::is_nothrow_move_constructible<T>::value &&
345 : std::is_nothrow_move_assignable<T>::value> {};
346 :
347 : template <class T, std::size_t N>
348 : struct is_std_swap_noexcept<T[N]> : is_std_swap_noexcept<T> {};
349 :
350 : template <class T, class U>
351 : struct is_adl_swap_noexcept
352 : : std::integral_constant<bool, noexcept(can_swap<T, U>(0))> {};
353 : } // namespace swap_adl_tests
354 :
355 : template <class T, class U = T>
356 : struct is_swappable
357 : : std::integral_constant<
358 : bool,
359 : decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value &&
360 : (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value ||
361 : (std::is_move_assignable<T>::value &&
362 : std::is_move_constructible<T>::value))> {};
363 :
364 : template <class T, std::size_t N>
365 : struct is_swappable<T[N], T[N]>
366 : : std::integral_constant<
367 : bool,
368 : decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value &&
369 : (!decltype(detail::swap_adl_tests::uses_std<T[N], T[N]>(
370 : 0))::value ||
371 : is_swappable<T, T>::value)> {};
372 :
373 : template <class T, class U = T>
374 : struct is_nothrow_swappable
375 : : std::integral_constant<
376 : bool,
377 : is_swappable<T, U>::value &&
378 : ((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
379 : detail::swap_adl_tests::is_std_swap_noexcept<T>::value) ||
380 : (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
381 : detail::swap_adl_tests::is_adl_swap_noexcept<T, U>::value))> {};
382 : #endif
383 : #endif
384 :
385 : // Trait for checking if a type is a tl::expected
386 : template <class T> struct is_expected_impl : std::false_type {};
387 : template <class T, class E>
388 : struct is_expected_impl<expected<T, E>> : std::true_type {};
389 : template <class T> using is_expected = is_expected_impl<decay_t<T>>;
390 :
391 : template <class T, class E, class U>
392 : using expected_enable_forward_value = detail::enable_if_t<
393 : std::is_constructible<T, U &&>::value &&
394 : !std::is_same<detail::decay_t<U>, in_place_t>::value &&
395 : !std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
396 : !std::is_same<unexpected<E>, detail::decay_t<U>>::value>;
397 :
398 : template <class T, class E, class U, class G, class UR, class GR>
399 : using expected_enable_from_other = detail::enable_if_t<
400 : std::is_constructible<T, UR>::value &&
401 : std::is_constructible<E, GR>::value &&
402 : !std::is_constructible<T, expected<U, G> &>::value &&
403 : !std::is_constructible<T, expected<U, G> &&>::value &&
404 : !std::is_constructible<T, const expected<U, G> &>::value &&
405 : !std::is_constructible<T, const expected<U, G> &&>::value &&
406 : !std::is_convertible<expected<U, G> &, T>::value &&
407 : !std::is_convertible<expected<U, G> &&, T>::value &&
408 : !std::is_convertible<const expected<U, G> &, T>::value &&
409 : !std::is_convertible<const expected<U, G> &&, T>::value>;
410 :
411 : template <class T, class U>
412 : using is_void_or = conditional_t<std::is_void<T>::value, std::true_type, U>;
413 :
414 : template <class T>
415 : using is_copy_constructible_or_void =
416 : is_void_or<T, std::is_copy_constructible<T>>;
417 :
418 : template <class T>
419 : using is_move_constructible_or_void =
420 : is_void_or<T, std::is_move_constructible<T>>;
421 :
422 : template <class T>
423 : using is_copy_assignable_or_void = is_void_or<T, std::is_copy_assignable<T>>;
424 :
425 : template <class T>
426 : using is_move_assignable_or_void = is_void_or<T, std::is_move_assignable<T>>;
427 :
428 : } // namespace detail
429 :
430 : namespace detail {
431 : struct no_init_t {};
432 : static constexpr no_init_t no_init{};
433 :
434 : // Implements the storage of the values, and ensures that the destructor is
435 : // trivial if it can be.
436 : //
437 : // This specialization is for where neither `T` or `E` is trivially
438 : // destructible, so the destructors must be called on destruction of the
439 : // `expected`
440 : template <class T, class E, bool = std::is_trivially_destructible<T>::value,
441 : bool = std::is_trivially_destructible<E>::value>
442 : struct expected_storage_base {
443 : constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
444 : constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
445 :
446 : template <class... Args,
447 : detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
448 : nullptr>
449 4640 : constexpr expected_storage_base(in_place_t, Args &&...args)
450 4643 : : m_val(std::forward<Args>(args)...), m_has_val(true) {}
451 :
452 : template <class U, class... Args,
453 : detail::enable_if_t<std::is_constructible<
454 : T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
455 : constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
456 : Args &&...args)
457 : : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
458 : template <class... Args,
459 : detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
460 : nullptr>
461 75 : constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
462 76 : : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
463 :
464 : template <class U, class... Args,
465 : detail::enable_if_t<std::is_constructible<
466 : E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
467 : constexpr explicit expected_storage_base(unexpect_t,
468 : std::initializer_list<U> il,
469 : Args &&...args)
470 : : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
471 :
472 4715 : ~expected_storage_base() {
473 4715 : if (m_has_val) {
474 4640 : m_val.~T();
475 : } else {
476 75 : m_unexpect.~unexpected<E>();
477 : }
478 4715 : }
479 : union {
480 : T m_val;
481 : unexpected<E> m_unexpect;
482 : char m_no_init;
483 : };
484 : bool m_has_val;
485 : };
486 :
487 : // This specialization is for when both `T` and `E` are trivially-destructible,
488 : // so the destructor of the `expected` can be trivial.
489 : template <class T, class E> struct expected_storage_base<T, E, true, true> {
490 : constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
491 8 : constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
492 :
493 : template <class... Args,
494 : detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
495 : nullptr>
496 270 : constexpr expected_storage_base(in_place_t, Args &&...args)
497 270 : : m_val(std::forward<Args>(args)...), m_has_val(true) {}
498 :
499 : template <class U, class... Args,
500 : detail::enable_if_t<std::is_constructible<
501 : T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
502 : constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
503 : Args &&...args)
504 : : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
505 : template <class... Args,
506 : detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
507 : nullptr>
508 22 : constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
509 22 : : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
510 :
511 : template <class U, class... Args,
512 : detail::enable_if_t<std::is_constructible<
513 : E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
514 : constexpr explicit expected_storage_base(unexpect_t,
515 : std::initializer_list<U> il,
516 : Args &&...args)
517 : : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
518 :
519 : ~expected_storage_base() = default;
520 : union {
521 : T m_val;
522 : unexpected<E> m_unexpect;
523 : char m_no_init;
524 : };
525 : bool m_has_val;
526 : };
527 :
528 : // T is trivial, E is not.
529 : template <class T, class E> struct expected_storage_base<T, E, true, false> {
530 : constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
531 153205 : TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base(no_init_t)
532 153205 : : m_no_init(), m_has_val(false) {}
533 :
534 : template <class... Args,
535 : detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
536 : nullptr>
537 159426 : constexpr expected_storage_base(in_place_t, Args &&...args)
538 159426 : : m_val(std::forward<Args>(args)...), m_has_val(true) {}
539 :
540 : template <class U, class... Args,
541 : detail::enable_if_t<std::is_constructible<
542 : T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
543 : constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
544 : Args &&...args)
545 : : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
546 : template <class... Args,
547 : detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
548 : nullptr>
549 107533 : constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
550 215066 : : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
551 :
552 : template <class U, class... Args,
553 : detail::enable_if_t<std::is_constructible<
554 : E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
555 : constexpr explicit expected_storage_base(unexpect_t,
556 : std::initializer_list<U> il,
557 : Args &&...args)
558 : : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
559 :
560 420164 : ~expected_storage_base() {
561 185768 : if (!m_has_val) {
562 214786 : m_unexpect.~unexpected<E>();
563 : }
564 : }
565 :
566 : union {
567 : T m_val;
568 : unexpected<E> m_unexpect;
569 : char m_no_init;
570 : };
571 : bool m_has_val;
572 : };
573 :
574 : // E is trivial, T is not.
575 : template <class T, class E> struct expected_storage_base<T, E, false, true> {
576 37098 : constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
577 167118 : constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
578 :
579 : template <class... Args,
580 : detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
581 : nullptr>
582 593688 : constexpr expected_storage_base(in_place_t, Args &&...args)
583 855852 : : m_val(std::forward<Args>(args)...), m_has_val(true) {}
584 :
585 : template <class U, class... Args,
586 : detail::enable_if_t<std::is_constructible<
587 : T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
588 : constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
589 : Args &&...args)
590 : : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
591 : template <class... Args,
592 : detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
593 : nullptr>
594 20963 : constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
595 20963 : : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
596 :
597 : template <class U, class... Args,
598 : detail::enable_if_t<std::is_constructible<
599 : E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
600 : constexpr explicit expected_storage_base(unexpect_t,
601 : std::initializer_list<U> il,
602 : Args &&...args)
603 : : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
604 :
605 949122 : ~expected_storage_base() {
606 197629 : if (m_has_val) {
607 853292 : m_val.~T();
608 : }
609 108122 : }
610 : union {
611 : T m_val;
612 : unexpected<E> m_unexpect;
613 : char m_no_init;
614 : };
615 : bool m_has_val;
616 : };
617 :
618 : // `T` is `void`, `E` is trivially-destructible
619 : template <class E> struct expected_storage_base<void, E, false, true> {
620 : #if __GNUC__ <= 5
621 : //no constexpr for GCC 4/5 bug
622 : #else
623 : TL_EXPECTED_MSVC2015_CONSTEXPR
624 : #endif
625 : expected_storage_base() : m_has_val(true) {}
626 :
627 : constexpr expected_storage_base(no_init_t) : m_val(), m_has_val(false) {}
628 :
629 : constexpr expected_storage_base(in_place_t) : m_has_val(true) {}
630 :
631 : template <class... Args,
632 : detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
633 : nullptr>
634 : constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
635 : : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
636 :
637 : template <class U, class... Args,
638 : detail::enable_if_t<std::is_constructible<
639 : E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
640 : constexpr explicit expected_storage_base(unexpect_t,
641 : std::initializer_list<U> il,
642 : Args &&...args)
643 : : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
644 :
645 : ~expected_storage_base() = default;
646 : struct dummy {};
647 : union {
648 : unexpected<E> m_unexpect;
649 : dummy m_val;
650 : };
651 : bool m_has_val;
652 : };
653 :
654 : // `T` is `void`, `E` is not trivially-destructible
655 : template <class E> struct expected_storage_base<void, E, false, false> {
656 : constexpr expected_storage_base() : m_dummy(), m_has_val(true) {}
657 : constexpr expected_storage_base(no_init_t) : m_dummy(), m_has_val(false) {}
658 :
659 : constexpr expected_storage_base(in_place_t) : m_dummy(), m_has_val(true) {}
660 :
661 : template <class... Args,
662 : detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
663 : nullptr>
664 : constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
665 : : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
666 :
667 : template <class U, class... Args,
668 : detail::enable_if_t<std::is_constructible<
669 : E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
670 : constexpr explicit expected_storage_base(unexpect_t,
671 : std::initializer_list<U> il,
672 : Args &&...args)
673 : : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
674 :
675 : ~expected_storage_base() {
676 : if (!m_has_val) {
677 : m_unexpect.~unexpected<E>();
678 : }
679 : }
680 :
681 : union {
682 : unexpected<E> m_unexpect;
683 : char m_dummy;
684 : };
685 : bool m_has_val;
686 : };
687 :
688 : // This base class provides some handy member functions which can be used in
689 : // further derived classes
690 : template <class T, class E>
691 2423159 : struct expected_operations_base : expected_storage_base<T, E> {
692 1576649 : using expected_storage_base<T, E>::expected_storage_base;
693 :
694 37096 : template <class... Args> void construct(Args &&...args) noexcept {
695 37096 : new (std::addressof(this->m_val)) T(std::forward<Args>(args)...);
696 37096 : this->m_has_val = true;
697 37096 : }
698 :
699 213070 : template <class Rhs> void construct_with(Rhs &&rhs) noexcept {
700 213070 : new (std::addressof(this->m_val)) T(std::forward<Rhs>(rhs).get());
701 115106 : this->m_has_val = true;
702 143916 : }
703 :
704 107296 : template <class... Args> void construct_error(Args &&...args) noexcept {
705 214549 : new (std::addressof(this->m_unexpect))
706 : unexpected<E>(std::forward<Args>(args)...);
707 107288 : this->m_has_val = false;
708 107296 : }
709 :
710 : #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
711 :
712 : // These assign overloads ensure that the most efficient assignment
713 : // implementation is used while maintaining the strong exception guarantee.
714 : // The problematic case is where rhs has a value, but *this does not.
715 : //
716 : // This overload handles the case where we can just copy-construct `T`
717 : // directly into place without throwing.
718 : template <class U = T,
719 : detail::enable_if_t<std::is_nothrow_copy_constructible<U>::value>
720 : * = nullptr>
721 : void assign(const expected_operations_base &rhs) noexcept {
722 : if (!this->m_has_val && rhs.m_has_val) {
723 : geterr().~unexpected<E>();
724 : construct(rhs.get());
725 : } else {
726 : assign_common(rhs);
727 : }
728 : }
729 :
730 : // This overload handles the case where we can attempt to create a copy of
731 : // `T`, then no-throw move it into place if the copy was successful.
732 : template <class U = T,
733 : detail::enable_if_t<!std::is_nothrow_copy_constructible<U>::value &&
734 : std::is_nothrow_move_constructible<U>::value>
735 : * = nullptr>
736 : void assign(const expected_operations_base &rhs) noexcept {
737 : if (!this->m_has_val && rhs.m_has_val) {
738 : T tmp = rhs.get();
739 : geterr().~unexpected<E>();
740 : construct(std::move(tmp));
741 : } else {
742 : assign_common(rhs);
743 : }
744 : }
745 :
746 : // This overload is the worst-case, where we have to move-construct the
747 : // unexpected value into temporary storage, then try to copy the T into place.
748 : // If the construction succeeds, then everything is fine, but if it throws,
749 : // then we move the old unexpected value back into place before rethrowing the
750 : // exception.
751 : template <class U = T,
752 : detail::enable_if_t<!std::is_nothrow_copy_constructible<U>::value &&
753 : !std::is_nothrow_move_constructible<U>::value>
754 : * = nullptr>
755 : void assign(const expected_operations_base &rhs) {
756 : if (!this->m_has_val && rhs.m_has_val) {
757 : auto tmp = std::move(geterr());
758 : geterr().~unexpected<E>();
759 :
760 : #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
761 : try {
762 : construct(rhs.get());
763 : } catch (...) {
764 : geterr() = std::move(tmp);
765 : throw;
766 : }
767 : #else
768 : construct(rhs.get());
769 : #endif
770 : } else {
771 : assign_common(rhs);
772 : }
773 : }
774 :
775 : // These overloads do the same as above, but for rvalues
776 : template <class U = T,
777 : detail::enable_if_t<std::is_nothrow_move_constructible<U>::value>
778 : * = nullptr>
779 : void assign(expected_operations_base &&rhs) noexcept {
780 : if (!this->m_has_val && rhs.m_has_val) {
781 : geterr().~unexpected<E>();
782 : construct(std::move(rhs).get());
783 : } else {
784 : assign_common(std::move(rhs));
785 : }
786 : }
787 :
788 : template <class U = T,
789 : detail::enable_if_t<!std::is_nothrow_move_constructible<U>::value>
790 : * = nullptr>
791 : void assign(expected_operations_base &&rhs) {
792 : if (!this->m_has_val && rhs.m_has_val) {
793 : auto tmp = std::move(geterr());
794 : geterr().~unexpected<E>();
795 : #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
796 : try {
797 : construct(std::move(rhs).get());
798 : } catch (...) {
799 : geterr() = std::move(tmp);
800 : throw;
801 : }
802 : #else
803 : construct(std::move(rhs).get());
804 : #endif
805 : } else {
806 : assign_common(std::move(rhs));
807 : }
808 : }
809 :
810 : #else
811 :
812 : // If exceptions are disabled then we can just copy-construct
813 : void assign(const expected_operations_base &rhs) noexcept {
814 : if (!this->m_has_val && rhs.m_has_val) {
815 : geterr().~unexpected<E>();
816 : construct(rhs.get());
817 : } else {
818 : assign_common(rhs);
819 : }
820 : }
821 :
822 64778 : void assign(expected_operations_base &&rhs) noexcept {
823 64778 : if (!this->m_has_val && rhs.m_has_val) {
824 0 : geterr().~unexpected<E>();
825 0 : construct(std::move(rhs).get());
826 : } else {
827 64778 : assign_common(std::move(rhs));
828 : }
829 64778 : }
830 :
831 : #endif
832 :
833 : // The common part of move/copy assigning
834 64778 : template <class Rhs> void assign_common(Rhs &&rhs) {
835 64778 : if (this->m_has_val) {
836 64778 : if (rhs.m_has_val) {
837 64745 : get() = std::forward<Rhs>(rhs).get();
838 : } else {
839 33 : destroy_val();
840 33 : construct_error(std::forward<Rhs>(rhs).geterr());
841 : }
842 : } else {
843 0 : if (!rhs.m_has_val) {
844 0 : geterr() = std::forward<Rhs>(rhs).geterr();
845 : }
846 : }
847 64778 : }
848 :
849 320331 : bool has_value() const { return this->m_has_val; }
850 :
851 64778 : TL_EXPECTED_11_CONSTEXPR T &get() & { return this->m_val; }
852 : constexpr const T &get() const & { return this->m_val; }
853 64745 : TL_EXPECTED_11_CONSTEXPR T &&get() && { return std::move(this->m_val); }
854 : #ifndef TL_EXPECTED_NO_CONSTRR
855 : constexpr const T &&get() const && { return std::move(this->m_val); }
856 : #endif
857 :
858 8 : TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & {
859 : return this->m_unexpect;
860 : }
861 107253 : constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; }
862 : TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && {
863 : return std::move(this->m_unexpect);
864 : }
865 : #ifndef TL_EXPECTED_NO_CONSTRR
866 : constexpr const unexpected<E> &&geterr() const && {
867 : return std::move(this->m_unexpect);
868 : }
869 : #endif
870 :
871 33 : TL_EXPECTED_11_CONSTEXPR void destroy_val() { get().~T(); }
872 : };
873 :
874 : // This base class provides some handy member functions which can be used in
875 : // further derived classes
876 : template <class E>
877 : struct expected_operations_base<void, E> : expected_storage_base<void, E> {
878 : using expected_storage_base<void, E>::expected_storage_base;
879 :
880 : template <class... Args> void construct() noexcept { this->m_has_val = true; }
881 :
882 : // This function doesn't use its argument, but needs it so that code in
883 : // levels above this can work independently of whether T is void
884 : template <class Rhs> void construct_with(Rhs &&) noexcept {
885 : this->m_has_val = true;
886 : }
887 :
888 : template <class... Args> void construct_error(Args &&...args) noexcept {
889 : new (std::addressof(this->m_unexpect))
890 : unexpected<E>(std::forward<Args>(args)...);
891 : this->m_has_val = false;
892 : }
893 :
894 : template <class Rhs> void assign(Rhs &&rhs) noexcept {
895 : if (!this->m_has_val) {
896 : if (rhs.m_has_val) {
897 : geterr().~unexpected<E>();
898 : construct();
899 : } else {
900 : geterr() = std::forward<Rhs>(rhs).geterr();
901 : }
902 : } else {
903 : if (!rhs.m_has_val) {
904 : construct_error(std::forward<Rhs>(rhs).geterr());
905 : }
906 : }
907 : }
908 :
909 : bool has_value() const { return this->m_has_val; }
910 :
911 : TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & {
912 : return this->m_unexpect;
913 : }
914 : constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; }
915 : TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && {
916 : return std::move(this->m_unexpect);
917 : }
918 : #ifndef TL_EXPECTED_NO_CONSTRR
919 : constexpr const unexpected<E> &&geterr() const && {
920 : return std::move(this->m_unexpect);
921 : }
922 : #endif
923 :
924 : TL_EXPECTED_11_CONSTEXPR void destroy_val() {
925 : // no-op
926 : }
927 : };
928 :
929 : // This class manages conditionally having a trivial copy constructor
930 : // This specialization is for when T and E are trivially copy constructible
931 : template <class T, class E,
932 : bool = is_void_or<T, TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)>::
933 : value &&TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value>
934 : struct expected_copy_base : expected_operations_base<T, E> {
935 : using expected_operations_base<T, E>::expected_operations_base;
936 : };
937 :
938 : // This specialization is for when T or E are not trivially copy constructible
939 : template <class T, class E>
940 2474780 : struct expected_copy_base<T, E, false> : expected_operations_base<T, E> {
941 1423444 : using expected_operations_base<T, E>::expected_operations_base;
942 :
943 37098 : expected_copy_base() = default;
944 153205 : expected_copy_base(const expected_copy_base &rhs)
945 153205 : : expected_operations_base<T, E>(no_init) {
946 153205 : if (rhs.has_value()) {
947 45952 : this->construct_with(rhs);
948 : } else {
949 107253 : this->construct_error(rhs.geterr());
950 : }
951 153205 : }
952 :
953 : expected_copy_base(expected_copy_base &&rhs) = default;
954 : expected_copy_base &operator=(const expected_copy_base &rhs) = default;
955 : expected_copy_base &operator=(expected_copy_base &&rhs) = default;
956 : };
957 :
958 : // This class manages conditionally having a trivial move constructor
959 : // Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
960 : // doesn't implement an analogue to std::is_trivially_move_constructible. We
961 : // have to make do with a non-trivial move constructor even if T is trivially
962 : // move constructible
963 : #ifndef TL_EXPECTED_GCC49
964 : template <class T, class E,
965 : bool = is_void_or<T, std::is_trivially_move_constructible<T>>::value
966 : &&std::is_trivially_move_constructible<E>::value>
967 : struct expected_move_base : expected_copy_base<T, E> {
968 : using expected_copy_base<T, E>::expected_copy_base;
969 : };
970 : #else
971 : template <class T, class E, bool = false> struct expected_move_base;
972 : #endif
973 : template <class T, class E>
974 2474780 : struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
975 1256318 : using expected_copy_base<T, E>::expected_copy_base;
976 :
977 37098 : expected_move_base() = default;
978 153205 : expected_move_base(const expected_move_base &rhs) = default;
979 :
980 167126 : expected_move_base(expected_move_base &&rhs) noexcept(
981 : std::is_nothrow_move_constructible<T>::value)
982 167126 : : expected_copy_base<T, E>(no_init) {
983 167126 : if (rhs.has_value()) {
984 97964 : this->construct_with(std::move(rhs));
985 : } else {
986 8 : this->construct_error(std::move(rhs.geterr()));
987 : }
988 8 : }
989 : expected_move_base &operator=(const expected_move_base &rhs) = default;
990 : expected_move_base &operator=(expected_move_base &&rhs) = default;
991 : };
992 :
993 : // This class manages conditionally having a trivial copy assignment operator
994 : template <class T, class E,
995 : bool = is_void_or<
996 : T, conjunction<TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T),
997 : TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T),
998 : TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T)>>::value
999 : &&TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(E)::value
1000 : &&TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value
1001 : &&TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(E)::value>
1002 : struct expected_copy_assign_base : expected_move_base<T, E> {
1003 : using expected_move_base<T, E>::expected_move_base;
1004 : };
1005 :
1006 : template <class T, class E>
1007 2474780 : struct expected_copy_assign_base<T, E, false> : expected_move_base<T, E> {
1008 1256318 : using expected_move_base<T, E>::expected_move_base;
1009 :
1010 37098 : expected_copy_assign_base() = default;
1011 306410 : expected_copy_assign_base(const expected_copy_assign_base &rhs) = default;
1012 :
1013 265092 : expected_copy_assign_base(expected_copy_assign_base &&rhs) = default;
1014 : expected_copy_assign_base &operator=(const expected_copy_assign_base &rhs) {
1015 : this->assign(rhs);
1016 : return *this;
1017 : }
1018 : expected_copy_assign_base &
1019 : operator=(expected_copy_assign_base &&rhs) = default;
1020 : };
1021 :
1022 : // This class manages conditionally having a trivial move assignment operator
1023 : // Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
1024 : // doesn't implement an analogue to std::is_trivially_move_assignable. We have
1025 : // to make do with a non-trivial move assignment operator even if T is trivially
1026 : // move assignable
1027 : #ifndef TL_EXPECTED_GCC49
1028 : template <class T, class E,
1029 : bool =
1030 : is_void_or<T, conjunction<std::is_trivially_destructible<T>,
1031 : std::is_trivially_move_constructible<T>,
1032 : std::is_trivially_move_assignable<T>>>::
1033 : value &&std::is_trivially_destructible<E>::value
1034 : &&std::is_trivially_move_constructible<E>::value
1035 : &&std::is_trivially_move_assignable<E>::value>
1036 : struct expected_move_assign_base : expected_copy_assign_base<T, E> {
1037 : using expected_copy_assign_base<T, E>::expected_copy_assign_base;
1038 : };
1039 : #else
1040 : template <class T, class E, bool = false> struct expected_move_assign_base;
1041 : #endif
1042 :
1043 : template <class T, class E>
1044 2474780 : struct expected_move_assign_base<T, E, false>
1045 : : expected_copy_assign_base<T, E> {
1046 1256318 : using expected_copy_assign_base<T, E>::expected_copy_assign_base;
1047 :
1048 37098 : expected_move_assign_base() = default;
1049 306410 : expected_move_assign_base(const expected_move_assign_base &rhs) = default;
1050 :
1051 265098 : expected_move_assign_base(expected_move_assign_base &&rhs) = default;
1052 :
1053 : expected_move_assign_base &
1054 : operator=(const expected_move_assign_base &rhs) = default;
1055 :
1056 : expected_move_assign_base &
1057 64778 : operator=(expected_move_assign_base &&rhs) noexcept(
1058 : std::is_nothrow_move_constructible<T>::value
1059 : &&std::is_nothrow_move_assignable<T>::value) {
1060 64778 : this->assign(std::move(rhs));
1061 : return *this;
1062 : }
1063 : };
1064 :
1065 : // expected_delete_ctor_base will conditionally delete copy and move
1066 : // constructors depending on whether T is copy/move constructible
1067 : template <class T, class E,
1068 : bool EnableCopy = (is_copy_constructible_or_void<T>::value &&
1069 : std::is_copy_constructible<E>::value),
1070 : bool EnableMove = (is_move_constructible_or_void<T>::value &&
1071 : std::is_move_constructible<E>::value)>
1072 : struct expected_delete_ctor_base {
1073 : expected_delete_ctor_base() = default;
1074 : expected_delete_ctor_base(const expected_delete_ctor_base &) = default;
1075 : expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default;
1076 : expected_delete_ctor_base &
1077 : operator=(const expected_delete_ctor_base &) = default;
1078 : expected_delete_ctor_base &
1079 : operator=(expected_delete_ctor_base &&) noexcept = default;
1080 : };
1081 :
1082 : template <class T, class E>
1083 : struct expected_delete_ctor_base<T, E, true, false> {
1084 : expected_delete_ctor_base() = default;
1085 : expected_delete_ctor_base(const expected_delete_ctor_base &) = default;
1086 : expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete;
1087 : expected_delete_ctor_base &
1088 : operator=(const expected_delete_ctor_base &) = default;
1089 : expected_delete_ctor_base &
1090 : operator=(expected_delete_ctor_base &&) noexcept = default;
1091 : };
1092 :
1093 : template <class T, class E>
1094 : struct expected_delete_ctor_base<T, E, false, true> {
1095 : expected_delete_ctor_base() = default;
1096 : expected_delete_ctor_base(const expected_delete_ctor_base &) = delete;
1097 : expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default;
1098 : expected_delete_ctor_base &
1099 : operator=(const expected_delete_ctor_base &) = default;
1100 : expected_delete_ctor_base &
1101 : operator=(expected_delete_ctor_base &&) noexcept = default;
1102 : };
1103 :
1104 : template <class T, class E>
1105 : struct expected_delete_ctor_base<T, E, false, false> {
1106 : expected_delete_ctor_base() = default;
1107 : expected_delete_ctor_base(const expected_delete_ctor_base &) = delete;
1108 : expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete;
1109 : expected_delete_ctor_base &
1110 : operator=(const expected_delete_ctor_base &) = default;
1111 : expected_delete_ctor_base &
1112 : operator=(expected_delete_ctor_base &&) noexcept = default;
1113 : };
1114 :
1115 : // expected_delete_assign_base will conditionally delete copy and move
1116 : // constructors depending on whether T and E are copy/move constructible +
1117 : // assignable
1118 : template <class T, class E,
1119 : bool EnableCopy = (is_copy_constructible_or_void<T>::value &&
1120 : std::is_copy_constructible<E>::value &&
1121 : is_copy_assignable_or_void<T>::value &&
1122 : std::is_copy_assignable<E>::value),
1123 : bool EnableMove = (is_move_constructible_or_void<T>::value &&
1124 : std::is_move_constructible<E>::value &&
1125 : is_move_assignable_or_void<T>::value &&
1126 : std::is_move_assignable<E>::value)>
1127 : struct expected_delete_assign_base {
1128 : expected_delete_assign_base() = default;
1129 : expected_delete_assign_base(const expected_delete_assign_base &) = default;
1130 : expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
1131 : default;
1132 : expected_delete_assign_base &
1133 : operator=(const expected_delete_assign_base &) = default;
1134 : expected_delete_assign_base &
1135 : operator=(expected_delete_assign_base &&) noexcept = default;
1136 : };
1137 :
1138 : template <class T, class E>
1139 : struct expected_delete_assign_base<T, E, true, false> {
1140 : expected_delete_assign_base() = default;
1141 : expected_delete_assign_base(const expected_delete_assign_base &) = default;
1142 : expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
1143 : default;
1144 : expected_delete_assign_base &
1145 : operator=(const expected_delete_assign_base &) = default;
1146 : expected_delete_assign_base &
1147 : operator=(expected_delete_assign_base &&) noexcept = delete;
1148 : };
1149 :
1150 : template <class T, class E>
1151 : struct expected_delete_assign_base<T, E, false, true> {
1152 : expected_delete_assign_base() = default;
1153 : expected_delete_assign_base(const expected_delete_assign_base &) = default;
1154 : expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
1155 : default;
1156 : expected_delete_assign_base &
1157 : operator=(const expected_delete_assign_base &) = delete;
1158 : expected_delete_assign_base &
1159 : operator=(expected_delete_assign_base &&) noexcept = default;
1160 : };
1161 :
1162 : template <class T, class E>
1163 : struct expected_delete_assign_base<T, E, false, false> {
1164 : expected_delete_assign_base() = default;
1165 : expected_delete_assign_base(const expected_delete_assign_base &) = default;
1166 : expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
1167 : default;
1168 : expected_delete_assign_base &
1169 : operator=(const expected_delete_assign_base &) = delete;
1170 : expected_delete_assign_base &
1171 : operator=(expected_delete_assign_base &&) noexcept = delete;
1172 : };
1173 :
1174 : // This is needed to be able to construct the expected_default_ctor_base which
1175 : // follows, while still conditionally deleting the default constructor.
1176 : struct default_constructor_tag {
1177 : explicit constexpr default_constructor_tag() = default;
1178 : };
1179 :
1180 : // expected_default_ctor_base will ensure that expected has a deleted default
1181 : // consturctor if T is not default constructible.
1182 : // This specialization is for when T is default constructible
1183 : template <class T, class E,
1184 : bool Enable =
1185 : std::is_default_constructible<T>::value || std::is_void<T>::value>
1186 : struct expected_default_ctor_base {
1187 : constexpr expected_default_ctor_base() noexcept = default;
1188 : constexpr expected_default_ctor_base(
1189 : expected_default_ctor_base const &) noexcept = default;
1190 : constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept =
1191 : default;
1192 : expected_default_ctor_base &
1193 : operator=(expected_default_ctor_base const &) noexcept = default;
1194 : expected_default_ctor_base &
1195 : operator=(expected_default_ctor_base &&) noexcept = default;
1196 :
1197 584225 : constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
1198 : };
1199 :
1200 : // This specialization is for when T is not default constructible
1201 : template <class T, class E> struct expected_default_ctor_base<T, E, false> {
1202 : constexpr expected_default_ctor_base() noexcept = delete;
1203 : constexpr expected_default_ctor_base(
1204 : expected_default_ctor_base const &) noexcept = default;
1205 : constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept =
1206 : default;
1207 : expected_default_ctor_base &
1208 : operator=(expected_default_ctor_base const &) noexcept = default;
1209 : expected_default_ctor_base &
1210 : operator=(expected_default_ctor_base &&) noexcept = default;
1211 :
1212 339490 : constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
1213 : };
1214 : } // namespace detail
1215 :
1216 : template <class E> class bad_expected_access : public std::exception {
1217 : public:
1218 0 : explicit bad_expected_access(E e) : m_val(std::move(e)) {}
1219 :
1220 0 : virtual const char *what() const noexcept override {
1221 0 : return "Bad expected access";
1222 : }
1223 :
1224 : const E &error() const & { return m_val; }
1225 : E &error() & { return m_val; }
1226 : const E &&error() const && { return std::move(m_val); }
1227 : E &&error() && { return std::move(m_val); }
1228 :
1229 : private:
1230 : E m_val;
1231 : };
1232 :
1233 : /// An `expected<T, E>` object is an object that contains the storage for
1234 : /// another object and manages the lifetime of this contained object `T`.
1235 : /// Alternatively it could contain the storage for another unexpected object
1236 : /// `E`. The contained object may not be initialized after the expected object
1237 : /// has been initialized, and may not be destroyed before the expected object
1238 : /// has been destroyed. The initialization state of the contained object is
1239 : /// tracked by the expected object.
1240 : template <class T, class E>
1241 1817874 : class expected : private detail::expected_move_assign_base<T, E>,
1242 : private detail::expected_delete_ctor_base<T, E>,
1243 : private detail::expected_delete_assign_base<T, E>,
1244 : private detail::expected_default_ctor_base<T, E> {
1245 : static_assert(!std::is_reference<T>::value, "T must not be a reference");
1246 : static_assert(!std::is_same<T, std::remove_cv<in_place_t>::type>::value,
1247 : "T must not be in_place_t");
1248 : static_assert(!std::is_same<T, std::remove_cv<unexpect_t>::type>::value,
1249 : "T must not be unexpect_t");
1250 : static_assert(
1251 : !std::is_same<T, typename std::remove_cv<unexpected<E>>::type>::value,
1252 : "T must not be unexpected<E>");
1253 : static_assert(!std::is_reference<E>::value, "E must not be a reference");
1254 :
1255 62478 : T *valptr() { return std::addressof(this->m_val); }
1256 : const T *valptr() const { return std::addressof(this->m_val); }
1257 : unexpected<E> *errptr() { return std::addressof(this->m_unexpect); }
1258 : const unexpected<E> *errptr() const {
1259 : return std::addressof(this->m_unexpect);
1260 : }
1261 :
1262 : template <class U = T,
1263 : detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
1264 738073 : TL_EXPECTED_11_CONSTEXPR U &val() {
1265 737266 : return this->m_val;
1266 : }
1267 : TL_EXPECTED_11_CONSTEXPR unexpected<E> &err() { return this->m_unexpect; }
1268 :
1269 : template <class U = T,
1270 : detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
1271 11877 : constexpr const U &val() const {
1272 11877 : return this->m_val;
1273 : }
1274 : constexpr const unexpected<E> &err() const { return this->m_unexpect; }
1275 :
1276 : using impl_base = detail::expected_move_assign_base<T, E>;
1277 : using ctor_base = detail::expected_default_ctor_base<T, E>;
1278 :
1279 : public:
1280 : typedef T value_type;
1281 : typedef E error_type;
1282 : typedef unexpected<E> unexpected_type;
1283 :
1284 : #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
1285 : !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
1286 226 : template <class F> TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & {
1287 226 : return and_then_impl(*this, std::forward<F>(f));
1288 : }
1289 117 : template <class F> TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && {
1290 39 : return and_then_impl(std::move(*this), std::forward<F>(f));
1291 : }
1292 : template <class F> constexpr auto and_then(F &&f) const & {
1293 : return and_then_impl(*this, std::forward<F>(f));
1294 : }
1295 :
1296 : #ifndef TL_EXPECTED_NO_CONSTRR
1297 : template <class F> constexpr auto and_then(F &&f) const && {
1298 : return and_then_impl(std::move(*this), std::forward<F>(f));
1299 : }
1300 : #endif
1301 :
1302 : #else
1303 : template <class F>
1304 : TL_EXPECTED_11_CONSTEXPR auto
1305 : and_then(F &&f) & -> decltype(and_then_impl(std::declval<expected &>(),
1306 : std::forward<F>(f))) {
1307 : return and_then_impl(*this, std::forward<F>(f));
1308 : }
1309 : template <class F>
1310 : TL_EXPECTED_11_CONSTEXPR auto
1311 : and_then(F &&f) && -> decltype(and_then_impl(std::declval<expected &&>(),
1312 : std::forward<F>(f))) {
1313 : return and_then_impl(std::move(*this), std::forward<F>(f));
1314 : }
1315 : template <class F>
1316 : constexpr auto and_then(F &&f) const & -> decltype(and_then_impl(
1317 : std::declval<expected const &>(), std::forward<F>(f))) {
1318 : return and_then_impl(*this, std::forward<F>(f));
1319 : }
1320 :
1321 : #ifndef TL_EXPECTED_NO_CONSTRR
1322 : template <class F>
1323 : constexpr auto and_then(F &&f) const && -> decltype(and_then_impl(
1324 : std::declval<expected const &&>(), std::forward<F>(f))) {
1325 : return and_then_impl(std::move(*this), std::forward<F>(f));
1326 : }
1327 : #endif
1328 : #endif
1329 :
1330 : #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
1331 : !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
1332 : template <class F> TL_EXPECTED_11_CONSTEXPR auto map(F &&f) & {
1333 : return expected_map_impl(*this, std::forward<F>(f));
1334 : }
1335 : template <class F> TL_EXPECTED_11_CONSTEXPR auto map(F &&f) && {
1336 : return expected_map_impl(std::move(*this), std::forward<F>(f));
1337 : }
1338 : template <class F> constexpr auto map(F &&f) const & {
1339 : return expected_map_impl(*this, std::forward<F>(f));
1340 : }
1341 : template <class F> constexpr auto map(F &&f) const && {
1342 : return expected_map_impl(std::move(*this), std::forward<F>(f));
1343 : }
1344 : #else
1345 : template <class F>
1346 : TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(
1347 : std::declval<expected &>(), std::declval<F &&>()))
1348 : map(F &&f) & {
1349 : return expected_map_impl(*this, std::forward<F>(f));
1350 : }
1351 : template <class F>
1352 : TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),
1353 : std::declval<F &&>()))
1354 : map(F &&f) && {
1355 : return expected_map_impl(std::move(*this), std::forward<F>(f));
1356 : }
1357 : template <class F>
1358 : constexpr decltype(expected_map_impl(std::declval<const expected &>(),
1359 : std::declval<F &&>()))
1360 : map(F &&f) const & {
1361 : return expected_map_impl(*this, std::forward<F>(f));
1362 : }
1363 :
1364 : #ifndef TL_EXPECTED_NO_CONSTRR
1365 : template <class F>
1366 : constexpr decltype(expected_map_impl(std::declval<const expected &&>(),
1367 : std::declval<F &&>()))
1368 : map(F &&f) const && {
1369 : return expected_map_impl(std::move(*this), std::forward<F>(f));
1370 : }
1371 : #endif
1372 : #endif
1373 :
1374 : #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
1375 : !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
1376 : template <class F> TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) & {
1377 : return expected_map_impl(*this, std::forward<F>(f));
1378 : }
1379 : template <class F> TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) && {
1380 : return expected_map_impl(std::move(*this), std::forward<F>(f));
1381 : }
1382 : template <class F> constexpr auto transform(F &&f) const & {
1383 : return expected_map_impl(*this, std::forward<F>(f));
1384 : }
1385 : template <class F> constexpr auto transform(F &&f) const && {
1386 : return expected_map_impl(std::move(*this), std::forward<F>(f));
1387 : }
1388 : #else
1389 : template <class F>
1390 : TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(
1391 : std::declval<expected &>(), std::declval<F &&>()))
1392 : transform(F &&f) & {
1393 : return expected_map_impl(*this, std::forward<F>(f));
1394 : }
1395 : template <class F>
1396 : TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval<expected>(),
1397 : std::declval<F &&>()))
1398 : transform(F &&f) && {
1399 : return expected_map_impl(std::move(*this), std::forward<F>(f));
1400 : }
1401 : template <class F>
1402 : constexpr decltype(expected_map_impl(std::declval<const expected &>(),
1403 : std::declval<F &&>()))
1404 : transform(F &&f) const & {
1405 : return expected_map_impl(*this, std::forward<F>(f));
1406 : }
1407 :
1408 : #ifndef TL_EXPECTED_NO_CONSTRR
1409 : template <class F>
1410 : constexpr decltype(expected_map_impl(std::declval<const expected &&>(),
1411 : std::declval<F &&>()))
1412 : transform(F &&f) const && {
1413 : return expected_map_impl(std::move(*this), std::forward<F>(f));
1414 : }
1415 : #endif
1416 : #endif
1417 :
1418 : #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
1419 : !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
1420 : template <class F> TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) & {
1421 : return map_error_impl(*this, std::forward<F>(f));
1422 : }
1423 : template <class F> TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) && {
1424 : return map_error_impl(std::move(*this), std::forward<F>(f));
1425 : }
1426 : template <class F> constexpr auto map_error(F &&f) const & {
1427 : return map_error_impl(*this, std::forward<F>(f));
1428 : }
1429 : template <class F> constexpr auto map_error(F &&f) const && {
1430 : return map_error_impl(std::move(*this), std::forward<F>(f));
1431 : }
1432 : #else
1433 : template <class F>
1434 : TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),
1435 : std::declval<F &&>()))
1436 : map_error(F &&f) & {
1437 : return map_error_impl(*this, std::forward<F>(f));
1438 : }
1439 : template <class F>
1440 : TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),
1441 : std::declval<F &&>()))
1442 : map_error(F &&f) && {
1443 : return map_error_impl(std::move(*this), std::forward<F>(f));
1444 : }
1445 : template <class F>
1446 : constexpr decltype(map_error_impl(std::declval<const expected &>(),
1447 : std::declval<F &&>()))
1448 : map_error(F &&f) const & {
1449 : return map_error_impl(*this, std::forward<F>(f));
1450 : }
1451 :
1452 : #ifndef TL_EXPECTED_NO_CONSTRR
1453 : template <class F>
1454 : constexpr decltype(map_error_impl(std::declval<const expected &&>(),
1455 : std::declval<F &&>()))
1456 : map_error(F &&f) const && {
1457 : return map_error_impl(std::move(*this), std::forward<F>(f));
1458 : }
1459 : #endif
1460 : #endif
1461 : #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
1462 : !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
1463 : template <class F> TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) & {
1464 : return map_error_impl(*this, std::forward<F>(f));
1465 : }
1466 : template <class F> TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) && {
1467 : return map_error_impl(std::move(*this), std::forward<F>(f));
1468 : }
1469 : template <class F> constexpr auto transform_error(F &&f) const & {
1470 : return map_error_impl(*this, std::forward<F>(f));
1471 : }
1472 : template <class F> constexpr auto transform_error(F &&f) const && {
1473 : return map_error_impl(std::move(*this), std::forward<F>(f));
1474 : }
1475 : #else
1476 : template <class F>
1477 : TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(),
1478 : std::declval<F &&>()))
1479 : transform_error(F &&f) & {
1480 : return map_error_impl(*this, std::forward<F>(f));
1481 : }
1482 : template <class F>
1483 : TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(),
1484 : std::declval<F &&>()))
1485 : transform_error(F &&f) && {
1486 : return map_error_impl(std::move(*this), std::forward<F>(f));
1487 : }
1488 : template <class F>
1489 : constexpr decltype(map_error_impl(std::declval<const expected &>(),
1490 : std::declval<F &&>()))
1491 : transform_error(F &&f) const & {
1492 : return map_error_impl(*this, std::forward<F>(f));
1493 : }
1494 :
1495 : #ifndef TL_EXPECTED_NO_CONSTRR
1496 : template <class F>
1497 : constexpr decltype(map_error_impl(std::declval<const expected &&>(),
1498 : std::declval<F &&>()))
1499 : transform_error(F &&f) const && {
1500 : return map_error_impl(std::move(*this), std::forward<F>(f));
1501 : }
1502 : #endif
1503 : #endif
1504 : template <class F> expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) & {
1505 : return or_else_impl(*this, std::forward<F>(f));
1506 : }
1507 :
1508 : template <class F> expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) && {
1509 : return or_else_impl(std::move(*this), std::forward<F>(f));
1510 : }
1511 :
1512 : template <class F> expected constexpr or_else(F &&f) const & {
1513 : return or_else_impl(*this, std::forward<F>(f));
1514 : }
1515 :
1516 : #ifndef TL_EXPECTED_NO_CONSTRR
1517 : template <class F> expected constexpr or_else(F &&f) const && {
1518 : return or_else_impl(std::move(*this), std::forward<F>(f));
1519 : }
1520 : #endif
1521 : constexpr expected() = default;
1522 153205 : constexpr expected(const expected &rhs) = default;
1523 265092 : constexpr expected(expected &&rhs) = default;
1524 : expected &operator=(const expected &rhs) = default;
1525 64778 : expected &operator=(expected &&rhs) = default;
1526 :
1527 : template <class... Args,
1528 : detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
1529 : nullptr>
1530 758024 : constexpr expected(in_place_t, Args &&...args)
1531 : : impl_base(in_place, std::forward<Args>(args)...),
1532 1020191 : ctor_base(detail::default_constructor_tag{}) {}
1533 :
1534 : template <class U, class... Args,
1535 : detail::enable_if_t<std::is_constructible<
1536 : T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
1537 : constexpr expected(in_place_t, std::initializer_list<U> il, Args &&...args)
1538 : : impl_base(in_place, il, std::forward<Args>(args)...),
1539 : ctor_base(detail::default_constructor_tag{}) {}
1540 :
1541 : template <class G = E,
1542 : detail::enable_if_t<std::is_constructible<E, const G &>::value> * =
1543 : nullptr,
1544 : detail::enable_if_t<!std::is_convertible<const G &, E>::value> * =
1545 : nullptr>
1546 : explicit constexpr expected(const unexpected<G> &e)
1547 : : impl_base(unexpect, e.value()),
1548 : ctor_base(detail::default_constructor_tag{}) {}
1549 :
1550 : template <
1551 : class G = E,
1552 : detail::enable_if_t<std::is_constructible<E, const G &>::value> * =
1553 : nullptr,
1554 : detail::enable_if_t<std::is_convertible<const G &, E>::value> * = nullptr>
1555 : constexpr expected(unexpected<G> const &e)
1556 : : impl_base(unexpect, e.value()),
1557 : ctor_base(detail::default_constructor_tag{}) {}
1558 :
1559 : template <
1560 : class G = E,
1561 : detail::enable_if_t<std::is_constructible<E, G &&>::value> * = nullptr,
1562 : detail::enable_if_t<!std::is_convertible<G &&, E>::value> * = nullptr>
1563 : explicit constexpr expected(unexpected<G> &&e) noexcept(
1564 : std::is_nothrow_constructible<E, G &&>::value)
1565 : : impl_base(unexpect, std::move(e.value())),
1566 : ctor_base(detail::default_constructor_tag{}) {}
1567 :
1568 : template <
1569 : class G = E,
1570 : detail::enable_if_t<std::is_constructible<E, G &&>::value> * = nullptr,
1571 : detail::enable_if_t<std::is_convertible<G &&, E>::value> * = nullptr>
1572 128571 : constexpr expected(unexpected<G> &&e) noexcept(
1573 : std::is_nothrow_constructible<E, G &&>::value)
1574 128571 : : impl_base(unexpect, std::move(e.value())),
1575 128571 : ctor_base(detail::default_constructor_tag{}) {}
1576 :
1577 : template <class... Args,
1578 : detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
1579 : nullptr>
1580 22 : constexpr explicit expected(unexpect_t, Args &&...args)
1581 : : impl_base(unexpect, std::forward<Args>(args)...),
1582 22 : ctor_base(detail::default_constructor_tag{}) {}
1583 :
1584 : template <class U, class... Args,
1585 : detail::enable_if_t<std::is_constructible<
1586 : E, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
1587 : constexpr explicit expected(unexpect_t, std::initializer_list<U> il,
1588 : Args &&...args)
1589 : : impl_base(unexpect, il, std::forward<Args>(args)...),
1590 : ctor_base(detail::default_constructor_tag{}) {}
1591 :
1592 : template <class U, class G,
1593 : detail::enable_if_t<!(std::is_convertible<U const &, T>::value &&
1594 : std::is_convertible<G const &, E>::value)> * =
1595 : nullptr,
1596 : detail::expected_enable_from_other<T, E, U, G, const U &, const G &>
1597 : * = nullptr>
1598 : explicit TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs)
1599 : : ctor_base(detail::default_constructor_tag{}) {
1600 : if (rhs.has_value()) {
1601 : this->construct(*rhs);
1602 : } else {
1603 : this->construct_error(rhs.error());
1604 : }
1605 : }
1606 :
1607 : template <class U, class G,
1608 : detail::enable_if_t<(std::is_convertible<U const &, T>::value &&
1609 : std::is_convertible<G const &, E>::value)> * =
1610 : nullptr,
1611 : detail::expected_enable_from_other<T, E, U, G, const U &, const G &>
1612 : * = nullptr>
1613 : TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs)
1614 : : ctor_base(detail::default_constructor_tag{}) {
1615 : if (rhs.has_value()) {
1616 : this->construct(*rhs);
1617 : } else {
1618 : this->construct_error(rhs.error());
1619 : }
1620 : }
1621 :
1622 : template <
1623 : class U, class G,
1624 : detail::enable_if_t<!(std::is_convertible<U &&, T>::value &&
1625 : std::is_convertible<G &&, E>::value)> * = nullptr,
1626 : detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr>
1627 : explicit TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs)
1628 : : ctor_base(detail::default_constructor_tag{}) {
1629 : if (rhs.has_value()) {
1630 : this->construct(std::move(*rhs));
1631 : } else {
1632 : this->construct_error(std::move(rhs.error()));
1633 : }
1634 : }
1635 :
1636 : template <
1637 : class U, class G,
1638 : detail::enable_if_t<(std::is_convertible<U &&, T>::value &&
1639 : std::is_convertible<G &&, E>::value)> * = nullptr,
1640 : detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr>
1641 37098 : TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs)
1642 37098 : : ctor_base(detail::default_constructor_tag{}) {
1643 37098 : if (rhs.has_value()) {
1644 37096 : this->construct(std::move(*rhs));
1645 : } else {
1646 2 : this->construct_error(std::move(rhs.error()));
1647 : }
1648 37098 : }
1649 :
1650 : template <
1651 : class U = T,
1652 : detail::enable_if_t<!std::is_convertible<U &&, T>::value> * = nullptr,
1653 : detail::expected_enable_forward_value<T, E, U> * = nullptr>
1654 : explicit TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v)
1655 : : expected(in_place, std::forward<U>(v)) {}
1656 :
1657 : template <
1658 : class U = T,
1659 : detail::enable_if_t<std::is_convertible<U &&, T>::value> * = nullptr,
1660 : detail::expected_enable_forward_value<T, E, U> * = nullptr>
1661 757993 : TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v)
1662 757995 : : expected(in_place, std::forward<U>(v)) {}
1663 :
1664 : template <
1665 : class U = T, class G = T,
1666 : detail::enable_if_t<std::is_nothrow_constructible<T, U &&>::value> * =
1667 : nullptr,
1668 : detail::enable_if_t<!std::is_void<G>::value> * = nullptr,
1669 : detail::enable_if_t<
1670 : (!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
1671 : !detail::conjunction<std::is_scalar<T>,
1672 : std::is_same<T, detail::decay_t<U>>>::value &&
1673 : std::is_constructible<T, U>::value &&
1674 : std::is_assignable<G &, U>::value &&
1675 : std::is_nothrow_move_constructible<E>::value)> * = nullptr>
1676 1615 : expected &operator=(U &&v) {
1677 1615 : if (has_value()) {
1678 186 : val() = std::forward<U>(v);
1679 : } else {
1680 1429 : err().~unexpected<E>();
1681 1429 : ::new (valptr()) T(std::forward<U>(v));
1682 1429 : this->m_has_val = true;
1683 : }
1684 :
1685 1615 : return *this;
1686 : }
1687 :
1688 : template <
1689 : class U = T, class G = T,
1690 : detail::enable_if_t<!std::is_nothrow_constructible<T, U &&>::value> * =
1691 : nullptr,
1692 : detail::enable_if_t<!std::is_void<U>::value> * = nullptr,
1693 : detail::enable_if_t<
1694 : (!std::is_same<expected<T, E>, detail::decay_t<U>>::value &&
1695 : !detail::conjunction<std::is_scalar<T>,
1696 : std::is_same<T, detail::decay_t<U>>>::value &&
1697 : std::is_constructible<T, U>::value &&
1698 : std::is_assignable<G &, U>::value &&
1699 : std::is_nothrow_move_constructible<E>::value)> * = nullptr>
1700 : expected &operator=(U &&v) {
1701 : if (has_value()) {
1702 : val() = std::forward<U>(v);
1703 : } else {
1704 : auto tmp = std::move(err());
1705 : err().~unexpected<E>();
1706 :
1707 : #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
1708 : try {
1709 : ::new (valptr()) T(std::forward<U>(v));
1710 : this->m_has_val = true;
1711 : } catch (...) {
1712 : err() = std::move(tmp);
1713 : throw;
1714 : }
1715 : #else
1716 : ::new (valptr()) T(std::forward<U>(v));
1717 : this->m_has_val = true;
1718 : #endif
1719 : }
1720 :
1721 : return *this;
1722 : }
1723 :
1724 : template <class G = E,
1725 : detail::enable_if_t<std::is_nothrow_copy_constructible<G>::value &&
1726 : std::is_assignable<G &, G>::value> * = nullptr>
1727 : expected &operator=(const unexpected<G> &rhs) {
1728 : if (!has_value()) {
1729 : err() = rhs;
1730 : } else {
1731 : this->destroy_val();
1732 : ::new (errptr()) unexpected<E>(rhs);
1733 : this->m_has_val = false;
1734 : }
1735 :
1736 : return *this;
1737 : }
1738 :
1739 : template <class G = E,
1740 : detail::enable_if_t<std::is_nothrow_move_constructible<G>::value &&
1741 : std::is_move_assignable<G>::value> * = nullptr>
1742 : expected &operator=(unexpected<G> &&rhs) noexcept {
1743 : if (!has_value()) {
1744 : err() = std::move(rhs);
1745 : } else {
1746 : this->destroy_val();
1747 : ::new (errptr()) unexpected<E>(std::move(rhs));
1748 : this->m_has_val = false;
1749 : }
1750 :
1751 : return *this;
1752 : }
1753 :
1754 : template <class... Args, detail::enable_if_t<std::is_nothrow_constructible<
1755 : T, Args &&...>::value> * = nullptr>
1756 : void emplace(Args &&...args) {
1757 : if (has_value()) {
1758 : val().~T();
1759 : } else {
1760 : err().~unexpected<E>();
1761 : this->m_has_val = true;
1762 : }
1763 : ::new (valptr()) T(std::forward<Args>(args)...);
1764 : }
1765 :
1766 : template <class... Args, detail::enable_if_t<!std::is_nothrow_constructible<
1767 : T, Args &&...>::value> * = nullptr>
1768 : void emplace(Args &&...args) {
1769 : if (has_value()) {
1770 : val().~T();
1771 : ::new (valptr()) T(std::forward<Args>(args)...);
1772 : } else {
1773 : auto tmp = std::move(err());
1774 : err().~unexpected<E>();
1775 :
1776 : #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
1777 : try {
1778 : ::new (valptr()) T(std::forward<Args>(args)...);
1779 : this->m_has_val = true;
1780 : } catch (...) {
1781 : err() = std::move(tmp);
1782 : throw;
1783 : }
1784 : #else
1785 : ::new (valptr()) T(std::forward<Args>(args)...);
1786 : this->m_has_val = true;
1787 : #endif
1788 : }
1789 : }
1790 :
1791 : template <class U, class... Args,
1792 : detail::enable_if_t<std::is_nothrow_constructible<
1793 : T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
1794 : void emplace(std::initializer_list<U> il, Args &&...args) {
1795 : if (has_value()) {
1796 : T t(il, std::forward<Args>(args)...);
1797 : val() = std::move(t);
1798 : } else {
1799 : err().~unexpected<E>();
1800 : ::new (valptr()) T(il, std::forward<Args>(args)...);
1801 : this->m_has_val = true;
1802 : }
1803 : }
1804 :
1805 : template <class U, class... Args,
1806 : detail::enable_if_t<!std::is_nothrow_constructible<
1807 : T, std::initializer_list<U> &, Args &&...>::value> * = nullptr>
1808 : void emplace(std::initializer_list<U> il, Args &&...args) {
1809 : if (has_value()) {
1810 : T t(il, std::forward<Args>(args)...);
1811 : val() = std::move(t);
1812 : } else {
1813 : auto tmp = std::move(err());
1814 : err().~unexpected<E>();
1815 :
1816 : #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
1817 : try {
1818 : ::new (valptr()) T(il, std::forward<Args>(args)...);
1819 : this->m_has_val = true;
1820 : } catch (...) {
1821 : err() = std::move(tmp);
1822 : throw;
1823 : }
1824 : #else
1825 : ::new (valptr()) T(il, std::forward<Args>(args)...);
1826 : this->m_has_val = true;
1827 : #endif
1828 : }
1829 : }
1830 :
1831 : private:
1832 : using t_is_void = std::true_type;
1833 : using t_is_not_void = std::false_type;
1834 : using t_is_nothrow_move_constructible = std::true_type;
1835 : using move_constructing_t_can_throw = std::false_type;
1836 : using e_is_nothrow_move_constructible = std::true_type;
1837 : using move_constructing_e_can_throw = std::false_type;
1838 :
1839 : void swap_where_both_have_value(expected & /*rhs*/, t_is_void) noexcept {
1840 : // swapping void is a no-op
1841 : }
1842 :
1843 : void swap_where_both_have_value(expected &rhs, t_is_not_void) {
1844 : using std::swap;
1845 : swap(val(), rhs.val());
1846 : }
1847 :
1848 : void swap_where_only_one_has_value(expected &rhs, t_is_void) noexcept(
1849 : std::is_nothrow_move_constructible<E>::value) {
1850 : ::new (errptr()) unexpected_type(std::move(rhs.err()));
1851 : rhs.err().~unexpected_type();
1852 : std::swap(this->m_has_val, rhs.m_has_val);
1853 : }
1854 :
1855 : void swap_where_only_one_has_value(expected &rhs, t_is_not_void) {
1856 : swap_where_only_one_has_value_and_t_is_not_void(
1857 : rhs, typename std::is_nothrow_move_constructible<T>::type{},
1858 : typename std::is_nothrow_move_constructible<E>::type{});
1859 : }
1860 :
1861 : void swap_where_only_one_has_value_and_t_is_not_void(
1862 : expected &rhs, t_is_nothrow_move_constructible,
1863 : e_is_nothrow_move_constructible) noexcept {
1864 : auto temp = std::move(val());
1865 : val().~T();
1866 : ::new (errptr()) unexpected_type(std::move(rhs.err()));
1867 : rhs.err().~unexpected_type();
1868 : ::new (rhs.valptr()) T(std::move(temp));
1869 : std::swap(this->m_has_val, rhs.m_has_val);
1870 : }
1871 :
1872 : void swap_where_only_one_has_value_and_t_is_not_void(
1873 : expected &rhs, t_is_nothrow_move_constructible,
1874 : move_constructing_e_can_throw) {
1875 : auto temp = std::move(val());
1876 : val().~T();
1877 : #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
1878 : try {
1879 : ::new (errptr()) unexpected_type(std::move(rhs.err()));
1880 : rhs.err().~unexpected_type();
1881 : ::new (rhs.valptr()) T(std::move(temp));
1882 : std::swap(this->m_has_val, rhs.m_has_val);
1883 : } catch (...) {
1884 : val() = std::move(temp);
1885 : throw;
1886 : }
1887 : #else
1888 : ::new (errptr()) unexpected_type(std::move(rhs.err()));
1889 : rhs.err().~unexpected_type();
1890 : ::new (rhs.valptr()) T(std::move(temp));
1891 : std::swap(this->m_has_val, rhs.m_has_val);
1892 : #endif
1893 : }
1894 :
1895 : void swap_where_only_one_has_value_and_t_is_not_void(
1896 : expected &rhs, move_constructing_t_can_throw,
1897 : e_is_nothrow_move_constructible) {
1898 : auto temp = std::move(rhs.err());
1899 : rhs.err().~unexpected_type();
1900 : #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
1901 : try {
1902 : ::new (rhs.valptr()) T(std::move(val()));
1903 : val().~T();
1904 : ::new (errptr()) unexpected_type(std::move(temp));
1905 : std::swap(this->m_has_val, rhs.m_has_val);
1906 : } catch (...) {
1907 : rhs.err() = std::move(temp);
1908 : throw;
1909 : }
1910 : #else
1911 : ::new (rhs.valptr()) T(std::move(val()));
1912 : val().~T();
1913 : ::new (errptr()) unexpected_type(std::move(temp));
1914 : std::swap(this->m_has_val, rhs.m_has_val);
1915 : #endif
1916 : }
1917 :
1918 : public:
1919 : template <class OT = T, class OE = E>
1920 : detail::enable_if_t<detail::is_swappable<OT>::value &&
1921 : detail::is_swappable<OE>::value &&
1922 : (std::is_nothrow_move_constructible<OT>::value ||
1923 : std::is_nothrow_move_constructible<OE>::value)>
1924 : swap(expected &rhs) noexcept(
1925 : std::is_nothrow_move_constructible<T>::value
1926 : &&detail::is_nothrow_swappable<T>::value
1927 : &&std::is_nothrow_move_constructible<E>::value
1928 : &&detail::is_nothrow_swappable<E>::value) {
1929 : if (has_value() && rhs.has_value()) {
1930 : swap_where_both_have_value(rhs, typename std::is_void<T>::type{});
1931 : } else if (!has_value() && rhs.has_value()) {
1932 : rhs.swap(*this);
1933 : } else if (has_value()) {
1934 : swap_where_only_one_has_value(rhs, typename std::is_void<T>::type{});
1935 : } else {
1936 : using std::swap;
1937 : swap(err(), rhs.err());
1938 : }
1939 : }
1940 :
1941 : constexpr const T *operator->() const {
1942 : TL_ASSERT(has_value());
1943 : return valptr();
1944 : }
1945 61049 : TL_EXPECTED_11_CONSTEXPR T *operator->() {
1946 0 : TL_ASSERT(has_value());
1947 61049 : return valptr();
1948 : }
1949 :
1950 : template <class U = T,
1951 : detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
1952 11877 : constexpr const U &operator*() const & {
1953 0 : TL_ASSERT(has_value());
1954 11877 : return val();
1955 : }
1956 : template <class U = T,
1957 : detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
1958 56012 : TL_EXPECTED_11_CONSTEXPR U &operator*() & {
1959 0 : TL_ASSERT(has_value());
1960 56012 : return val();
1961 : }
1962 : template <class U = T,
1963 : detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
1964 : constexpr const U &&operator*() const && {
1965 : TL_ASSERT(has_value());
1966 : return std::move(val());
1967 : }
1968 : template <class U = T,
1969 : detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
1970 95 : TL_EXPECTED_11_CONSTEXPR U &&operator*() && {
1971 0 : TL_ASSERT(has_value());
1972 95 : return std::move(val());
1973 : }
1974 :
1975 372588 : constexpr bool has_value() const noexcept { return this->m_has_val; }
1976 1053296 : constexpr explicit operator bool() const noexcept { return this->m_has_val; }
1977 :
1978 : template <class U = T,
1979 : detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
1980 : TL_EXPECTED_11_CONSTEXPR const U &value() const & {
1981 : if (!has_value())
1982 : detail::throw_exception(bad_expected_access<E>(err().value()));
1983 : return val();
1984 : }
1985 : template <class U = T,
1986 : detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
1987 681704 : TL_EXPECTED_11_CONSTEXPR U &value() & {
1988 681162 : if (!has_value())
1989 0 : detail::throw_exception(bad_expected_access<E>(err().value()));
1990 681704 : return val();
1991 : }
1992 : template <class U = T,
1993 : detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
1994 : TL_EXPECTED_11_CONSTEXPR const U &&value() const && {
1995 : if (!has_value())
1996 : detail::throw_exception(bad_expected_access<E>(std::move(err()).value()));
1997 : return std::move(val());
1998 : }
1999 : template <class U = T,
2000 : detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
2001 76 : TL_EXPECTED_11_CONSTEXPR U &&value() && {
2002 76 : if (!has_value())
2003 0 : detail::throw_exception(bad_expected_access<E>(std::move(err()).value()));
2004 76 : return std::move(val());
2005 : }
2006 :
2007 : constexpr const E &error() const & {
2008 : TL_ASSERT(!has_value());
2009 : return err().value();
2010 : }
2011 198845 : TL_EXPECTED_11_CONSTEXPR E &error() & {
2012 198845 : TL_ASSERT(!has_value());
2013 198845 : return err().value();
2014 : }
2015 : constexpr const E &&error() const && {
2016 : TL_ASSERT(!has_value());
2017 : return std::move(err().value());
2018 : }
2019 22 : TL_EXPECTED_11_CONSTEXPR E &&error() && {
2020 22 : TL_ASSERT(!has_value());
2021 22 : return std::move(err().value());
2022 : }
2023 :
2024 : template <class U> constexpr T value_or(U &&v) const & {
2025 : static_assert(std::is_copy_constructible<T>::value &&
2026 : std::is_convertible<U &&, T>::value,
2027 : "T must be copy-constructible and convertible to from U&&");
2028 : return bool(*this) ? **this : static_cast<T>(std::forward<U>(v));
2029 : }
2030 4711 : template <class U> TL_EXPECTED_11_CONSTEXPR T value_or(U &&v) && {
2031 : static_assert(std::is_move_constructible<T>::value &&
2032 : std::is_convertible<U &&, T>::value,
2033 : "T must be move-constructible and convertible to from U&&");
2034 4711 : return bool(*this) ? std::move(**this) : static_cast<T>(std::forward<U>(v));
2035 : }
2036 : };
2037 :
2038 : namespace detail {
2039 : template <class Exp> using exp_t = typename detail::decay_t<Exp>::value_type;
2040 : template <class Exp> using err_t = typename detail::decay_t<Exp>::error_type;
2041 : template <class Exp, class Ret> using ret_t = expected<Ret, err_t<Exp>>;
2042 :
2043 : #ifdef TL_EXPECTED_CXX14
2044 : template <class Exp, class F,
2045 : detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2046 : class Ret = decltype(detail::invoke(std::declval<F>(),
2047 : *std::declval<Exp>()))>
2048 343 : constexpr auto and_then_impl(Exp &&exp, F &&f) {
2049 : static_assert(detail::is_expected<Ret>::value, "F must return an expected");
2050 :
2051 343 : return exp.has_value()
2052 343 : ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
2053 343 : : Ret(unexpect, std::forward<Exp>(exp).error());
2054 : }
2055 :
2056 : template <class Exp, class F,
2057 : detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2058 : class Ret = decltype(detail::invoke(std::declval<F>()))>
2059 : constexpr auto and_then_impl(Exp &&exp, F &&f) {
2060 : static_assert(detail::is_expected<Ret>::value, "F must return an expected");
2061 :
2062 : return exp.has_value() ? detail::invoke(std::forward<F>(f))
2063 : : Ret(unexpect, std::forward<Exp>(exp).error());
2064 : }
2065 : #else
2066 : template <class> struct TC;
2067 : template <class Exp, class F,
2068 : class Ret = decltype(detail::invoke(std::declval<F>(),
2069 : *std::declval<Exp>())),
2070 : detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr>
2071 : auto and_then_impl(Exp &&exp, F &&f) -> Ret {
2072 : static_assert(detail::is_expected<Ret>::value, "F must return an expected");
2073 :
2074 : return exp.has_value()
2075 : ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
2076 : : Ret(unexpect, std::forward<Exp>(exp).error());
2077 : }
2078 :
2079 : template <class Exp, class F,
2080 : class Ret = decltype(detail::invoke(std::declval<F>())),
2081 : detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr>
2082 : constexpr auto and_then_impl(Exp &&exp, F &&f) -> Ret {
2083 : static_assert(detail::is_expected<Ret>::value, "F must return an expected");
2084 :
2085 : return exp.has_value() ? detail::invoke(std::forward<F>(f))
2086 : : Ret(unexpect, std::forward<Exp>(exp).error());
2087 : }
2088 : #endif
2089 :
2090 : #ifdef TL_EXPECTED_CXX14
2091 : template <class Exp, class F,
2092 : detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2093 : class Ret = decltype(detail::invoke(std::declval<F>(),
2094 : *std::declval<Exp>())),
2095 : detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2096 : constexpr auto expected_map_impl(Exp &&exp, F &&f) {
2097 : using result = ret_t<Exp, detail::decay_t<Ret>>;
2098 : return exp.has_value() ? result(detail::invoke(std::forward<F>(f),
2099 : *std::forward<Exp>(exp)))
2100 : : result(unexpect, std::forward<Exp>(exp).error());
2101 : }
2102 :
2103 : template <class Exp, class F,
2104 : detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2105 : class Ret = decltype(detail::invoke(std::declval<F>(),
2106 : *std::declval<Exp>())),
2107 : detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2108 : auto expected_map_impl(Exp &&exp, F &&f) {
2109 : using result = expected<void, err_t<Exp>>;
2110 : if (exp.has_value()) {
2111 : detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp));
2112 : return result();
2113 : }
2114 :
2115 : return result(unexpect, std::forward<Exp>(exp).error());
2116 : }
2117 :
2118 : template <class Exp, class F,
2119 : detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2120 : class Ret = decltype(detail::invoke(std::declval<F>())),
2121 : detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2122 : constexpr auto expected_map_impl(Exp &&exp, F &&f) {
2123 : using result = ret_t<Exp, detail::decay_t<Ret>>;
2124 : return exp.has_value() ? result(detail::invoke(std::forward<F>(f)))
2125 : : result(unexpect, std::forward<Exp>(exp).error());
2126 : }
2127 :
2128 : template <class Exp, class F,
2129 : detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2130 : class Ret = decltype(detail::invoke(std::declval<F>())),
2131 : detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2132 : auto expected_map_impl(Exp &&exp, F &&f) {
2133 : using result = expected<void, err_t<Exp>>;
2134 : if (exp.has_value()) {
2135 : detail::invoke(std::forward<F>(f));
2136 : return result();
2137 : }
2138 :
2139 : return result(unexpect, std::forward<Exp>(exp).error());
2140 : }
2141 : #else
2142 : template <class Exp, class F,
2143 : detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2144 : class Ret = decltype(detail::invoke(std::declval<F>(),
2145 : *std::declval<Exp>())),
2146 : detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2147 :
2148 : constexpr auto expected_map_impl(Exp &&exp, F &&f)
2149 : -> ret_t<Exp, detail::decay_t<Ret>> {
2150 : using result = ret_t<Exp, detail::decay_t<Ret>>;
2151 :
2152 : return exp.has_value() ? result(detail::invoke(std::forward<F>(f),
2153 : *std::forward<Exp>(exp)))
2154 : : result(unexpect, std::forward<Exp>(exp).error());
2155 : }
2156 :
2157 : template <class Exp, class F,
2158 : detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2159 : class Ret = decltype(detail::invoke(std::declval<F>(),
2160 : *std::declval<Exp>())),
2161 : detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2162 :
2163 : auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> {
2164 : if (exp.has_value()) {
2165 : detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp));
2166 : return {};
2167 : }
2168 :
2169 : return unexpected<err_t<Exp>>(std::forward<Exp>(exp).error());
2170 : }
2171 :
2172 : template <class Exp, class F,
2173 : detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2174 : class Ret = decltype(detail::invoke(std::declval<F>())),
2175 : detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2176 :
2177 : constexpr auto expected_map_impl(Exp &&exp, F &&f)
2178 : -> ret_t<Exp, detail::decay_t<Ret>> {
2179 : using result = ret_t<Exp, detail::decay_t<Ret>>;
2180 :
2181 : return exp.has_value() ? result(detail::invoke(std::forward<F>(f)))
2182 : : result(unexpect, std::forward<Exp>(exp).error());
2183 : }
2184 :
2185 : template <class Exp, class F,
2186 : detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2187 : class Ret = decltype(detail::invoke(std::declval<F>())),
2188 : detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2189 :
2190 : auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> {
2191 : if (exp.has_value()) {
2192 : detail::invoke(std::forward<F>(f));
2193 : return {};
2194 : }
2195 :
2196 : return unexpected<err_t<Exp>>(std::forward<Exp>(exp).error());
2197 : }
2198 : #endif
2199 :
2200 : #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
2201 : !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
2202 : template <class Exp, class F,
2203 : detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2204 : class Ret = decltype(detail::invoke(std::declval<F>(),
2205 : std::declval<Exp>().error())),
2206 : detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2207 : constexpr auto map_error_impl(Exp &&exp, F &&f) {
2208 : using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
2209 : return exp.has_value()
2210 : ? result(*std::forward<Exp>(exp))
2211 : : result(unexpect, detail::invoke(std::forward<F>(f),
2212 : std::forward<Exp>(exp).error()));
2213 : }
2214 : template <class Exp, class F,
2215 : detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2216 : class Ret = decltype(detail::invoke(std::declval<F>(),
2217 : std::declval<Exp>().error())),
2218 : detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2219 : auto map_error_impl(Exp &&exp, F &&f) {
2220 : using result = expected<exp_t<Exp>, monostate>;
2221 : if (exp.has_value()) {
2222 : return result(*std::forward<Exp>(exp));
2223 : }
2224 :
2225 : detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
2226 : return result(unexpect, monostate{});
2227 : }
2228 : template <class Exp, class F,
2229 : detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2230 : class Ret = decltype(detail::invoke(std::declval<F>(),
2231 : std::declval<Exp>().error())),
2232 : detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2233 : constexpr auto map_error_impl(Exp &&exp, F &&f) {
2234 : using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
2235 : return exp.has_value()
2236 : ? result()
2237 : : result(unexpect, detail::invoke(std::forward<F>(f),
2238 : std::forward<Exp>(exp).error()));
2239 : }
2240 : template <class Exp, class F,
2241 : detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2242 : class Ret = decltype(detail::invoke(std::declval<F>(),
2243 : std::declval<Exp>().error())),
2244 : detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2245 : auto map_error_impl(Exp &&exp, F &&f) {
2246 : using result = expected<exp_t<Exp>, monostate>;
2247 : if (exp.has_value()) {
2248 : return result();
2249 : }
2250 :
2251 : detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
2252 : return result(unexpect, monostate{});
2253 : }
2254 : #else
2255 : template <class Exp, class F,
2256 : detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2257 : class Ret = decltype(detail::invoke(std::declval<F>(),
2258 : std::declval<Exp>().error())),
2259 : detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2260 : constexpr auto map_error_impl(Exp &&exp, F &&f)
2261 : -> expected<exp_t<Exp>, detail::decay_t<Ret>> {
2262 : using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
2263 :
2264 : return exp.has_value()
2265 : ? result(*std::forward<Exp>(exp))
2266 : : result(unexpect, detail::invoke(std::forward<F>(f),
2267 : std::forward<Exp>(exp).error()));
2268 : }
2269 :
2270 : template <class Exp, class F,
2271 : detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
2272 : class Ret = decltype(detail::invoke(std::declval<F>(),
2273 : std::declval<Exp>().error())),
2274 : detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2275 : auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> {
2276 : using result = expected<exp_t<Exp>, monostate>;
2277 : if (exp.has_value()) {
2278 : return result(*std::forward<Exp>(exp));
2279 : }
2280 :
2281 : detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
2282 : return result(unexpect, monostate{});
2283 : }
2284 :
2285 : template <class Exp, class F,
2286 : detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2287 : class Ret = decltype(detail::invoke(std::declval<F>(),
2288 : std::declval<Exp>().error())),
2289 : detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2290 : constexpr auto map_error_impl(Exp &&exp, F &&f)
2291 : -> expected<exp_t<Exp>, detail::decay_t<Ret>> {
2292 : using result = expected<exp_t<Exp>, detail::decay_t<Ret>>;
2293 :
2294 : return exp.has_value()
2295 : ? result()
2296 : : result(unexpect, detail::invoke(std::forward<F>(f),
2297 : std::forward<Exp>(exp).error()));
2298 : }
2299 :
2300 : template <class Exp, class F,
2301 : detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
2302 : class Ret = decltype(detail::invoke(std::declval<F>(),
2303 : std::declval<Exp>().error())),
2304 : detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2305 : auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> {
2306 : using result = expected<exp_t<Exp>, monostate>;
2307 : if (exp.has_value()) {
2308 : return result();
2309 : }
2310 :
2311 : detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
2312 : return result(unexpect, monostate{});
2313 : }
2314 : #endif
2315 :
2316 : #ifdef TL_EXPECTED_CXX14
2317 : template <class Exp, class F,
2318 : class Ret = decltype(detail::invoke(std::declval<F>(),
2319 : std::declval<Exp>().error())),
2320 : detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2321 : constexpr auto or_else_impl(Exp &&exp, F &&f) {
2322 : static_assert(detail::is_expected<Ret>::value, "F must return an expected");
2323 : return exp.has_value() ? std::forward<Exp>(exp)
2324 : : detail::invoke(std::forward<F>(f),
2325 : std::forward<Exp>(exp).error());
2326 : }
2327 :
2328 : template <class Exp, class F,
2329 : class Ret = decltype(detail::invoke(std::declval<F>(),
2330 : std::declval<Exp>().error())),
2331 : detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2332 : detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) {
2333 : return exp.has_value() ? std::forward<Exp>(exp)
2334 : : (detail::invoke(std::forward<F>(f),
2335 : std::forward<Exp>(exp).error()),
2336 : std::forward<Exp>(exp));
2337 : }
2338 : #else
2339 : template <class Exp, class F,
2340 : class Ret = decltype(detail::invoke(std::declval<F>(),
2341 : std::declval<Exp>().error())),
2342 : detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
2343 : auto or_else_impl(Exp &&exp, F &&f) -> Ret {
2344 : static_assert(detail::is_expected<Ret>::value, "F must return an expected");
2345 : return exp.has_value() ? std::forward<Exp>(exp)
2346 : : detail::invoke(std::forward<F>(f),
2347 : std::forward<Exp>(exp).error());
2348 : }
2349 :
2350 : template <class Exp, class F,
2351 : class Ret = decltype(detail::invoke(std::declval<F>(),
2352 : std::declval<Exp>().error())),
2353 : detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
2354 : detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) {
2355 : return exp.has_value() ? std::forward<Exp>(exp)
2356 : : (detail::invoke(std::forward<F>(f),
2357 : std::forward<Exp>(exp).error()),
2358 : std::forward<Exp>(exp));
2359 : }
2360 : #endif
2361 : } // namespace detail
2362 :
2363 : template <class T, class E, class U, class F>
2364 : constexpr bool operator==(const expected<T, E> &lhs,
2365 : const expected<U, F> &rhs) {
2366 : return (lhs.has_value() != rhs.has_value())
2367 : ? false
2368 : : (!lhs.has_value() ? lhs.error() == rhs.error() : *lhs == *rhs);
2369 : }
2370 : template <class T, class E, class U, class F>
2371 : constexpr bool operator!=(const expected<T, E> &lhs,
2372 : const expected<U, F> &rhs) {
2373 : return (lhs.has_value() != rhs.has_value())
2374 : ? true
2375 : : (!lhs.has_value() ? lhs.error() != rhs.error() : *lhs != *rhs);
2376 : }
2377 : template <class E, class F>
2378 : constexpr bool operator==(const expected<void, E> &lhs,
2379 : const expected<void, F> &rhs) {
2380 : return (lhs.has_value() != rhs.has_value())
2381 : ? false
2382 : : (!lhs.has_value() ? lhs.error() == rhs.error() : true);
2383 : }
2384 : template <class E, class F>
2385 : constexpr bool operator!=(const expected<void, E> &lhs,
2386 : const expected<void, F> &rhs) {
2387 : return (lhs.has_value() != rhs.has_value())
2388 : ? true
2389 : : (!lhs.has_value() ? lhs.error() == rhs.error() : false);
2390 : }
2391 :
2392 : template <class T, class E, class U>
2393 11877 : constexpr bool operator==(const expected<T, E> &x, const U &v) {
2394 11877 : return x.has_value() ? *x == v : false;
2395 : }
2396 : template <class T, class E, class U>
2397 : constexpr bool operator==(const U &v, const expected<T, E> &x) {
2398 : return x.has_value() ? *x == v : false;
2399 : }
2400 : template <class T, class E, class U>
2401 : constexpr bool operator!=(const expected<T, E> &x, const U &v) {
2402 : return x.has_value() ? *x != v : true;
2403 : }
2404 : template <class T, class E, class U>
2405 : constexpr bool operator!=(const U &v, const expected<T, E> &x) {
2406 : return x.has_value() ? *x != v : true;
2407 : }
2408 :
2409 : template <class T, class E>
2410 : constexpr bool operator==(const expected<T, E> &x, const unexpected<E> &e) {
2411 : return x.has_value() ? false : x.error() == e.value();
2412 : }
2413 : template <class T, class E>
2414 : constexpr bool operator==(const unexpected<E> &e, const expected<T, E> &x) {
2415 : return x.has_value() ? false : x.error() == e.value();
2416 : }
2417 : template <class T, class E>
2418 : constexpr bool operator!=(const expected<T, E> &x, const unexpected<E> &e) {
2419 : return x.has_value() ? true : x.error() != e.value();
2420 : }
2421 : template <class T, class E>
2422 : constexpr bool operator!=(const unexpected<E> &e, const expected<T, E> &x) {
2423 : return x.has_value() ? true : x.error() != e.value();
2424 : }
2425 :
2426 : template <class T, class E,
2427 : detail::enable_if_t<(std::is_void<T>::value ||
2428 : std::is_move_constructible<T>::value) &&
2429 : detail::is_swappable<T>::value &&
2430 : std::is_move_constructible<E>::value &&
2431 : detail::is_swappable<E>::value> * = nullptr>
2432 : void swap(expected<T, E> &lhs,
2433 : expected<T, E> &rhs) noexcept(noexcept(lhs.swap(rhs))) {
2434 : lhs.swap(rhs);
2435 : }
2436 : } // namespace tl
2437 :
2438 : #endif
|