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