MySQL 8.0.40
Source Code Documentation
expected.h
Go to the documentation of this file.
1/*
2 Copyright (c) 2019, 2024, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is designed to work with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have either included with
14 the program or referenced in the documentation.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24*/
25
26#ifndef MYSQL_HARNESS_STDX_EXPECTED_H_
27#define MYSQL_HARNESS_STDX_EXPECTED_H_
28
29// implementation of C++23's std::expected<> in C++17
30//
31// and http://wg21.link/p2505 (r0) for .and_then(), .or_else() and .transform()
32//
33// See http://wg21.link/p0323
34//
35// missing: trivial destructors if T and E are trivial.
36
37#include <functional> // invoke
38#include <initializer_list>
39#include <new> // ::operator new
40#include <type_traits>
41#include <utility> // std::forward
42
43#include "my_compiler.h"
45
46#if defined(__GNUC__) || defined(__clang__)
47#define RESO_ASSUME(x) \
48 if (!(x)) __builtin_unreachable();
49#elif defined(_MSC_VER)
50#define RESO_ASSUME(x) \
51 if (!(x)) __assume(0);
52#else
53#define RESO_ASSUME(x) \
54 if (!(x)) { \
55 };
56#endif
57
58/* workaround default-constructor of std::unique_ptr<T, D> triggering a
59 * static-exception when it is tested for "std::is_default_constructible"
60 *
61 * The problem exists in GCC's libstdc++ up to 7.0.0 and is tracked by C++ std
62 * as DR 2801
63 *
64 * http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2801
65 *
66 * It is fixed in GCC-7.1.0 and later:
67 *
68 * https://gcc.gnu.org/legacy-ml/gcc-cvs/2017-01/msg00068.html
69 */
70
71#include <memory>
72namespace std {
73template <class T>
74struct is_default_constructible<std::unique_ptr<T, void (*)(T *)>>
75 : std::false_type {};
76} // namespace std
77
78namespace stdx {
79
80// inplace construction of unexpected values.
81struct unexpect_t {
82 explicit unexpect_t() = default;
83};
84
85inline constexpr unexpect_t unexpect{};
86
87template <typename E>
89 public:
90 static_assert(!std::is_same<E, void>::value, "E must not be void");
91
92 using error_type = E;
93
94 unexpected() = delete;
95
96 constexpr explicit unexpected(error_type &&e) : error_{std::move(e)} {}
97 // GCC 8.3.1, 8.4.0 report:
98 //
99 // '*((void*)& accu +64)' may be used uninitialized in this function
100 // [-Werror=maybe-uninitialized]
102 MY_COMPILER_GCC_DIAGNOSTIC_IGNORE("-Wmaybe-uninitialized")
103 constexpr explicit unexpected(const error_type &e) : error_{e} {}
105
106 template <
107 class... Args,
108 std::enable_if_t<std::is_constructible_v<E, Args &&...>> * = nullptr>
109 constexpr explicit unexpected(std::in_place_t, Args &&...args) {
110 error_(std::forward<Args>(args)...);
111 }
112
113 constexpr error_type &value() &noexcept { return error_; }
114 constexpr const error_type &value() const &noexcept { return error_; }
115 constexpr error_type &&value() &&noexcept { return std::move(error_); }
116 constexpr const error_type &&value() const &&noexcept {
117 return std::move(error_);
118 }
119
120 private:
122};
123
124template <typename E>
126 return unexpected<std::decay_t<E>>(std::forward<E>(e));
127}
128
129// deduction guide
130template <class E>
132
133template <class T, class E>
134class expected;
135
136namespace base {
137template <class T, class E>
139 using value_type = T;
140 using error_type = E;
141
142 storage_t() {} // NOLINT(modernize-use-equals-default)
143 ~storage_t() {} // NOLINT(modernize-use-equals-default)
144
145 template <bool B = std::is_default_constructible<T>::value,
146 std::enable_if_t<B> * = nullptr>
148 new (&value_) value_type();
149 }
150
151 template <bool B = std::is_copy_constructible<T>::value,
152 std::enable_if_t<B> * = nullptr>
154 new (&value_) value_type(e);
155 }
156
157 template <bool B = std::is_move_constructible<T>::value,
158 std::enable_if_t<B> * = nullptr>
160 new (&value_) value_type(std::move(e));
161 }
162
163 // enable inplace construction of value_type, if the T supports it
164 template <class... Args,
165 std::enable_if_t<std::is_constructible_v<T, Args &&...>, void *> =
166 nullptr>
167 void construct_value(std::in_place_t, Args &&...args) {
168 new (&value_) value_type(std::forward<Args>(args)...);
169 }
170
171 template <class U, class... Args,
172 std::enable_if_t<std::is_constructible_v<
173 T, std::initializer_list<U> &, Args &&...>,
174 void *> = nullptr>
175 void construct_value(std::in_place_t, std::initializer_list<U> il,
176 Args &&...args) {
177 new (&value_) value_type(il, std::forward<Args>(args)...);
178 }
179
180 void destruct_value() { value_.~value_type(); }
181
182 void construct_error(error_type const &e) { new (&error_) error_type(e); }
184 new (&error_) error_type(std::move(e));
185 }
186
187 // enable inplace construction of error, if the E supports it
188 template <
189 class... Args,
190 std::enable_if_t<std::is_constructible_v<E, Args &&...>> * = nullptr>
191 void construct_error(std::in_place_t, Args &&...args) {
192 new (&error_) error_type(std::forward<Args>(args)...);
193 }
194
195 void destruct_error() { error_.~error_type(); }
196
197 constexpr const value_type &value() const & { return value_; }
198 constexpr const value_type &&value() const && { return std::move(value_); }
199 value_type &value() & { return value_; }
200 constexpr value_type &&value() && { return std::move(value_); }
201
202 const value_type *value_ptr() const { return &value_; }
204
205 constexpr const error_type &error() const & { return error_; }
206 constexpr const error_type &&error() const && { return std::move(error_); }
207 constexpr error_type &error() & { return error_; }
208 constexpr error_type &&error() && { return std::move(error_); }
209
210 private:
213};
214
215/**
216 * specialized storage for <void, E>.
217 *
218 * as 'value' is void, all related functions are removed.
219 */
220template <typename E>
222 using value_type = void;
223 using error_type = E;
224
225 static_assert(!std::is_void<E>::value, "E must not be void");
226
227 storage_t() {} // NOLINT(modernize-use-equals-default)
228 ~storage_t() {} // NOLINT(modernize-use-equals-default)
229
230 void construct_error(error_type const &e) { new (&error_) error_type(e); }
232 new (&error_) error_type(std::move(e));
233 }
234
235 // enable inplace construction of error, if the E supports it
236 template <
237 class... Args,
238 std::enable_if_t<std::is_constructible_v<E, Args &&...>> * = nullptr>
239 void construct_error(std::in_place_t, Args &&...args) {
240 new (&error_) error_type(std::forward<Args>(args)...);
241 }
242
243 void destruct_error() { error_.~error_type(); }
244
245 const error_type &error() const & { return error_; }
246 error_type &error() & { return error_; }
247 constexpr const error_type &&error() const && { return std::move(error_); }
248 constexpr error_type &&error() && { return std::move(error_); }
249
250 private:
252};
253
254// member_policy to disable implicit constructors and assignment operations
255enum class member_policy {
256 none = 0,
257 copy = 1 << 1,
258 move = 1 << 2,
259};
260
263
264 return static_cast<member_policy>(static_cast<int_type>(x) |
265 static_cast<int_type>(y));
266}
267
268// control creation of default-constructors
269template <bool = true>
271 constexpr default_ctor_base() noexcept = default;
272
273 constexpr default_ctor_base(const default_ctor_base &) = default;
274 constexpr default_ctor_base(default_ctor_base &&) = default;
275
276 default_ctor_base &operator=(const default_ctor_base &) noexcept = default;
277 default_ctor_base &operator=(default_ctor_base &&) noexcept = default;
278};
279
280template <>
281struct default_ctor_base<false> {
282 constexpr default_ctor_base() noexcept = delete;
283
284 constexpr default_ctor_base(const default_ctor_base &) = default;
285 constexpr default_ctor_base(default_ctor_base &&) = default;
286
287 default_ctor_base &operator=(const default_ctor_base &) noexcept = default;
288 default_ctor_base &operator=(default_ctor_base &&) noexcept = default;
289};
290
291// control creation of copy and move-constructors
292template <member_policy>
294
295template <>
297 constexpr ctor_base() noexcept = default;
298
299 constexpr ctor_base(const ctor_base &) = delete;
300 constexpr ctor_base(ctor_base &&) = delete;
301
302 ctor_base &operator=(const ctor_base &) noexcept = default;
303 ctor_base &operator=(ctor_base &&) noexcept = default;
304};
305
306template <>
308 constexpr ctor_base() noexcept = default;
309
310 constexpr ctor_base(const ctor_base &) = default;
311 constexpr ctor_base(ctor_base &&) = delete;
312
313 ctor_base &operator=(const ctor_base &) noexcept = default;
314 ctor_base &operator=(ctor_base &&) noexcept = default;
315};
316
317template <>
319 constexpr ctor_base() noexcept = default;
320
321 constexpr ctor_base(const ctor_base &) = delete;
322 constexpr ctor_base(ctor_base &&) = default;
323
324 ctor_base &operator=(const ctor_base &) noexcept = default;
325 ctor_base &operator=(ctor_base &&) noexcept = default;
326};
327
328template <>
329struct ctor_base<member_policy::move | member_policy::copy> {
330 constexpr ctor_base() noexcept = default;
331
332 constexpr ctor_base(const ctor_base &) = default;
333 constexpr ctor_base(ctor_base &&) = default;
334
335 ctor_base &operator=(const ctor_base &) noexcept = default;
336 ctor_base &operator=(ctor_base &&) noexcept = default;
337};
338
339// control creation of copy and move-assignment operators
340template <member_policy>
342
343template <>
345 constexpr assign_base() noexcept = default;
346
347 constexpr assign_base(const assign_base &) = default;
348 constexpr assign_base(assign_base &&) = default;
349
350 assign_base &operator=(const assign_base &) noexcept = delete;
351 assign_base &operator=(assign_base &&) noexcept = delete;
352};
353
354template <>
356 constexpr assign_base() noexcept = default;
357
358 constexpr assign_base(const assign_base &) = default;
359 constexpr assign_base(assign_base &&) = default;
360
361 assign_base &operator=(const assign_base &) noexcept = default;
362 assign_base &operator=(assign_base &&) noexcept = delete;
363};
364
365template <>
367 constexpr assign_base() noexcept = default;
368
369 constexpr assign_base(const assign_base &) = default;
370 constexpr assign_base(assign_base &&) = default;
371
372 assign_base &operator=(const assign_base &) noexcept = delete;
373 assign_base &operator=(assign_base &&) noexcept = default;
374};
375
376template <>
378 constexpr assign_base() noexcept = default;
379
380 constexpr assign_base(const assign_base &) = default;
381 constexpr assign_base(assign_base &&) = default;
382
383 assign_base &operator=(const assign_base &) noexcept = default;
384 assign_base &operator=(assign_base &&) noexcept = default;
385};
386
387template <class B>
388using not_ = std::negation<B>;
389
390template <class... B>
391using and_ = std::conjunction<B...>;
392
393template <class... B>
394using or_ = std::disjunction<B...>;
395
396// enable copy constructor if T and E are copy-constructible or void
397// enable move constructor if T and E are move-constructible or void
398template <class T, class E>
400 ctor_base<(and_<or_<std::is_void<T>, std::is_copy_constructible<T>>,
401 std::is_copy_constructible<E>>::value
402 ? member_policy::copy
403 : member_policy::none) |
404 (and_<or_<std::is_void<T>, std::is_move_constructible<T>>,
405 std::is_move_constructible<E>>::value
406 ? member_policy::move
407 : member_policy::none)>;
408
409// enable copy assignment if T and E are (copy-constructible and
410// copy-assignable) or void
411//
412// enable move assignment if T and E are
413// (move-constructible and move-assignable) or void
414template <class T, class E>
416 (and_<
417 or_<std::is_void<T>,
418 and_<std::is_copy_constructible<T>, std::is_copy_assignable<T>>>,
419 and_<std::is_copy_constructible<E>, std::is_copy_assignable<E>>>::value
420 ? member_policy::copy
421 : member_policy::none) |
422 (or_<std::is_void<T>,
423 and_<std::is_move_constructible<T>, std::is_move_assignable<T>>>::value
424 ? member_policy::move
425 : member_policy::none)>;
426
427} // namespace base
428
430 public:
431 constexpr explicit ExpectedImplBase(bool has_value) noexcept
432 : has_value_{has_value} {}
433
434 constexpr bool has_value() const { return has_value_; }
435 constexpr explicit operator bool() const noexcept { return has_value(); }
436
437 void swap(ExpectedImplBase &other) noexcept {
438 using std::swap;
439
440 swap(has_value_, other.has_value_);
441 }
442
443 private:
445};
446
447template <class T, class E>
449 public:
450 using value_type = T;
451 using error_type = E;
453
454 template <bool B = std::is_default_constructible<T>::value,
455 std::enable_if_t<B> * = nullptr>
456 constexpr ExpectedImpl() : ExpectedImplBase{true} {
457 storage_.construct_value();
458 }
459
460 template <class UF, class GF>
462 std::bool_constant<!std::is_convertible_v<UF, T> ||
463 !std::is_convertible_v<GF, E>>;
464
465 //
466 template <class U, class G, class UF, class GF>
467 using can_value_convert_construct = std::bool_constant<
468 std::is_constructible_v<T, UF> && std::is_constructible_v<E, GF> &&
469 !std::is_constructible_v<T, ExpectedImpl<U, G> &> &&
470 !std::is_constructible_v<T, ExpectedImpl<U, G>> &&
471 !std::is_constructible_v<T, const ExpectedImpl<U, G> &> &&
472 !std::is_constructible_v<T, const ExpectedImpl<U, G>> &&
473 !std::is_convertible_v<ExpectedImpl<U, G> &, T> &&
474 !std::is_convertible_v<ExpectedImpl<U, G>, T> &&
475 !std::is_convertible_v<const ExpectedImpl<U, G> &, T> &&
476 !std::is_convertible_v<const ExpectedImpl<U, G>, T> &&
477 !std::is_constructible_v<unexpected<E>, ExpectedImpl<U, G> &> &&
478 !std::is_constructible_v<unexpected<E>, ExpectedImpl<U, G>> &&
479 !std::is_constructible_v<unexpected<E>, const ExpectedImpl<U, G> &> &&
480 !std::is_constructible_v<unexpected<E>, const ExpectedImpl<U, G>>>;
481
482 template <
483 class U, class G, class UF = const U &, class GF = const G &,
484 std::enable_if_t<can_value_convert_construct<U, G, UF, GF>::value &&
486 constexpr ExpectedImpl(const ExpectedImpl<U, G> &rhs)
487 : ExpectedImplBase{rhs.has_value()} {
488 if (rhs.has_value()) {
489 storage_.construct_value(std::forward<UF>(*rhs));
490 } else {
491 storage_.construct_error(rhs.error());
492 }
493 }
494
495 template <
496 class U, class G, class UF = const U &, class GF = const G &,
497 std::enable_if_t<can_value_convert_construct<U, G, UF, GF>::value &&
498 constructor_is_explicit<UF, GF>::value> * = nullptr>
499 explicit constexpr ExpectedImpl(const ExpectedImpl<U, G> &rhs)
500 : ExpectedImplBase{rhs.has_value()} {
501 if (rhs.has_value()) {
502 storage_.construct_value(std::forward<UF>(*rhs));
503 } else {
504 storage_.construct_error(rhs.error());
505 }
506 }
507
508 template <
509 class U, class G, class UF = U, class GF = G,
510 std::enable_if_t<can_value_convert_construct<U, G, UF, GF>::value &&
511 !constructor_is_explicit<UF, GF>::value> * = nullptr>
513 : ExpectedImplBase{rhs.has_value()} {
514 if (rhs.has_value()) {
515 storage_.construct_value(std::forward<UF>(*rhs));
516 } else {
517 storage_.construct_error(rhs.error());
518 }
519 }
520
521 template <
522 class U, class G, class UF = U, class GF = G,
523 std::enable_if_t<can_value_convert_construct<U, G, UF, GF>::value &&
524 constructor_is_explicit<UF, GF>::value> * = nullptr>
525 explicit constexpr ExpectedImpl(ExpectedImpl<U, G> &&rhs)
526 : ExpectedImplBase{rhs.has_value()} {
527 if (rhs.has_value()) {
528 storage_.construct_value(std::forward<UF>(*rhs));
529 } else {
530 storage_.construct_error(rhs.error());
531 }
532 }
533
534 template <class U>
535 using can_construct_from_value_type = std::conjunction<
536 std::negation<std::is_same<std::in_place_t, stdx::remove_cvref_t<U>>>,
537 std::negation<std::is_same<ExpectedImpl<T, E>, stdx::remove_cvref_t<U>>>,
538 std::negation<std::is_same<unexpected<E>, stdx::remove_cvref_t<U>>>,
539 std::is_constructible<T, U>>;
540
541 template <class U>
543 std::negation<std::is_convertible<U, T>>;
544
545 template <class U = T,
546 std::enable_if_t<can_construct_from_value_type<U>::value &&
548 * = nullptr>
549 constexpr ExpectedImpl(U &&v) : ExpectedImplBase{true} {
550 storage_.construct_value(std::forward<U>(v));
551 }
552
553 template <class U = T,
554 std::enable_if_t<can_construct_from_value_type<U>::value &&
555 can_construct_from_value_type_explicit<U>::value>
556 * = nullptr>
557 explicit constexpr ExpectedImpl(U &&v) : ExpectedImplBase{true} {
558 storage_.construct_value(std::in_place, std::forward<U>(v));
559 }
560
561 // enable inplace construction of value_type, if the T supports it
562 template <
563 class... Args,
564 std::enable_if_t<std::is_constructible_v<T, Args &&...>> * = nullptr>
565 constexpr ExpectedImpl(std::in_place_t, Args &&...args)
566 : ExpectedImplBase{true} {
567 storage_.construct_value(std::in_place, std::forward<Args>(args)...);
568 }
569
570 // enable inplace construction of error_type, if the E supports it
571 template <
572 class... Args,
573 std::enable_if_t<std::is_constructible_v<E, Args &&...>> * = nullptr>
574 constexpr ExpectedImpl(stdx::unexpect_t, Args &&...args)
575 : ExpectedImplBase{false} {
576 storage_.construct_error(std::in_place, std::forward<Args>(args)...);
577 }
578
579 constexpr ExpectedImpl(const ExpectedImpl &other)
580 : ExpectedImplBase{other.has_value()} {
581 if (has_value()) {
582 storage_.construct_value(other.storage_.value());
583 } else {
584 storage_.construct_error(other.storage_.error());
585 }
586 }
587
588 constexpr ExpectedImpl(ExpectedImpl &&other) noexcept(
589 std::is_nothrow_move_constructible<E>::value
590 &&std::is_nothrow_move_constructible<T>::value)
591 : ExpectedImplBase{other.has_value()} {
592 if (has_value()) {
593 storage_.construct_value(std::move(other.storage_.value()));
594 } else {
595 storage_.construct_error(std::move(other.storage_.error()));
596 }
597 }
598
599 template <class G,
600 std::enable_if_t<std::is_constructible_v<E, const G &>> * = nullptr>
601 constexpr ExpectedImpl(const unexpected<G> &e) : ExpectedImplBase{false} {
602 storage_.construct_error(e.value());
603 }
604
605 template <class G,
606 std::enable_if_t<std::is_constructible_v<E, G>> * = nullptr>
608 storage_.construct_error(std::move(e.value()));
609 }
610
612 ExpectedImpl(other).swap(*this);
613
614 return *this;
615 }
616
618 ExpectedImpl(std::move(other)).swap(*this);
619
620 return *this;
621 }
622
623 template <class U = T,
624 std::enable_if_t<
625 !std::is_same_v<ExpectedImpl<T, E>, stdx::remove_cvref_t<U>> &&
626 !std::conjunction_v<std::is_scalar<T>,
627 std::is_same<T, std::decay_t<U>>> &&
628 std::is_constructible_v<T, U> && std::is_assignable_v<T &, U>>
629 * = nullptr>
631 if (bool(*this)) {
632 storage_.value() = std::forward<U>(v);
633 } else {
634 ExpectedImpl(std::forward<U>(v)).swap(*this);
635 }
636
637 return *this;
638 }
639
640 // destruct
642 if (has_value()) {
643 storage_.destruct_value();
644 } else {
645 storage_.destruct_error();
646 }
647 }
648
649 //
650 template <class U = T, class G = E>
651 std::enable_if_t<
652#if defined(__cpp_lib_is_swappable)
653 std::is_swappable<U>::value && std::is_swappable<G>::value &&
654#endif
655 (std::is_move_constructible<U>::value ||
656 std::is_move_constructible<G>::value)>
657 swap(ExpectedImpl &other) noexcept(
658 std::is_nothrow_move_constructible<T>::value
659 &&std::is_nothrow_move_constructible<E>::value
660#if defined(__cpp_lib_is_swappable)
661 &&std::is_nothrow_swappable<T &>::value
662 &&std::is_nothrow_swappable<E &>::value
663#endif
664 ) {
665 using std::swap;
666
667 if (bool(*this) && bool(other)) {
668 swap(storage_.value(), other.storage_.value());
669 } else if (!bool(*this) && !bool(other)) {
670 swap(storage_.error(), other.storage_.error());
671 } else if (bool(*this) && !bool(other)) {
672 error_type t{std::move(other.error())};
673
674 other.storage_.destruct_error();
675 other.storage_.construct_value(std::move(storage_.value()));
676 storage_.destruct_value();
677 storage_.construct_error(std::move(t));
678
679 swap(static_cast<ExpectedImplBase &>(*this),
680 static_cast<ExpectedImplBase &>(other));
681 } else if (!bool(*this) && bool(other)) {
682 other.swap(*this);
683 }
684 }
685
686 // value accessors
687
688 constexpr const value_type &value() const & { return storage_.value(); }
689 constexpr const value_type &&value() const && {
690 return std::move(storage_.value());
691 }
692 value_type &value() & { return storage_.value(); }
693 value_type &&value() && { return std::move(storage_.value()); }
694
695 // unchecked value access
697 RESO_ASSUME(has_value());
698
699 return storage_.value();
700 }
701 constexpr const value_type &operator*() const & {
702 RESO_ASSUME(has_value());
703
704 return storage_.value();
705 }
706
708 RESO_ASSUME(has_value());
709
710 return storage_.value_ptr();
711 }
712 constexpr const value_type *operator->() const {
713 RESO_ASSUME(has_value());
714
715 return storage_.value_ptr();
716 }
717
718 template <class U>
719 constexpr value_type value_or(U &&v) const & {
720 static_assert(std::is_copy_constructible<T>::value &&
721 std::is_convertible<U &&, T>::value,
722 "T must be copy-constructible and convertible from U&&");
723
724 return has_value() ? **this : static_cast<T>(std::forward<U>(v));
725 }
726
727 template <class U>
728 constexpr value_type value_or(U &&v) && {
729 static_assert(std::is_move_constructible<T>::value &&
730 std::is_convertible<U &&, T>::value,
731 "T must be move-constructible and convertible from U&&");
732
733 return has_value() ? std::move(**this) : static_cast<T>(std::forward<U>(v));
734 }
735
736 // error accessors
737 constexpr const error_type &error() const & {
738 RESO_ASSUME(!has_value());
739 return storage_.error();
740 }
741 constexpr const error_type &&error() const && {
742 RESO_ASSUME(!has_value());
743 return std::move(storage_.error());
744 }
745 constexpr error_type &error() & {
746 RESO_ASSUME(!has_value());
747 return storage_.error();
748 }
749 constexpr error_type &&error() && {
750 RESO_ASSUME(!has_value());
751 return std::move(storage_.error());
752 }
753
754 constexpr unexpected_type get_unexpected() const {
755 return make_unexpected(storage_.error());
756 }
757
758 private:
760};
761
762// specialization for T=void
763template <class E>
764class ExpectedImpl<void, E> : public ExpectedImplBase {
765 public:
766 using value_type = void;
767 using error_type = E;
769
770 constexpr ExpectedImpl() noexcept : ExpectedImplBase{true} {}
771
772 // enable inplace construction of error_type, if the E supports it
773 template <
774 class... Args,
775 std::enable_if_t<std::is_constructible_v<E, Args &&...>> * = nullptr>
776 constexpr ExpectedImpl(stdx::unexpect_t, Args &&...args)
777 : ExpectedImplBase{false} {
778 storage_.construct_error(std::in_place, std::forward<Args>(args)...);
779 }
780
781 constexpr ExpectedImpl(const ExpectedImpl &other)
782 : ExpectedImplBase{other.has_value()} {
783 if (!has_value()) {
784 storage_.construct_error(other.storage_.error());
785 }
786 }
787
788 constexpr ExpectedImpl(ExpectedImpl &&other) noexcept(
789 std::is_nothrow_move_constructible<E>::value)
790 : ExpectedImplBase{other.has_value()} {
791 if (!has_value()) {
792 storage_.construct_error(std::move(other.storage_.error()));
793 }
794 }
795
797 ExpectedImpl(other).swap(*this);
798
799 return *this;
800 }
801
803 ExpectedImpl(std::move(other)).swap(*this);
804
805 return *this;
806 }
807
808 constexpr ExpectedImpl(const unexpected<E> &e) : ExpectedImplBase{false} {
809 storage_.construct_error(e.value());
810 }
811
813 storage_.construct_error(std::move(e.value()));
814 }
815
816 // destruct
818 if (!has_value()) {
819 storage_.destruct_error();
820 }
821 }
822
823 // swap
824 template <class G = E, std::enable_if_t<
825#if defined(__cpp_lib_is_swappable)
826 std::is_swappable<G>::value &&
827#endif
828 std::is_move_constructible<G>::value,
829 void *> = nullptr>
830 void swap(ExpectedImpl &other) noexcept(
831 std::is_nothrow_move_constructible<G>::value
832#if defined(__cpp_lib_is_swappable)
833 &&std::is_nothrow_swappable<G &>::value
834#endif
835 ) {
836 using std::swap;
837
838 if (bool(*this) && bool(other)) {
839 // both types have void value, nothing to swap
840 } else if (!bool(*this) && !bool(other)) {
841 swap(storage_.error(), other.storage_.error());
842 } else if (bool(*this) && !bool(other)) {
843 // we are value, but have no storage. Nothing to destroy on our side
844 // before we move the error-type over
845 storage_.construct_error(std::move(other.error()));
846
847 swap(static_cast<ExpectedImplBase &>(*this),
848 static_cast<ExpectedImplBase &>(other));
849 } else if (!bool(*this) && bool(other)) {
850 other.swap(*this);
851 }
852 }
853
854 // error accessors
855 constexpr const error_type &error() const & {
856 RESO_ASSUME(!has_value());
857 return storage_.error();
858 }
859 constexpr const error_type &&error() const && {
860 RESO_ASSUME(!has_value());
861 return std::move(storage_.error());
862 }
863 constexpr error_type &error() & {
864 RESO_ASSUME(!has_value());
865 return storage_.error();
866 }
867 constexpr error_type &&error() && {
868 RESO_ASSUME(!has_value());
869 return std::move(storage_.error());
870 }
871
872 constexpr unexpected_type get_unexpected() const {
873 return make_unexpected(storage_.error());
874 }
875
876 private:
878};
879
880template <class T>
881struct is_expected_impl : std::false_type {};
882
883template <class T, class E>
884struct is_expected_impl<expected<T, E>> : std::true_type {};
885
886template <class T>
888
889namespace base {
890
891template <
892 class Exp, class Func,
893 typename value_type = typename std::decay_t<Exp>::value_type,
894 std::enable_if_t<std::is_void_v<value_type>
895 ? std::is_invocable_v<Func>
896 : std::is_invocable_v<Func, value_type>> * = nullptr>
897constexpr auto and_then_impl(Exp &&exp, Func &&func) {
898 if constexpr (std::is_void_v<value_type>) {
899 using Ret = std::invoke_result_t<Func>;
900
901 static_assert(stdx::is_expected<Ret>::value,
902 "Func must return a stdx::expected<>");
903
904 if (exp.has_value()) {
905 return std::invoke(func);
906 } else {
907 return Ret{stdx::unexpect, std::forward<Exp>(exp).error()};
908 }
909 } else {
910 using Ret = std::invoke_result_t<Func, value_type>;
911
912 static_assert(stdx::is_expected<Ret>::value,
913 "Func must return a stdx::expected<>");
914
915 if (exp.has_value()) {
916 return std::invoke(func, *std::forward<Exp>(exp));
917 } else {
918 return Ret{stdx::unexpect, std::forward<Exp>(exp).error()};
919 }
920 }
921}
922
923template <class Exp, class Func,
924 typename error_type = typename std::decay_t<Exp>::error_type,
925 std::enable_if_t<std::is_invocable_v<Func, error_type>> * = nullptr>
926constexpr auto or_else_impl(Exp &&exp, Func &&func) {
927 static_assert(
928 std::is_same_v<
930 "Func must return an expected<>");
931
932 if (exp.has_value()) {
933 return std::forward<Exp>(exp);
934 }
935
936 return std::invoke(std::forward<Func>(func), std::forward<Exp>(exp).error());
937}
938
939} // namespace base
940
941template <class T, class E>
942class expected : public ExpectedImpl<T, E>,
943 private base::select_assign_base<T, E>,
944 private base::select_ctor_base<T, E> {
945 public:
946 static_assert(!std::is_void<E>::value, "E must not be void");
947 static_assert(!std::is_reference<T>::value, "T must not be a reference");
948 static_assert(!std::is_same<T, std::remove_cv<std::in_place_t>>::value,
949 "T must not be std::in_place_t");
950 static_assert(!std::is_same<T, std::remove_cv<unexpected<E>>>::value,
951 "T must not be unexpected<E>");
952 static_assert(!std::is_reference<E>::value, "E must not be a reference");
953
954 // inherit all the constructors of our base
956
957 //
958 // and_then
959 //
960
961 template <class Func>
962 constexpr auto and_then(Func &&func) & {
963 return base::and_then_impl(*this, std::forward<Func>(func));
964 }
965
966 template <class Func>
967 constexpr auto and_then(Func &&func) && {
968 return base::and_then_impl(std::move(*this), std::forward<Func>(func));
969 }
970
971 template <class Func>
972 constexpr auto and_then(Func &&func) const & {
973 return base::and_then_impl(*this, std::forward<Func>(func));
974 }
975
976 template <class Func>
977 constexpr auto and_then(Func &&func) const && {
978 return base::and_then_impl(std::move(*this), std::forward<Func>(func));
979 }
980
981 //
982 // or_else
983 //
984
985 template <class Func>
986 constexpr auto or_else(Func &&func) & {
987 return base::or_else_impl(*this, std::forward<Func>(func));
988 }
989
990 template <class Func>
991 constexpr auto or_else(Func &&func) && {
992 return base::or_else_impl(std::move(*this), std::forward<Func>(func));
993 }
994
995 template <class Func>
996 constexpr auto or_else(Func &&func) const & {
997 return base::or_else_impl(*this, std::forward<Func>(func));
998 }
999
1000 template <class Func>
1001 constexpr auto or_else(Func &&func) const && {
1002 return base::or_else_impl(std::move(*this), std::forward<Func>(func));
1003 }
1004
1005 //
1006 // transform
1007 //
1008
1009 template <class Func>
1010 constexpr auto transform(Func &&func) & {
1011 return expected_transform_impl(*this, std::forward<Func>(func));
1012 }
1013
1014 template <class Func>
1015 constexpr auto transform(Func &&func) && {
1016 return expected_transform_impl(std::move(*this), std::forward<Func>(func));
1017 }
1018
1019 template <class Func>
1020 constexpr auto transform(Func &&func) const & {
1021 return expected_transform_impl(*this, std::forward<Func>(func));
1022 }
1023
1024 template <class Func>
1025 constexpr auto transform(Func &&func) const && {
1026 return expected_transform_impl(std::move(*this), std::forward<Func>(func));
1027 }
1028};
1029
1030template <class Exp, class Func>
1031constexpr auto expected_transform_impl(Exp &&exp, Func &&func) {
1032 // type of the value that's passed to func
1033 using func_value_type = typename std::decay_t<Exp>::value_type;
1034
1035 if constexpr (std::is_void_v<func_value_type>) {
1036 using func_return_type = std::invoke_result_t<Func>;
1037 using result_type =
1039
1040 if (!exp.has_value()) {
1041 return result_type{stdx::unexpect, std::forward<Exp>(exp).error()};
1042 }
1043
1044 if constexpr (std::is_void_v<func_return_type>) {
1045 std::invoke(func);
1046 return result_type();
1047 } else {
1048 return result_type(std::invoke(func));
1049 }
1050 } else {
1051 using func_return_type = std::invoke_result_t<Func, func_value_type>;
1052 using result_type =
1054
1055 if (!exp.has_value()) {
1056 return result_type{stdx::unexpect, std::forward<Exp>(exp).error()};
1057 }
1058
1059 if constexpr (std::is_void_v<func_return_type>) {
1060 std::invoke(func, *std::forward<Exp>(exp));
1061 return result_type();
1062 } else {
1063 return result_type(std::invoke(func, *std::forward<Exp>(exp)));
1064 }
1065 }
1066}
1067
1068template <class E1, class E2>
1069inline bool operator==(const unexpected<E1> &a, const unexpected<E2> &b) {
1070 return a.value() == b.value();
1071}
1072
1073template <class E1, class E2>
1074inline bool operator!=(const unexpected<E1> &a, const unexpected<E2> &b) {
1075 return !(a == b);
1076}
1077
1078template <class T1, class E1, class T2, class E2>
1079inline bool operator==(const expected<T1, E1> &a, const expected<T2, E2> &b) {
1080 if (a.has_value() != b.has_value()) return false;
1081
1082 if (!a.has_value()) return a.error() == b.error();
1083 return *a == *b;
1084}
1085
1086template <class E1, class E2>
1087inline bool operator==(const expected<void, E1> &a,
1088 const expected<void, E2> &b) {
1089 if (a.has_value() != b.has_value()) return false;
1090
1091 if (!a.has_value()) return a.error() == b.error();
1092 return true;
1093}
1094
1095template <class T1, class E1, class T2, class E2>
1096inline bool operator!=(const expected<T1, E1> &a, const expected<T2, E2> &b) {
1097 return !(a == b);
1098}
1099
1100template <class T1, class E1, class E2>
1101inline bool operator==(const expected<T1, E1> &a, const unexpected<E2> &b) {
1102 if (a.has_value()) return false;
1103
1104 return a.get_unexpected() == b;
1105}
1106
1107template <class T1, class E1, class E2>
1108inline bool operator==(const unexpected<E2> &a, const expected<T1, E1> &b) {
1109 return b == a;
1110}
1111
1112template <class T1, class E1, class E2>
1113inline bool operator!=(const expected<T1, E1> &a, const unexpected<E2> &b) {
1114 return !(a == b);
1115}
1116
1117template <class T1, class E1, class E2>
1119 return !(b == a);
1120}
1121
1122} // namespace stdx
1123
1124#endif
Definition: expected.h:429
constexpr bool has_value() const
Definition: expected.h:434
bool has_value_
Definition: expected.h:444
void swap(ExpectedImplBase &other) noexcept
Definition: expected.h:437
constexpr ExpectedImplBase(bool has_value) noexcept
Definition: expected.h:431
base::storage_t< void, E > storage_
Definition: expected.h:877
constexpr ExpectedImpl(const ExpectedImpl &other)
Definition: expected.h:781
ExpectedImpl & operator=(ExpectedImpl const &other)
Definition: expected.h:796
constexpr ExpectedImpl() noexcept
Definition: expected.h:770
constexpr error_type && error() &&
Definition: expected.h:867
constexpr ExpectedImpl(unexpected< E > &&e)
Definition: expected.h:812
ExpectedImpl & operator=(ExpectedImpl &&other)
Definition: expected.h:802
void value_type
Definition: expected.h:766
constexpr error_type & error() &
Definition: expected.h:863
constexpr unexpected_type get_unexpected() const
Definition: expected.h:872
constexpr ExpectedImpl(ExpectedImpl &&other) noexcept(std::is_nothrow_move_constructible< E >::value)
Definition: expected.h:788
constexpr const error_type && error() const &&
Definition: expected.h:859
constexpr const error_type & error() const &
Definition: expected.h:855
void swap(ExpectedImpl &other) noexcept(std::is_nothrow_move_constructible< G >::value)
Definition: expected.h:830
E error_type
Definition: expected.h:767
constexpr ExpectedImpl(stdx::unexpect_t, Args &&...args)
Definition: expected.h:776
~ExpectedImpl()
Definition: expected.h:817
constexpr ExpectedImpl(const unexpected< E > &e)
Definition: expected.h:808
Definition: expected.h:448
std::enable_if_t<(std::is_move_constructible< U >::value||std::is_move_constructible< G >::value)> swap(ExpectedImpl &other) noexcept(std::is_nothrow_move_constructible< T >::value &&std::is_nothrow_move_constructible< E >::value)
Definition: expected.h:657
value_type & operator*() &
Definition: expected.h:696
constexpr ExpectedImpl(const unexpected< G > &e)
Definition: expected.h:601
value_type & value() &
Definition: expected.h:692
constexpr ExpectedImpl(stdx::unexpect_t, Args &&...args)
Definition: expected.h:574
ExpectedImpl & operator=(ExpectedImpl &&other)
Definition: expected.h:617
std::bool_constant<!std::is_convertible_v< UF, T >||!std::is_convertible_v< GF, E > > constructor_is_explicit
Definition: expected.h:463
constexpr ExpectedImpl(const ExpectedImpl< U, G > &rhs)
Definition: expected.h:486
E error_type
Definition: expected.h:451
constexpr const value_type && value() const &&
Definition: expected.h:689
value_type * operator->()
Definition: expected.h:707
constexpr error_type & error() &
Definition: expected.h:745
constexpr ExpectedImpl(U &&v)
Definition: expected.h:549
ExpectedImpl & operator=(U &&v)
Definition: expected.h:630
std::conjunction< std::negation< std::is_same< std::in_place_t, stdx::remove_cvref_t< U > > >, std::negation< std::is_same< ExpectedImpl< T, E >, stdx::remove_cvref_t< U > > >, std::negation< std::is_same< unexpected< E >, stdx::remove_cvref_t< U > > >, std::is_constructible< T, U > > can_construct_from_value_type
Definition: expected.h:539
std::bool_constant< std::is_constructible_v< T, UF > &&std::is_constructible_v< E, GF > &&!std::is_constructible_v< T, ExpectedImpl< U, G > & > &&!std::is_constructible_v< T, ExpectedImpl< U, G > > &&!std::is_constructible_v< T, const ExpectedImpl< U, G > & > &&!std::is_constructible_v< T, const ExpectedImpl< U, G > > &&!std::is_convertible_v< ExpectedImpl< U, G > &, T > &&!std::is_convertible_v< ExpectedImpl< U, G >, T > &&!std::is_convertible_v< const ExpectedImpl< U, G > &, T > &&!std::is_convertible_v< const ExpectedImpl< U, G >, T > &&!std::is_constructible_v< unexpected< E >, ExpectedImpl< U, G > & > &&!std::is_constructible_v< unexpected< E >, ExpectedImpl< U, G > > &&!std::is_constructible_v< unexpected< E >, const ExpectedImpl< U, G > & > &&!std::is_constructible_v< unexpected< E >, const ExpectedImpl< U, G > > > can_value_convert_construct
Definition: expected.h:480
constexpr ExpectedImpl(ExpectedImpl &&other) noexcept(std::is_nothrow_move_constructible< E >::value &&std::is_nothrow_move_constructible< T >::value)
Definition: expected.h:588
constexpr value_type value_or(U &&v) &&
Definition: expected.h:728
constexpr const error_type && error() const &&
Definition: expected.h:741
constexpr const value_type & value() const &
Definition: expected.h:688
constexpr value_type value_or(U &&v) const &
Definition: expected.h:719
constexpr const value_type & operator*() const &
Definition: expected.h:701
constexpr ExpectedImpl(ExpectedImpl< U, G > &&rhs)
Definition: expected.h:512
constexpr error_type && error() &&
Definition: expected.h:749
~ExpectedImpl()
Definition: expected.h:641
T value_type
Definition: expected.h:450
constexpr unexpected_type get_unexpected() const
Definition: expected.h:754
constexpr ExpectedImpl(const ExpectedImpl &other)
Definition: expected.h:579
constexpr const value_type * operator->() const
Definition: expected.h:712
ExpectedImpl & operator=(ExpectedImpl const &other)
Definition: expected.h:611
constexpr const error_type & error() const &
Definition: expected.h:737
constexpr ExpectedImpl()
Definition: expected.h:456
constexpr ExpectedImpl(unexpected< G > &&e)
Definition: expected.h:607
constexpr ExpectedImpl(std::in_place_t, Args &&...args)
Definition: expected.h:565
value_type && value() &&
Definition: expected.h:693
base::storage_t< T, E > storage_
Definition: expected.h:759
std::negation< std::is_convertible< U, T > > can_construct_from_value_type_explicit
Definition: expected.h:543
Definition: expected.h:944
constexpr auto or_else(Func &&func) &
Definition: expected.h:986
constexpr auto or_else(Func &&func) &&
Definition: expected.h:991
constexpr auto and_then(Func &&func) &&
Definition: expected.h:967
constexpr auto and_then(Func &&func) const &
Definition: expected.h:972
constexpr auto transform(Func &&func) &
Definition: expected.h:1010
constexpr auto transform(Func &&func) const &
Definition: expected.h:1020
constexpr auto transform(Func &&func) const &&
Definition: expected.h:1025
constexpr auto or_else(Func &&func) const &&
Definition: expected.h:1001
constexpr auto transform(Func &&func) &&
Definition: expected.h:1015
constexpr auto or_else(Func &&func) const &
Definition: expected.h:996
constexpr auto and_then(Func &&func) const &&
Definition: expected.h:977
constexpr auto and_then(Func &&func) &
Definition: expected.h:962
Definition: expected.h:88
unexpected()=delete
constexpr error_type & value() &noexcept
Definition: expected.h:113
constexpr error_type && value() &&noexcept
Definition: expected.h:115
error_type error_
Definition: expected.h:121
constexpr unexpected(error_type &&e)
Definition: expected.h:96
constexpr const error_type & value() const &noexcept
Definition: expected.h:114
E error_type
Definition: expected.h:92
constexpr const error_type && value() const &&noexcept
Definition: expected.h:116
#define U
Definition: ctype-tis620.cc:75
error_type
Definition: error.h:36
#define RESO_ASSUME(x)
Definition: expected.h:53
Header for compiler-dependent features.
#define MY_COMPILER_GCC_DIAGNOSTIC_IGNORE(X)
Definition: my_compiler.h:261
#define MY_COMPILER_DIAGNOSTIC_PUSH()
save the compiler's diagnostic (enabled warnings, errors, ...) state
Definition: my_compiler.h:296
#define MY_COMPILER_DIAGNOSTIC_POP()
restore the compiler's diagnostic (enabled warnings, errors, ...) state
Definition: my_compiler.h:297
Log error(cerr, "ERROR")
uint16_t value_type
Definition: vt100.h:184
Definition: gcs_xcom_synode.h:64
constexpr member_policy operator|(member_policy x, member_policy y)
Definition: expected.h:261
std::disjunction< B... > or_
Definition: expected.h:394
constexpr auto or_else_impl(Exp &&exp, Func &&func)
Definition: expected.h:926
constexpr auto and_then_impl(Exp &&exp, Func &&func)
Definition: expected.h:897
member_policy
Definition: expected.h:255
std::negation< B > not_
Definition: expected.h:388
std::conjunction< B... > and_
Definition: expected.h:391
Definition: bit.h:34
bool operator!=(const unexpected< E1 > &a, const unexpected< E2 > &b)
Definition: expected.h:1074
constexpr auto expected_transform_impl(Exp &&exp, Func &&func)
Definition: expected.h:1031
constexpr unexpect_t unexpect
Definition: expected.h:85
constexpr auto make_unexpected(E &&e) -> unexpected< std::decay_t< E > >
Definition: expected.h:125
unexpected(E) -> unexpected< E >
typename remove_cvref< T >::type remove_cvref_t
Definition: type_traits.h:73
bool operator==(const unexpected< E1 > &a, const unexpected< E2 > &b)
Definition: expected.h:1069
std::conditional_t< !std::is_array< T >::value, std::unique_ptr< T, detail::Deleter< T > >, std::conditional_t< detail::is_unbounded_array_v< T >, std::unique_ptr< T, detail::Array_deleter< std::remove_extent_t< T > > >, void > > unique_ptr
The following is a common type that is returned by all the ut::make_unique (non-aligned) specializati...
Definition: ut0new.h:2439
required string type
Definition: replication_group_member_actions.proto:34
static void swap(String &a, String &b) noexcept
Definition: sql_string.h:642
constexpr assign_base() noexcept=default
constexpr assign_base() noexcept=default
constexpr assign_base() noexcept=default
Definition: expected.h:341
constexpr ctor_base() noexcept=default
constexpr ctor_base() noexcept=default
constexpr ctor_base() noexcept=default
Definition: expected.h:293
constexpr default_ctor_base() noexcept=delete
Definition: expected.h:270
constexpr default_ctor_base() noexcept=default
Definition: expected.h:881
Definition: expected.h:81
unexpect_t()=default
Definition: dtoa.cc:594
specialized storage for <void, E>.
Definition: expected.h:221
error_type & error() &
Definition: expected.h:246
constexpr const error_type && error() const &&
Definition: expected.h:247
void destruct_error()
Definition: expected.h:243
const error_type & error() const &
Definition: expected.h:245
void value_type
Definition: expected.h:222
constexpr error_type && error() &&
Definition: expected.h:248
E error_type
Definition: expected.h:223
error_type error_
Definition: expected.h:251
storage_t()
Definition: expected.h:227
void construct_error(error_type &&e)
Definition: expected.h:231
void construct_error(error_type const &e)
Definition: expected.h:230
~storage_t()
Definition: expected.h:228
void construct_error(std::in_place_t, Args &&...args)
Definition: expected.h:239
Definition: expected.h:138
void construct_value(value_type &&e)
Definition: expected.h:159
constexpr const error_type && error() const &&
Definition: expected.h:206
error_type error_
Definition: expected.h:212
void construct_error(error_type &&e)
Definition: expected.h:183
void destruct_value()
Definition: expected.h:180
value_type & value() &
Definition: expected.h:199
void construct_value(value_type const &e)
Definition: expected.h:153
~storage_t()
Definition: expected.h:143
void construct_error(std::in_place_t, Args &&...args)
Definition: expected.h:191
value_type * value_ptr()
Definition: expected.h:203
E error_type
Definition: expected.h:140
constexpr const value_type && value() const &&
Definition: expected.h:198
constexpr error_type & error() &
Definition: expected.h:207
constexpr const value_type & value() const &
Definition: expected.h:197
constexpr value_type && value() &&
Definition: expected.h:200
void construct_value()
Definition: expected.h:147
void construct_value(std::in_place_t, std::initializer_list< U > il, Args &&...args)
Definition: expected.h:175
void construct_value(std::in_place_t, Args &&...args)
Definition: expected.h:167
void destruct_error()
Definition: expected.h:195
T value_type
Definition: expected.h:139
value_type value_
Definition: expected.h:211
storage_t()
Definition: expected.h:142
void construct_error(error_type const &e)
Definition: expected.h:182
const value_type * value_ptr() const
Definition: expected.h:202
constexpr error_type && error() &&
Definition: expected.h:208
constexpr const error_type & error() const &
Definition: expected.h:205