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