Branch data 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 : 315600 : 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 : 329266 : 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 : 234305 : 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 : 118830 : unexpected<typename std::decay<E>::type> make_unexpected(E &&e) {
200 : 108785 : 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 : : constexpr expected_storage_base(in_place_t, Args &&...args)
450 : : : 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 : : constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
462 : : : 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 : : ~expected_storage_base() {
473 : : if (m_has_val) {
474 : : m_val.~T();
475 : : } else {
476 : : m_unexpect.~unexpected<E>();
477 : : }
478 : : }
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 : 150090 : TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base(no_init_t)
532 : 150090 : : 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 : 153850 : constexpr expected_storage_base(in_place_t, Args &&...args)
538 : 153850 : : 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 : 105207 : constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
550 : 210414 : : 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 : 409147 : ~expected_storage_base() {
561 : 259049 : if (!m_has_val) {
562 : 210393 : 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 : : constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
577 : : 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 : 9201 : constexpr expected_storage_base(in_place_t, Args &&...args)
583 : 10641 : : 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 : 13623 : constexpr explicit expected_storage_base(unexpect_t, Args &&...args)
595 : 13623 : : 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 : 22824 : ~expected_storage_base() {
606 : 600 : if (m_has_val) {
607 : 9795 : m_val.~T();
608 : : }
609 : 600 : }
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 : 713252 : struct expected_operations_base : expected_storage_base<T, E> {
692 : 538918 : using expected_storage_base<T, E>::expected_storage_base;
693 : :
694 : : template <class... Args> void construct(Args &&...args) noexcept {
695 : : new (std::addressof(this->m_val)) T(std::forward<Args>(args)...);
696 : : this->m_has_val = true;
697 : : }
698 : :
699 : 44904 : template <class Rhs> void construct_with(Rhs &&rhs) noexcept {
700 : 44904 : new (std::addressof(this->m_val)) T(std::forward<Rhs>(rhs).get());
701 : 44904 : this->m_has_val = true;
702 : 44904 : }
703 : :
704 : 105194 : template <class... Args> void construct_error(Args &&...args) noexcept {
705 : 210380 : new (std::addressof(this->m_unexpect))
706 : : unexpected<E>(std::forward<Args>(args)...);
707 : 105186 : this->m_has_val = false;
708 : 105194 : }
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 : : void assign(expected_operations_base &&rhs) noexcept {
823 : : if (!this->m_has_val && rhs.m_has_val) {
824 : : geterr().~unexpected<E>();
825 : : construct(std::move(rhs).get());
826 : : } else {
827 : : assign_common(std::move(rhs));
828 : : }
829 : : }
830 : :
831 : : #endif
832 : :
833 : : // The common part of move/copy assigning
834 : : template <class Rhs> void assign_common(Rhs &&rhs) {
835 : : if (this->m_has_val) {
836 : : if (rhs.m_has_val) {
837 : : get() = std::forward<Rhs>(rhs).get();
838 : : } else {
839 : : destroy_val();
840 : : construct_error(std::forward<Rhs>(rhs).geterr());
841 : : }
842 : : } else {
843 : : if (!rhs.m_has_val) {
844 : : geterr() = std::forward<Rhs>(rhs).geterr();
845 : : }
846 : : }
847 : : }
848 : :
849 : 150098 : bool has_value() const { return this->m_has_val; }
850 : :
851 : : TL_EXPECTED_11_CONSTEXPR T &get() & { return this->m_val; }
852 : : constexpr const T &get() const & { return this->m_val; }
853 : : 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 : 105186 : 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 : : 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 : 713852 : struct expected_copy_base<T, E, false> : expected_operations_base<T, E> {
941 : 388828 : using expected_operations_base<T, E>::expected_operations_base;
942 : :
943 : : expected_copy_base() = default;
944 : 150090 : expected_copy_base(const expected_copy_base &rhs)
945 : 150090 : : expected_operations_base<T, E>(no_init) {
946 : 150090 : if (rhs.has_value()) {
947 : 44904 : this->construct_with(rhs);
948 : : } else {
949 : 105186 : this->construct_error(rhs.geterr());
950 : : }
951 : 150090 : }
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 : 713852 : struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
975 : 388820 : using expected_copy_base<T, E>::expected_copy_base;
976 : :
977 : : expected_move_base() = default;
978 : 150090 : expected_move_base(const expected_move_base &rhs) = default;
979 : :
980 : 8 : expected_move_base(expected_move_base &&rhs) noexcept(
981 : : std::is_nothrow_move_constructible<T>::value)
982 : 8 : : expected_copy_base<T, E>(no_init) {
983 : 8 : if (rhs.has_value()) {
984 : 0 : 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 : 713852 : struct expected_copy_assign_base<T, E, false> : expected_move_base<T, E> {
1008 : 388820 : using expected_move_base<T, E>::expected_move_base;
1009 : :
1010 : : expected_copy_assign_base() = default;
1011 : 300180 : expected_copy_assign_base(const expected_copy_assign_base &rhs) = default;
1012 : :
1013 : 8 : 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 : 713852 : struct expected_move_assign_base<T, E, false>
1045 : : : expected_copy_assign_base<T, E> {
1046 : 388820 : using expected_copy_assign_base<T, E>::expected_copy_assign_base;
1047 : :
1048 : : expected_move_assign_base() = default;
1049 : 300180 : expected_move_assign_base(const expected_move_assign_base &rhs) = default;
1050 : :
1051 : 14 : 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 : : operator=(expected_move_assign_base &&rhs) noexcept(
1058 : : std::is_nothrow_move_constructible<T>::value
1059 : : &&std::is_nothrow_move_assignable<T>::value) {
1060 : : 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 : 277463 : 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 : 4710 : 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 : 395665 : 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 : 4 : 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 : 15116 : TL_EXPECTED_11_CONSTEXPR U &val() {
1265 : 14310 : 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 : : constexpr const U &val() const {
1272 : : 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 : 150090 : constexpr expected(const expected &rhs) = default;
1523 : 8 : constexpr expected(expected &&rhs) = default;
1524 : : expected &operator=(const expected &rhs) = default;
1525 : : expected &operator=(expected &&rhs) = default;
1526 : :
1527 : : template <class... Args,
1528 : : detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * =
1529 : : nullptr>
1530 : 163321 : constexpr expected(in_place_t, Args &&...args)
1531 : : : impl_base(in_place, std::forward<Args>(args)...),
1532 : 164761 : 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 : 118830 : constexpr expected(unexpected<G> &&e) noexcept(
1573 : : std::is_nothrow_constructible<E, G &&>::value)
1574 : 118830 : : impl_base(unexpect, std::move(e.value())),
1575 : 118830 : 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 : : TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs)
1642 : : : ctor_base(detail::default_constructor_tag{}) {
1643 : : if (rhs.has_value()) {
1644 : : this->construct(std::move(*rhs));
1645 : : } else {
1646 : : this->construct_error(std::move(rhs.error()));
1647 : : }
1648 : : }
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 : 163292 : TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v)
1662 : 163292 : : 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 : : expected &operator=(U &&v) {
1677 : : if (has_value()) {
1678 : : val() = std::forward<U>(v);
1679 : : } else {
1680 : : err().~unexpected<E>();
1681 : : ::new (valptr()) T(std::forward<U>(v));
1682 : : this->m_has_val = true;
1683 : : }
1684 : :
1685 : : 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 : 4 : TL_EXPECTED_11_CONSTEXPR T *operator->() {
1946 : 0 : TL_ASSERT(has_value());
1947 : 4 : return valptr();
1948 : : }
1949 : :
1950 : : template <class U = T,
1951 : : detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
1952 : : constexpr const U &operator*() const & {
1953 : : TL_ASSERT(has_value());
1954 : : return val();
1955 : : }
1956 : : template <class U = T,
1957 : : detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
1958 : 14181 : TL_EXPECTED_11_CONSTEXPR U &operator*() & {
1959 : 0 : TL_ASSERT(has_value());
1960 : 14181 : 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 : 137584 : constexpr bool has_value() const noexcept { return this->m_has_val; }
1976 : 232291 : 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 : 828 : TL_EXPECTED_11_CONSTEXPR U &value() & {
1988 : 277 : if (!has_value())
1989 : 0 : detail::throw_exception(bad_expected_access<E>(err().value()));
1990 : 794 : 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 : 12 : TL_EXPECTED_11_CONSTEXPR U &&value() && {
2002 : 12 : if (!has_value())
2003 : 0 : detail::throw_exception(bad_expected_access<E>(std::move(err()).value()));
2004 : 12 : return std::move(val());
2005 : : }
2006 : :
2007 : : constexpr const E &error() const & {
2008 : : TL_ASSERT(!has_value());
2009 : : return err().value();
2010 : : }
2011 : 115453 : TL_EXPECTED_11_CONSTEXPR E &error() & {
2012 : 115453 : TL_ASSERT(!has_value());
2013 : 115453 : 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 : : 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 : : 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 : : constexpr bool operator==(const expected<T, E> &x, const U &v) {
2394 : : 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
|