STX  1.0.0
option_result.h
Go to the documentation of this file.
1 
30 #pragma once
31 
33 
34 // Why so long? Option and Result depend on each other. I don't know of a
35 // way to break the cyclic dependency, primarily because they are templated
36 //
37 // Lifetime notes:
38 // - Every change of state must be followed by a destruction (and construction
39 // if it has a non-null variant)
40 // - The object must be destroyed immediately after the contained value is moved
41 // from it.
42 //
43 // Notes:
44 // - Result is an object-forwarding type. It is unique to an
45 // interaction. It functions like a std::unique_ptr, as it doesn't allow
46 // implicitly copying its data content. Unless explicitly stated via the
47 // .clone() method
48 // - We strive to make lifetime paths as visible and predictable as
49 // possible
50 // - We also try to prevent you from shooting yourself in the foot, especially
51 // with references and implicit copies
52 // - Many are marked constexpr but won't work in a constexpr context in C++ 17
53 // mode. They work in C++ 20 and We don't want macros for that
54 // - std::move & std::forward or macros?
55 
72 
74 
75 template <typename T>
76 struct Some;
77 
78 struct NoneType;
79 
80 template <typename T>
81 struct Option;
82 
83 template <typename T>
84 struct Ok;
85 
86 template <typename E>
87 struct Err;
88 
89 template <typename T, typename E>
90 struct Result;
91 
98 struct [[nodiscard]] NoneType {
99  constexpr NoneType() noexcept = default;
100  constexpr NoneType(NoneType const&) noexcept = default;
101  constexpr NoneType(NoneType &&) noexcept = default;
102  constexpr NoneType& operator=(NoneType const&) noexcept = default;
103  constexpr NoneType& operator=(NoneType&&) noexcept = default;
104 
105  STX_CXX20_DESTRUCTOR_CONSTEXPR ~NoneType() noexcept = default;
106 
107  [[nodiscard]] constexpr bool operator==(NoneType const&) const noexcept {
108  return true;
109  }
110 
111  [[nodiscard]] constexpr bool operator!=(NoneType const&) const noexcept {
112  return false;
113  }
114 
115  template <typename T>
116  [[nodiscard]] constexpr bool operator==(Some<T> const&) const noexcept {
117  return false;
118  }
119 
120  template <typename T>
121  [[nodiscard]] constexpr bool operator!=(Some<T> const&) const noexcept {
122  return true;
123  }
124 };
125 
127 constexpr NoneType const None{};
128 
160 template <typename T>
161 struct [[nodiscard]] Some {
162  static_assert(movable<T>, "Value type 'T' for 'Option<T>' must be movable");
163  static_assert(
164  !is_reference<T>,
165  "Cannot use a reference for value type 'T' of 'Option<T>' , To prevent "
166  "subtleties use "
167  "type wrappers like std::reference_wrapper (stx::Ref) or any of the "
168  "`stx::ConstRef` or `stx::MutRef` specialized aliases instead");
169 
170  using value_type = T;
171 
173  explicit constexpr Some(T && value) : value_(std::forward<T&&>(value)) {}
174 
175  constexpr Some(Some && rhs) = default;
176  constexpr Some& operator=(Some&& rhs) = default;
177  constexpr Some(Some const&) = default;
178  constexpr Some& operator=(Some const&) = default;
179 
180  STX_CXX20_DESTRUCTOR_CONSTEXPR ~Some() = default;
181 
182  [[nodiscard]] constexpr T const& value() const& noexcept { return value_; }
183  [[nodiscard]] constexpr T& value()& noexcept { return value_; }
184  [[nodiscard]] constexpr T const value() const&& { return std::move(value_); }
185  [[nodiscard]] constexpr T value()&& { return std::move(value_); }
186 
187  template <typename U>
188  [[nodiscard]] constexpr bool operator==(Some<U> const& cmp) const {
189  static_assert(equality_comparable<T, U>);
190  return value() == cmp.value();
191  }
192 
193  template <typename U>
194  [[nodiscard]] constexpr bool operator!=(Some<U> const& cmp) const {
195  static_assert(equality_comparable<T, U>);
196  return value() != cmp.value();
197  }
198 
199  [[nodiscard]] constexpr bool operator==(NoneType const&) const noexcept {
200  return false;
201  }
202 
203  [[nodiscard]] constexpr bool operator!=(NoneType const&) const noexcept {
204  return true;
205  }
206 
207  private:
208  T value_;
209 
210  template <typename Tp>
211  friend struct Option;
212 };
213 
242 template <typename T>
243 struct [[nodiscard]] Ok {
244  static_assert(movable<T>, "Value type 'T' for 'Ok<T>' must be movable");
245  static_assert(
246  !is_reference<T>,
247  "Cannot use a reference for value type 'T' of 'Ok<T>' , To prevent "
248  "subtleties use "
249  "type wrappers like std::reference_wrapper (stx::Ref) or any of the "
250  "`stx::ConstRef` or `stx::MutRef` specialized aliases instead");
251 
252  using value_type = T;
253 
255  explicit constexpr Ok(T && value) : value_(std::forward<T&&>(value)) {}
256 
257  constexpr Ok(Ok && rhs) = default;
258  constexpr Ok& operator=(Ok&& rhs) = default;
259  constexpr Ok(Ok const&) = default;
260  constexpr Ok& operator=(Ok const&) = default;
261 
262  STX_CXX20_DESTRUCTOR_CONSTEXPR ~Ok() = default;
263 
264  template <typename U>
265  [[nodiscard]] constexpr bool operator==(Ok<U> const& cmp) const {
266  static_assert(equality_comparable<T, U>);
267  return value() == cmp.value();
268  }
269 
270  template <typename U>
271  [[nodiscard]] constexpr bool operator!=(Ok<U> const& cmp) const {
272  static_assert(equality_comparable<T, U>);
273  return value() != cmp.value();
274  }
275 
276  template <typename U>
277  [[nodiscard]] constexpr bool operator==(Err<U> const&) const noexcept {
278  return false;
279  }
280 
281  template <typename U>
282  [[nodiscard]] constexpr bool operator!=(Err<U> const&) const noexcept {
283  return true;
284  }
285 
286  [[nodiscard]] constexpr T const& value() const& noexcept { return value_; }
287  [[nodiscard]] constexpr T& value()& noexcept { return value_; }
288  [[nodiscard]] constexpr T const value() const&& { return std::move(value_); }
289  [[nodiscard]] constexpr T value()&& { return std::move(value_); }
290 
291  private:
292  T value_;
293 
294  template <typename Tp, typename Er>
295  friend struct Result;
296 };
297 
327 template <typename E>
328 struct [[nodiscard]] Err {
329  static_assert(movable<E>, "Error type 'E' for 'Err<E>' must be movable");
330  static_assert(
331  !is_reference<E>,
332  "Cannot use a reference for error type 'E' of 'Err<E>' , To prevent "
333  "subtleties use "
334  "type wrappers like std::reference_wrapper (stx::Ref) or any of the "
335  "`stx::ConstRef` or `stx::MutRef` specialized aliases instead");
336 
337  using value_type = E;
338 
340  explicit constexpr Err(E && value) : value_(std::forward<E&&>(value)) {}
341 
342  constexpr Err(Err && rhs) = default;
343  constexpr Err& operator=(Err&& rhs) = default;
344  constexpr Err(Err const&) = default;
345  constexpr Err& operator=(Err const&) = default;
346 
347  STX_CXX20_DESTRUCTOR_CONSTEXPR ~Err() = default;
348 
349  template <typename F>
350  [[nodiscard]] constexpr bool operator==(Err<F> const& cmp) const {
351  static_assert(equality_comparable<E, F>);
352  return value() == cmp.value();
353  }
354 
355  template <typename F>
356  [[nodiscard]] constexpr bool operator!=(Err<F> const& cmp) const {
357  static_assert(equality_comparable<E, F>);
358  return value() != cmp.value();
359  }
360 
361  template <typename F>
362  [[nodiscard]] constexpr bool operator==(Ok<F> const&) const noexcept {
363  return false;
364  }
365 
366  template <typename F>
367  [[nodiscard]] constexpr bool operator!=(Ok<F> const&) const noexcept {
368  return true;
369  }
370 
371  [[nodiscard]] constexpr E const& value() const& noexcept { return value_; }
372  [[nodiscard]] constexpr E& value()& noexcept { return value_; }
373  [[nodiscard]] constexpr E const value() const&& { return std::move(value_); }
374  [[nodiscard]] constexpr E value()&& { return std::move(value_); }
375 
376  private:
377  E value_;
378 
379  template <typename Tp, typename Er>
380  friend struct Result;
381 };
382 
383 // JUST LOOK AWAY
384 
385 namespace internal {
386 namespace option {
387 // constructs an r-value reference to the option's value directly, without
388 // checking if it is in the `Some` or `None` state. This is totally unsafe and
389 // user-end code should **never** use this
390 template <typename Tp>
391 inline Tp&& unsafe_value_move(Option<Tp>&);
392 
393 } // namespace option
394 } // namespace internal
395 
438 template <typename T>
439 struct [[nodiscard]] Option {
440  public:
441  using value_type = T;
442 
443  static_assert(movable<T>, "Value type 'T' for 'Option<T>' must be movable");
444  static_assert(
445  !is_reference<T>,
446  "Cannot use a reference for value type 'T' of 'Option<T>' , To prevent "
447  "subtleties use "
448  "type wrappers like std::reference_wrapper (stx::Ref) or any of the "
449  "`stx::ConstRef` or `stx::MutRef` specialized aliases instead");
450 
451  constexpr Option() noexcept : is_none_(true) {}
452 
453  constexpr Option(Some<T> && some)
454  : storage_value_(std::move(some.value_)), is_none_(false) {}
455 
456  constexpr Option(Some<T> const& some)
457  : storage_value_(some.value()), is_none_(false) {
458  static_assert(copy_constructible<T>);
459  }
460 
461  constexpr Option(NoneType const&) noexcept : is_none_(true) {}
462 
463  // constexpr?
464  // placement-new!
465  // we can't make this constexpr as of C++ 20
466  Option(Option && rhs) : is_none_(rhs.is_none_) {
467  if (rhs.is_some()) {
468  new (&storage_value_) T(std::move(rhs.storage_value_));
469  }
470  }
471 
472  Option& operator=(Option&& rhs) {
473  // contained object is destroyed as appropriate in the parent scope
474  if (is_some() && rhs.is_some()) {
475  std::swap(storage_value_, rhs.storage_value_);
476  } else if (is_some() && rhs.is_none()) {
477  // we let the ref'd `rhs` destroy the object instead
478  new (&rhs.storage_value_) T(std::move(storage_value_));
479  storage_value_.~T();
480  is_none_ = true;
481  rhs.is_none_ = false;
482  } else if (is_none() && rhs.is_some()) {
483  new (&storage_value_) T(std::move(rhs.storage_value_));
484  rhs.storage_value_.~T();
485  rhs.is_none_ = true;
486  is_none_ = false;
487  }
488 
489  return *this;
490  }
491 
492  Option(Option const& rhs) : is_none_(rhs.is_none_) {
493  static_assert(copy_constructible<T>);
494  if (rhs.is_some()) {
495  new (&storage_value_) T(rhs.storage_value_);
496  }
497  }
498 
499  Option& operator=(Option const& rhs) {
500  static_assert(copy_constructible<T>);
501 
502  if (is_some() && rhs.is_some()) {
503  storage_value_ = rhs.storage_value_;
504  } else if (is_some() && rhs.is_none()) {
505  storage_value_.~T();
506  is_none_ = true;
507  } else if (is_none() && rhs.is_some()) {
508  new (&storage_value_) T(rhs.storage_value_);
509  is_none_ = false;
510  }
511 
512  return *this;
513  }
514 
516  if (is_some()) {
517  storage_value_.~T();
518  }
519  }
520 
521  template <typename U>
522  [[nodiscard]] constexpr bool operator==(Option<U> const& cmp) const {
523  static_assert(equality_comparable<T, U>);
524  if (is_some() && cmp.is_some()) {
525  return value_cref_() == cmp.value_cref_();
526  } else if (is_none() && cmp.is_none()) {
527  return true;
528  } else {
529  return false;
530  }
531  }
532 
533  template <typename U>
534  [[nodiscard]] constexpr bool operator!=(Option<U> const& cmp) const {
535  static_assert(equality_comparable<T, U>);
536  if (is_some() && cmp.is_some()) {
537  return value_cref_() != cmp.value_cref_();
538  } else if (is_none() && cmp.is_none()) {
539  return false;
540  } else {
541  return true;
542  }
543  }
544 
545  template <typename U>
546  [[nodiscard]] constexpr bool operator==(Some<U> const& cmp) const {
547  static_assert(equality_comparable<T, U>);
548  if (is_some()) {
549  return value_cref_() == cmp.value();
550  } else {
551  return false;
552  }
553  }
554 
555  template <typename U>
556  [[nodiscard]] constexpr bool operator!=(Some<U> const& cmp) const {
557  static_assert(equality_comparable<T, U>);
558  if (is_some()) {
559  return value_cref_() != cmp.value();
560  } else {
561  return true;
562  }
563  }
564 
565  [[nodiscard]] constexpr bool operator==(NoneType const&) const noexcept {
566  return is_none();
567  }
568 
569  [[nodiscard]] constexpr bool operator!=(NoneType const&) const noexcept {
570  return is_some();
571  }
572 
587  [[nodiscard]] constexpr bool is_some() const noexcept { return !is_none(); }
588 
602  [[nodiscard]] constexpr bool is_none() const noexcept { return is_none_; }
603 
604  [[nodiscard]] operator bool() const noexcept { return is_some(); }
605 
623  template <typename CmpType>
624  [[nodiscard]] constexpr bool contains(CmpType const& cmp) const {
625  static_assert(equality_comparable<T, CmpType>);
626  if (is_some()) {
627  return value_cref_() == cmp;
628  } else {
629  return false;
630  }
631  }
632 
646  template <typename UnaryPredicate>
647  [[nodiscard]] constexpr bool exists(UnaryPredicate && predicate) const {
648  static_assert(invocable<UnaryPredicate&&, T const&>);
650 
651  if (is_some()) {
652  return std::forward<UnaryPredicate&&>(predicate)(value_cref_());
653  } else {
654  return false;
655  }
656  }
657 
676  [[nodiscard]] T& value()& noexcept {
677  if (is_none()) internal::option::no_lref();
678  return value_ref_();
679  }
680 
698  [[nodiscard]] T const& value() const& noexcept {
699  if (is_none()) internal::option::no_lref();
700  return value_cref_();
701  }
702 
704  [[deprecated("Use `unwrap()` instead")]] T value()&& = delete;
706  [[deprecated("Use `unwrap()` instead")]] T const value() const&& = delete;
707 
714  [[nodiscard]] constexpr auto as_cref() const& noexcept->Option<ConstRef<T>> {
715  if (is_some()) {
716  return Some<ConstRef<T>>(ConstRef<T>(value_cref_()));
717  } else {
718  return None;
719  }
720  }
721 
722  [[deprecated(
723  "calling Option::as_cref() on an r-value, and therefore binding a "
724  "reference to an object that is marked to be moved")]] //
725  [[nodiscard]] constexpr auto
726  as_cref() const&& noexcept->Option<ConstRef<T>> = delete;
727 
748  [[nodiscard]] constexpr auto as_ref()& noexcept->Option<MutRef<T>> {
749  if (is_some()) {
750  return Some<MutRef<T>>(MutRef<T>(value_ref_()));
751  } else {
752  return None;
753  }
754  }
755 
756  [[nodiscard]] constexpr auto as_ref() const& noexcept->Option<ConstRef<T>> {
757  return as_cref();
758  }
759 
760  [[deprecated(
761  "calling Option::as_ref() on an r-value, and therefore binding a "
762  "reference to an object that is marked to be moved")]] //
763  [[nodiscard]] constexpr auto
764  as_ref()&& noexcept->Option<MutRef<T>> = delete;
765 
766  [[deprecated(
767  "calling Option::as_ref() on an r-value, and therefore binding a "
768  "reference to an object that is marked to be moved")]] //
769  [[nodiscard]] constexpr auto
770  as_ref() const&& noexcept->Option<ConstRef<T>> = delete;
771 
793  [[nodiscard]] auto expect(std::string_view const& msg)&&->T {
794  if (is_some()) {
795  return std::move(value_ref_());
796  } else {
798  }
799  }
800 
823  [[nodiscard]] auto unwrap()&&->T {
824  if (is_some()) {
825  return std::move(value_ref_());
826  } else {
828  }
829  }
830 
846  [[nodiscard]] constexpr auto unwrap_or(T && alt)&&->T {
847  if (is_some()) {
848  return std::move(value_ref_());
849  } else {
850  return std::move(alt);
851  }
852  }
853 
867  template <typename Fn>
868  [[nodiscard]] constexpr auto unwrap_or_else(Fn && op)&&->T {
869  static_assert(invocable<Fn&&>);
870  if (is_some()) {
871  return std::move(value_ref_());
872  } else {
873  return std::forward<Fn&&>(op)();
874  }
875  }
876 
899  template <typename Fn>
900  [[nodiscard]] constexpr auto map(Fn &&
901  op)&&->Option<invoke_result<Fn&&, T&&>> {
902  static_assert(invocable<Fn&&, T&&>);
903  if (is_some()) {
905  std::forward<Fn&&>(op)(std::move(value_ref_())));
906  } else {
907  return None;
908  }
909  }
910 
926  template <typename Fn, typename A>
927  [[nodiscard]] constexpr auto map_or(Fn && op,
928  A && alt)&&->invoke_result<Fn&&, T&&> {
929  static_assert(invocable<Fn&&, T&&>);
930  if (is_some()) {
931  return std::forward<Fn&&>(op)(std::move(value_ref_()));
932  } else {
933  return std::forward<A&&>(alt);
934  }
935  }
936 
955  template <typename Fn, typename AltFn>
956  [[nodiscard]] constexpr auto map_or_else(
957  Fn && op, AltFn && alt)&&->invoke_result<Fn&&, T&&> {
958  static_assert(invocable<Fn&&, T&&>);
959  static_assert(invocable<AltFn&&>);
960 
961  if (is_some()) {
962  return std::forward<Fn&&>(op)(std::move(value_ref_()));
963  } else {
964  return std::forward<AltFn&&>(alt)();
965  }
966  }
967 
986  // copies the argument if not an r-value
987  template <typename E>
988  [[nodiscard]] constexpr auto ok_or(E error)&&->Result<T, E> {
989  if (is_some()) {
990  return Ok<T>(std::move(value_ref_()));
991  } else {
992  // tries to copy if it is an l-value ref and moves if it is an r-value
993  return Err<E>(std::forward<E>(error));
994  }
995  }
996 
1013  // can return reference but the user will get the error
1014  template <typename Fn>
1015  [[nodiscard]] constexpr auto ok_or_else(
1016  Fn && op)&&->Result<T, invoke_result<Fn&&>> {
1017  static_assert(invocable<Fn&&>);
1018  if (is_some()) {
1019  return Ok<T>(std::move(value_ref_()));
1020  } else {
1021  return Err<invoke_result<Fn&&>>(std::forward<Fn&&>(op)());
1022  }
1023  }
1024 
1048  // won't compile if a normal reference is passed since it is not copyable
1049  // if an rvalue, will pass. We are not forwarding refences here.
1050  // a requirement here is for it to be constructible with a None
1051  template <typename U> //
1052  [[nodiscard]] constexpr auto AND(Option<U> && cmp)&&->Option<U> {
1053  if (is_some()) {
1054  return std::forward<Option<U>&&>(cmp);
1055  } else {
1056  return None;
1057  }
1058  }
1059 
1078  template <typename Fn>
1079  [[nodiscard]] constexpr auto and_then(Fn && op)&&->invoke_result<Fn&&, T&&> {
1080  static_assert(invocable<Fn&&, T&&>);
1081  if (is_some()) {
1082  return std::forward<Fn&&>(op)(std::move(value_ref_()));
1083  } else {
1084  return None;
1085  }
1086  }
1087 
1107  template <typename UnaryPredicate>
1108  [[nodiscard]] constexpr auto filter(UnaryPredicate && predicate)&&->Option {
1109  static_assert(invocable<UnaryPredicate&&, T const&>);
1111 
1112  if (is_some() && std::forward<UnaryPredicate&&>(predicate)(value_cref_())) {
1113  return std::move(*this);
1114  } else {
1115  return None;
1116  }
1117  }
1118 
1138  template <typename UnaryPredicate>
1139  [[nodiscard]] constexpr auto filter_not(UnaryPredicate &&
1140  predicate)&&->Option {
1141  static_assert(invocable<UnaryPredicate&&, T const&>);
1143 
1144  if (is_some() &&
1145  !std::forward<UnaryPredicate&&>(predicate)(value_cref_())) {
1146  return std::move(*this);
1147  } else {
1148  return None;
1149  }
1150  }
1151 
1180  [[nodiscard]] constexpr auto OR(Option && alt)&&->Option {
1181  if (is_some()) {
1182  return std::move(*this);
1183  } else {
1184  return std::move(alt);
1185  }
1186  }
1187 
1204  template <typename Fn>
1205  [[nodiscard]] constexpr auto or_else(Fn && op)&&->Option {
1206  static_assert(invocable<Fn&&>);
1207  if (is_some()) {
1208  return std::move(*this);
1209  } else {
1210  return std::forward<Fn&&>(op)();
1211  }
1212  }
1213 
1239  [[nodiscard]] constexpr auto XOR(Option && alt)&&->Option {
1240  if (is_some() && alt.is_none()) {
1241  return std::move(*this);
1242  } else if (is_none() && alt.is_some()) {
1243  return std::move(alt);
1244  } else {
1245  return None;
1246  }
1247  }
1248 
1267  [[nodiscard]] constexpr auto take()->Option {
1268  if (is_some()) {
1269  auto some = Some<T>(std::move(value_ref_()));
1270  value_ref_().~T();
1271  is_none_ = true;
1272  return some;
1273  } else {
1274  return None;
1275  }
1276  }
1277 
1298  [[nodiscard]] auto replace(T && replacement)->Option {
1299  if (is_some()) {
1300  std::swap(replacement, value_ref_());
1301  return Some<T>(std::move(replacement));
1302  } else {
1303  new (&storage_value_) T(std::forward<T&&>(replacement));
1304  is_none_ = false;
1305  return None;
1306  }
1307  }
1308 
1329  [[nodiscard]] auto replace(T const& replacement)->Option {
1330  static_assert(copy_constructible<T>);
1331  if (is_some()) {
1332  T copy = replacement;
1333  std::swap(copy, value_ref_());
1334  return Some<T>(std::move(copy));
1335  } else {
1336  new (&storage_value_) T(replacement);
1337  is_none_ = false;
1338  return None;
1339  }
1340  }
1341 
1353  [[nodiscard]] constexpr auto clone() const->Option {
1354  static_assert(copy_constructible<T>);
1355  if (is_some()) {
1356  return Some<T>(std::move(T(value_cref_())));
1357  } else {
1358  return None;
1359  }
1360  }
1361 
1382  void expect_none(std::string_view const& msg)&& {
1383  if (is_some()) {
1385  }
1386  }
1387 
1408  void unwrap_none()&& {
1409  if (is_some()) {
1411  }
1412  }
1413 
1432  [[nodiscard]] constexpr auto unwrap_or_default()&&->T {
1433  static_assert(std::is_default_constructible_v<T>);
1434  if (is_some()) {
1435  return std::move(value_ref_());
1436  } else {
1437  return T();
1438  }
1439  }
1440 
1469  template <typename SomeFn, typename NoneFn>
1470  [[nodiscard]] constexpr auto match(
1471  SomeFn && some_fn, NoneFn && none_fn)&&->invoke_result<SomeFn&&, T&&> {
1472  static_assert(invocable<SomeFn&&, T&&>);
1473  static_assert(invocable<NoneFn&&>);
1474 
1475  if (is_some()) {
1476  return std::forward<SomeFn&&>(some_fn)(std::move(value_ref_()));
1477  } else {
1478  return std::forward<NoneFn&&>(none_fn)();
1479  }
1480  }
1481 
1482  template <typename SomeFn, typename NoneFn>
1483  [[nodiscard]] constexpr auto match(
1484  SomeFn && some_fn, NoneFn && none_fn)&->invoke_result<SomeFn&&, T&> {
1485  static_assert(invocable<SomeFn&&, T&>);
1486  static_assert(invocable<NoneFn&&>);
1487 
1488  if (is_some()) {
1489  return std::forward<SomeFn&&>(some_fn)(value_ref_());
1490  } else {
1491  return std::forward<NoneFn&&>(none_fn)();
1492  }
1493  }
1494 
1495  template <typename SomeFn, typename NoneFn>
1496  [[nodiscard]] constexpr auto match(SomeFn && some_fn, NoneFn && none_fn)
1497  const&->invoke_result<SomeFn&&, T const&> {
1498  static_assert(invocable<SomeFn&&, T const&>);
1499  static_assert(invocable<NoneFn&&>);
1500 
1501  if (is_some()) {
1502  return std::forward<SomeFn&&>(some_fn)(value_cref_());
1503  } else {
1504  return std::forward<NoneFn&&>(none_fn)();
1505  }
1506  }
1507 
1508  private:
1509  union {
1511  };
1512 
1513  bool is_none_;
1514 
1515  [[nodiscard]] constexpr T& value_ref_() { return storage_value_; }
1516 
1517  [[nodiscard]] constexpr T const& value_cref_() const {
1518  return storage_value_;
1519  }
1520 
1521  template <typename Tp>
1523 };
1524 
1525 template <typename U, typename T>
1526 [[nodiscard]] STX_FORCE_INLINE constexpr bool operator==(
1527  Some<U> const& cmp, Option<T> const& option) {
1528  return option == cmp;
1529 }
1530 
1531 template <typename U, typename T>
1532 [[nodiscard]] STX_FORCE_INLINE constexpr bool operator!=(
1533  Some<U> const& cmp, Option<T> const& option) {
1534  return option != cmp;
1535 }
1536 
1537 template <typename T>
1538 [[nodiscard]] STX_FORCE_INLINE constexpr bool operator==(
1539  NoneType const&, Option<T> const& option) noexcept {
1540  return option.is_none();
1541 }
1542 
1543 template <typename T>
1544 [[nodiscard]] STX_FORCE_INLINE constexpr bool operator!=(
1545  NoneType const&, Option<T> const& option) noexcept {
1546  return option.is_some();
1547 }
1548 
1549 // JUST LOOK AWAY
1550 
1551 namespace internal {
1552 namespace result {
1553 
1554 // constructs an r-value reference to the result's value directly, without
1555 // checking if it is in the `Ok` or `Err` state. This is totally unsafe and
1556 // user-end code should **never** use this
1557 template <typename Tp, typename Er>
1558 inline Tp&& unsafe_value_move(Result<Tp, Er>&);
1559 
1560 // constructs an r-value reference to the result's error directly, without
1561 // checking if it is in the `Err` or `Ok` state. This is totally unsafe and
1562 // user-end code should **never** use this
1563 template <typename Tp, typename Er>
1564 inline Er&& unsafe_err_move(Result<Tp, Er>&);
1565 
1566 } // namespace result
1567 } // namespace internal
1568 
1638 template <typename T, typename E>
1639 struct [[nodiscard]] Result {
1640  public:
1641  static_assert(movable<T>,
1642  "Value type 'T' for 'Result<T, E>' must be movable");
1643  static_assert(movable<E>,
1644  "Error type 'E' for 'Result<T, E>' must be movable");
1645  static_assert(
1646  !is_reference<T>,
1647  "Cannot use a reference for value type 'T' of 'Result<T, E>', To prevent "
1648  "subtleties use "
1649  "type wrappers like std::reference_wrapper (stx::Ref) or any of the "
1650  "`stx::ConstRef` or `stx::MutRef` specialized aliases instead");
1651  static_assert(
1652  !is_reference<E>,
1653  "Cannot use a reference for error type 'E' of 'Result<T, E>', To prevent "
1654  "subtleties use "
1655  "type wrappers like std::reference_wrapper (stx::Ref) or any of the "
1656  "`stx::ConstRef` or `stx::MutRef` specialized aliases instead");
1657 
1658  using value_type = T;
1659  using error_type = E;
1660 
1661  constexpr Result(Ok<T> && result)
1662  : storage_value_(std::forward<T>(result.value_)), is_ok_(true) {}
1663 
1664  constexpr Result(Err<E> && err)
1665  : storage_err_(std::forward<E>(err.value_)), is_ok_(false) {}
1666 
1667  // not possible as constexpr yet:
1668  // 1 - we need to check which variant is present
1669  // 2 - the union will be default-constructed (empty) and we thus need to call
1670  // placement-new in the constructor block
1671  Result(Result && rhs) : is_ok_(rhs.is_ok_) {
1672  if (rhs.is_ok()) {
1673  new (&storage_value_) T(std::move(rhs.storage_value_));
1674  } else {
1675  new (&storage_err_) E(std::move(rhs.storage_err_));
1676  }
1677  }
1678 
1679  Result& operator=(Result&& rhs) {
1680  if (is_ok() && rhs.is_ok()) {
1681  std::swap(value_ref_(), rhs.value_ref_());
1682  } else if (is_ok() && rhs.is_err()) {
1683  // we need to place a new value in here (discarding old value)
1684  storage_value_.~T();
1685  new (&storage_err_) E(std::move(rhs.storage_err_));
1686  is_ok_ = false;
1687  } else if (is_err() && rhs.is_ok()) {
1688  storage_err_.~E();
1689  new (&storage_value_) T(std::move(rhs.storage_value_));
1690  is_ok_ = true;
1691  } else {
1692  // both are errs
1693  std::swap(err_ref_(), rhs.err_ref_()); // NOLINT
1694  }
1695  return *this;
1696  }
1697 
1698  Result() = delete;
1699  Result(Result const& rhs) = delete;
1700  Result& operator=(Result const& rhs) = delete;
1701 
1703  if (is_ok()) {
1704  storage_value_.~T();
1705  } else {
1706  storage_err_.~E();
1707  }
1708  };
1709 
1710  template <typename U>
1711  [[nodiscard]] constexpr bool operator==(Ok<U> const& cmp) const {
1712  static_assert(equality_comparable<T, U>);
1713  if (is_ok()) {
1714  return value_cref_() == cmp.value();
1715  } else {
1716  return false;
1717  }
1718  }
1719 
1720  template <typename U>
1721  [[nodiscard]] constexpr bool operator!=(Ok<U> const& cmp) const {
1722  static_assert(equality_comparable<T, U>);
1723  if (is_ok()) {
1724  return value_cref_() != cmp.value();
1725  } else {
1726  return true;
1727  }
1728  }
1729 
1730  template <typename F>
1731  [[nodiscard]] constexpr bool operator==(Err<F> const& cmp) const {
1732  static_assert(equality_comparable<E, F>);
1733  if (is_ok()) {
1734  return false;
1735  } else {
1736  return err_cref_() == cmp.value();
1737  }
1738  }
1739 
1740  template <typename F>
1741  [[nodiscard]] constexpr bool operator!=(Err<F> const& cmp) const {
1742  static_assert(equality_comparable<E, F>);
1743  if (is_ok()) {
1744  return true;
1745  } else {
1746  return err_cref_() != cmp.value();
1747  }
1748  }
1749 
1750  template <typename U, typename F>
1751  [[nodiscard]] constexpr bool operator==(Result<U, F> const& cmp) const {
1752  static_assert(equality_comparable<T, U>);
1753  static_assert(equality_comparable<E, F>);
1754 
1755  if (is_ok() && cmp.is_ok()) {
1756  return value_cref_() == cmp.value_cref_();
1757  } else if (is_err() && cmp.is_err()) {
1758  return err_cref_() == cmp.err_cref_();
1759  } else {
1760  return false;
1761  }
1762  }
1763 
1764  template <typename U, typename F>
1765  [[nodiscard]] constexpr bool operator!=(Result<U, F> const& cmp) const {
1766  static_assert(equality_comparable<T, U>);
1767  static_assert(equality_comparable<E, F>);
1768 
1769  if (is_ok() && cmp.is_ok()) {
1770  return value_cref_() != cmp.value_cref_();
1771  } else if (is_err() && cmp.is_err()) {
1772  return err_cref_() != cmp.err_cref_();
1773  } else {
1774  return true;
1775  }
1776  }
1777 
1792  [[nodiscard]] constexpr bool is_ok() const noexcept { return is_ok_; }
1793 
1807  [[nodiscard]] constexpr bool is_err() const noexcept { return !is_ok(); }
1808 
1809  [[nodiscard]] operator bool() const noexcept { return is_ok(); }
1810 
1829  template <typename CmpType>
1830  [[nodiscard]] constexpr bool contains(CmpType const& cmp) const {
1831  static_assert(equality_comparable<T, CmpType>);
1832  if (is_ok()) {
1833  return value_cref_() == cmp;
1834  } else {
1835  return false;
1836  }
1837  }
1838 
1857  template <typename ErrCmp>
1858  [[nodiscard]] constexpr bool contains_err(ErrCmp const& cmp) const {
1859  static_assert(equality_comparable<E, ErrCmp>);
1860  if (is_ok()) {
1861  return false;
1862  } else {
1863  return err_cref_() == cmp;
1864  }
1865  }
1866 
1881  template <typename UnaryPredicate>
1882  [[nodiscard]] constexpr bool exists(UnaryPredicate && predicate) const {
1883  static_assert(invocable<UnaryPredicate&&, T const&>);
1885 
1886  if (is_ok()) {
1887  return std::forward<UnaryPredicate&&>(predicate)(value_cref_());
1888  } else {
1889  return false;
1890  }
1891  }
1892 
1907  template <typename UnaryPredicate>
1908  [[nodiscard]] constexpr bool err_exists(UnaryPredicate && predicate) const {
1909  static_assert(invocable<UnaryPredicate&&, E const&>);
1911 
1912  if (is_err()) {
1913  return std::forward<UnaryPredicate&&>(predicate)(err_cref_());
1914  } else {
1915  return false;
1916  }
1917  }
1918 
1937  [[nodiscard]] T& value()& noexcept {
1938  if (is_err()) internal::result::no_lref(err_cref_());
1939  return value_ref_();
1940  }
1941 
1959  [[nodiscard]] T const& value() const& noexcept {
1960  if (is_err()) internal::result::no_lref(err_cref_());
1961  return value_cref_();
1962  }
1963 
1965  [[deprecated("Use `unwrap()` instead")]] T value()&& = delete;
1967  [[deprecated("Use `unwrap()` instead")]] T const value() const&& = delete;
1968 
1987  [[nodiscard]] E& err_value()& noexcept {
1988  if (is_ok()) internal::result::no_err_lref();
1989  return err_ref_();
1990  }
1991 
2009  [[nodiscard]] E const& err_value() const& noexcept {
2010  if (is_ok()) internal::result::no_err_lref();
2011  return err_cref_();
2012  }
2013 
2015  [[deprecated("Use `unwrap_err()` instead")]] E err_value()&& = delete;
2017  [[deprecated("Use `unwrap_err()` instead")]] E const err_value() const&& =
2018  delete;
2019 
2036  [[nodiscard]] constexpr auto ok()&&->Option<T> {
2037  if (is_ok()) {
2038  return Some<T>(std::move(value_ref_()));
2039  } else {
2040  return None;
2041  }
2042  }
2043 
2060  [[nodiscard]] constexpr auto err()&&->Option<E> {
2061  if (is_ok()) {
2062  return None;
2063  } else {
2064  return Some<E>(std::move(err_ref_()));
2065  }
2066  }
2067 
2084  [[nodiscard]] constexpr auto as_cref()
2085  const& noexcept->Result<ConstRef<T>, ConstRef<E>> {
2086  if (is_ok()) {
2087  return Ok<ConstRef<T>>(ConstRef<T>(value_cref_()));
2088  } else {
2089  return Err<ConstRef<E>>(ConstRef<E>(err_cref_()));
2090  }
2091  }
2092 
2093  [[deprecated(
2094  "calling Result::as_cref() on an r-value, and "
2095  "therefore binding an l-value reference to an object that is marked to "
2096  "be moved")]] //
2097  [[nodiscard]] constexpr auto
2098  as_cref() const&& noexcept->Result<ConstRef<T>, ConstRef<E>> = delete;
2099 
2120  [[nodiscard]] constexpr auto as_ref()& noexcept
2121  ->Result<MutRef<T>, MutRef<E>> {
2122  if (is_ok()) {
2123  return Ok<MutRef<T>>(MutRef<T>(value_ref_()));
2124  } else {
2125  return Err<MutRef<E>>(MutRef<E>(err_ref_()));
2126  }
2127  }
2128 
2129  [[nodiscard]] constexpr auto as_ref()
2130  const& noexcept->Result<ConstRef<T>, ConstRef<E>> {
2131  return as_cref();
2132  }
2133 
2134  [[deprecated(
2135  "calling Result::as_ref() on an r-value, and therefore binding a "
2136  "reference to an object that is marked to be moved")]] //
2137  [[nodiscard]] constexpr auto
2138  as_ref()&& noexcept->Result<MutRef<T>, MutRef<E>> = delete;
2139 
2140  [[deprecated(
2141  "calling Result::as_ref() on an r-value, and therefore binding a "
2142  "reference to an object that is marked to be moved")]] //
2143  [[nodiscard]] constexpr auto
2144  as_ref() const&& noexcept->Result<ConstRef<T>, ConstRef<E>> = delete;
2145 
2171  template <typename Fn>
2172  [[nodiscard]] constexpr auto map(Fn &&
2173  op)&&->Result<invoke_result<Fn&&, T&&>, E> {
2174  static_assert(invocable<Fn&&, T&&>);
2175  if (is_ok()) {
2177  std::forward<Fn&&>(op)(std::move(value_ref_())));
2178  } else {
2179  return Err<E>(std::move(err_ref_()));
2180  }
2181  }
2182 
2198  template <typename Fn, typename AltType>
2199  [[nodiscard]] constexpr auto map_or(
2200  Fn && op, AltType && alt)&&->invoke_result<Fn&&, T&&> {
2201  static_assert(invocable<Fn&&, T&&>);
2202  if (is_ok()) {
2203  return std::forward<Fn&&>(op)(std::move(value_ref_()));
2204  } else {
2205  return std::forward<AltType&&>(alt);
2206  }
2207  }
2208 
2231  template <typename Fn, typename A>
2232  [[nodiscard]] constexpr auto map_or_else(
2233  Fn && op, A && alt_op)&&->invoke_result<Fn&&, T&&> {
2234  static_assert(invocable<Fn&&, T&&>);
2235  static_assert(invocable<A&&, E&&>);
2236 
2237  if (is_ok()) {
2238  return std::forward<Fn&&>(op)(std::move(value_ref_()));
2239  } else {
2240  return std::forward<A&&>(alt_op)(std::move(err_ref_()));
2241  }
2242  }
2243 
2264  template <typename Fn>
2265  [[nodiscard]] constexpr auto map_err(
2266  Fn && op)&&->Result<T, invoke_result<Fn&&, E&&>> {
2267  static_assert(invocable<Fn&&, E&&>);
2268  if (is_ok()) {
2269  return Ok<T>(std::move(value_ref_()));
2270  } else {
2272  std::forward<Fn&&>(op)(std::move(err_ref_())));
2273  }
2274  }
2275 
2300  // a copy attempt like passing a const could cause an error
2301  template <typename U, typename F>
2302  [[nodiscard]] constexpr auto AND(Result<U, F> && res)&&->Result<U, F> {
2303  static_assert(convertible<E&&, F>);
2304  if (is_ok()) {
2305  return std::forward<Result<U, F>&&>(res);
2306  } else {
2307  return Err<F>(std::move(static_cast<F>(std::move(err_ref_()))));
2308  }
2309  }
2310 
2329  template <typename Fn>
2330  [[nodiscard]] constexpr auto and_then(
2331  Fn && op)&&->Result<invoke_result<Fn&&, T&&>, E> {
2332  static_assert(invocable<Fn&&, T&&>);
2333  if (is_ok()) {
2335  std::forward<Fn&&>(op)(std::move(value_ref_())));
2336  } else {
2337  return Err<E>(std::move(err_ref_()));
2338  }
2339  }
2340 
2369  // passing a const ref will cause an error
2370  template <typename U, typename F>
2371  [[nodiscard]] constexpr auto OR(Result<U, F> && alt)&&->Result<U, F> {
2372  static_assert(convertible<T&&, U>);
2373  if (is_ok()) {
2374  return Ok<U>(std::move(static_cast<U>(std::move(value_ref_()))));
2375  } else {
2376  return std::forward<Result<U, F>&&>(alt);
2377  }
2378  }
2379 
2400  template <typename Fn>
2401  [[nodiscard]] constexpr auto or_else(Fn && op)&&->invoke_result<Fn&&, E&&> {
2402  static_assert(invocable<Fn&&, E&&>);
2403  if (is_ok()) {
2404  return Ok<T>(std::move(value_ref_()));
2405  } else {
2406  return std::forward<Fn&&>(op)(std::move(err_ref_()));
2407  }
2408  }
2409 
2430  [[nodiscard]] constexpr auto unwrap_or(T && alt)&&->T {
2431  if (is_ok()) {
2432  return std::move(value_ref_());
2433  } else {
2434  return std::move(alt);
2435  }
2436  }
2437 
2453  template <typename Fn>
2454  [[nodiscard]] constexpr auto unwrap_or_else(Fn && op)&&->T {
2455  static_assert(invocable<Fn&&, E&&>);
2456  if (is_ok()) {
2457  return std::move(value_ref_());
2458  } else {
2459  return std::forward<Fn&&>(op)(std::move(err_ref_()));
2460  }
2461  }
2462 
2479  [[nodiscard]] auto unwrap()&&->T {
2480  if (is_err()) {
2481  internal::result::no_value(err_cref_());
2482  }
2483  return std::move(value_ref_());
2484  }
2485 
2501  [[nodiscard]] auto expect(std::string_view const& msg)&&->T {
2502  if (is_err()) {
2503  internal::result::expect_value_failed(msg, err_cref_());
2504  }
2505  return std::move(value_ref_());
2506  }
2507 
2527  [[nodiscard]] auto unwrap_err()&&->E {
2528  if (is_ok()) {
2530  }
2531  return std::move(err_ref_());
2532  }
2533 
2552  [[nodiscard]] auto expect_err(std::string_view const& msg)&&->E {
2553  if (is_ok()) {
2555  }
2556  return std::move(err_ref_());
2557  }
2558 
2579  [[nodiscard]] constexpr auto unwrap_or_default()&&->T {
2580  static_assert(std::is_default_constructible_v<T>);
2581  if (is_ok()) {
2582  return std::move(value_ref_());
2583  } else {
2584  return T();
2585  }
2586  }
2587 
2619  template <typename OkFn, typename ErrFn>
2620  [[nodiscard]] constexpr auto match(
2621  OkFn && ok_fn, ErrFn && err_fn)&&->invoke_result<OkFn&&, T&&> {
2622  static_assert(invocable<OkFn&&, T&&>);
2623  static_assert(invocable<ErrFn&&, E&&>);
2624 
2625  if (is_ok()) {
2626  return std::forward<OkFn&&>(ok_fn)(std::move(value_ref_()));
2627  } else {
2628  return std::forward<ErrFn&&>(err_fn)(std::move(err_ref_()));
2629  }
2630  }
2631 
2632  template <typename OkFn, typename ErrFn>
2633  [[nodiscard]] constexpr auto match(
2634  OkFn && ok_fn, ErrFn && err_fn)&->invoke_result<OkFn&&, T&> {
2635  static_assert(invocable<OkFn&&, T&>);
2636  static_assert(invocable<ErrFn&&, E&>);
2637 
2638  if (is_ok()) {
2639  return std::forward<OkFn&&>(ok_fn)(value_ref_());
2640  } else {
2641  return std::forward<ErrFn&&>(err_fn)(err_ref_());
2642  }
2643  }
2644 
2645  template <typename OkFn, typename ErrFn>
2646  [[nodiscard]] constexpr auto match(OkFn && ok_fn, ErrFn && err_fn)
2647  const&->invoke_result<OkFn&&, T const&> {
2648  static_assert(invocable<OkFn&&, T const&>);
2649  static_assert(invocable<ErrFn&&, E const&>);
2650 
2651  if (is_ok()) {
2652  return std::forward<OkFn&&>(ok_fn)(value_cref_());
2653  } else {
2654  return std::forward<ErrFn&&>(err_fn)(err_cref_());
2655  }
2656  }
2657 
2669  [[nodiscard]] constexpr auto clone() const->Result<T, E> {
2670  static_assert(copy_constructible<T>);
2671  static_assert(copy_constructible<E>);
2672 
2673  if (is_ok()) {
2674  return Ok<T>(std::move(T(value_cref_())));
2675  } else {
2676  return Err<E>(std::move(E(err_cref_())));
2677  }
2678  }
2679 
2680  private:
2681  union {
2684  };
2685 
2686  bool is_ok_;
2687 
2688  [[nodiscard]] constexpr T& value_ref_() noexcept { return storage_value_; }
2689 
2690  [[nodiscard]] constexpr T const& value_cref_() const noexcept {
2691  return storage_value_;
2692  }
2693 
2694  [[nodiscard]] constexpr E& err_ref_() noexcept { return storage_err_; }
2695 
2696  [[nodiscard]] constexpr E const& err_cref_() const noexcept {
2697  return storage_err_;
2698  }
2699 
2700  template <typename Tp, typename Er>
2702 
2703  template <typename Tp, typename Er>
2705 };
2706 
2707 template <typename U, typename T, typename E>
2708 [[nodiscard]] STX_FORCE_INLINE constexpr bool operator==(
2709  Ok<U> const& cmp, Result<T, E> const& result) {
2710  return result == cmp;
2711 }
2712 
2713 template <typename U, typename T, typename E>
2714 [[nodiscard]] STX_FORCE_INLINE constexpr bool operator!=(
2715  Ok<U> const& cmp, Result<T, E> const& result) {
2716  return result != cmp;
2717 }
2718 
2719 template <typename F, typename T, typename E>
2720 [[nodiscard]] STX_FORCE_INLINE constexpr bool operator==(
2721  Err<F> const& cmp, Result<T, E> const& result) {
2722  return result == cmp;
2723 }
2724 
2725 template <typename F, typename T, typename E>
2726 [[nodiscard]] STX_FORCE_INLINE constexpr bool operator!=(
2727  Err<F> const& cmp, Result<T, E> const& result) {
2728  return result != cmp;
2729 }
2730 
2731 /********************* HELPER FUNCTIONS *********************/
2732 
2766 template <typename T>
2767 [[nodiscard]] STX_FORCE_INLINE constexpr auto make_some(T value) -> Option<T> {
2768  return Some<T>(std::forward<T>(value));
2769 }
2770 
2797 template <typename T>
2798 [[nodiscard]] STX_FORCE_INLINE constexpr auto make_none() noexcept
2799  -> Option<T> {
2800  return None;
2801 }
2802 
2834 template <typename T, typename E>
2835 [[nodiscard]] STX_FORCE_INLINE constexpr auto make_ok(T value) -> Result<T, E> {
2836  return Ok<T>(std::forward<T>(value));
2837 }
2838 
2869 template <typename T, typename E>
2870 [[nodiscard]] STX_FORCE_INLINE constexpr auto make_err(E err) -> Result<T, E> {
2871  return Err<E>(std::forward<E>(err));
2872 }
2873 
2894 template <typename T>
2895 STX_FORCE_INLINE auto some_ref(T& value) noexcept {
2896  return Some<Ref<T>>(std::forward<T&>(value));
2897 }
2898 
2919 template <typename T>
2920 STX_FORCE_INLINE auto ok_ref(T& value) noexcept {
2921  return Ok<Ref<T>>(std::forward<T&>(value));
2922 }
2923 
2944 template <typename E>
2945 STX_FORCE_INLINE auto err_ref(E& value) noexcept {
2946  return Err<Ref<E>>(std::forward<E&>(value));
2947 }
2948 
2950 
2951 // Error propagation macros
2952 #include "stx/internal/try.h"
STX_FORCE_INLINE void no_err(SourceLocation const &location=SourceLocation::current()) noexcept
panic helper for Result<T, E>::unwrap_err() when a value is present
Definition: panic_helpers.h:110
constexpr auto AND(Result< U, F > &&res) &&-> Result< U, F >
Definition: option_result.h:2302
E const & err_value() const &noexcept
Definition: option_result.h:2009
STX_FORCE_INLINE void no_value(SourceLocation const &location=SourceLocation::current()) noexcept
panic helper for Option<T>::unwrap() when no value is present
Definition: panic_helpers.h:57
auto unwrap() &&-> T
Definition: option_result.h:2479
constexpr auto OR(Result< U, F > &&alt) &&-> Result< U, F >
Definition: option_result.h:2371
std::reference_wrapper< std::remove_const_t< std::remove_reference_t< T > >> MutRef
MutRef is an always-mutable Ref
Definition: common.h:90
constexpr bool operator==(Ok< U > const &cmp) const
Definition: option_result.h:265
constexpr auto match(SomeFn &&some_fn, NoneFn &&none_fn) &&-> invoke_result< SomeFn &&, T &&>
Definition: option_result.h:1470
T & value() &noexcept
Definition: option_result.h:1937
constexpr T & value() &noexcept
Definition: option_result.h:183
constexpr bool is_none() const noexcept
Definition: option_result.h:602
auto expect(std::string_view const &msg) &&-> T
Definition: option_result.h:2501
Definition: option_result.h:98
constexpr auto and_then(Fn &&op) &&-> Result< invoke_result< Fn &&, T &&>, E >
Definition: option_result.h:2330
constexpr bool contains(CmpType const &cmp) const
Definition: option_result.h:1830
constexpr auto err() &&-> Option< E >
Definition: option_result.h:2060
STX_FORCE_INLINE void no_none(SourceLocation const &location=SourceLocation::current()) noexcept
panic helper for Option<T>::unwrap_none() when a value is present
Definition: panic_helpers.h:69
constexpr bool exists(UnaryPredicate &&predicate) const
Definition: option_result.h:1882
constexpr bool operator==(NoneType const &) const noexcept
Definition: option_result.h:565
constexpr bool operator!=(Ok< F > const &) const noexcept
Definition: option_result.h:367
auto expect_err(std::string_view const &msg) &&-> E
Definition: option_result.h:2552
auto unwrap_err() &&-> E
Definition: option_result.h:2527
constexpr auto OR(Option &&alt) &&-> Option
Definition: option_result.h:1180
constexpr auto unwrap_or_else(Fn &&op) &&-> T
Definition: option_result.h:868
STX_FORCE_INLINE constexpr bool operator!=(Err< F > const &cmp, Result< T, E > const &result)
Definition: option_result.h:2726
constexpr bool operator==(NoneType const &) const noexcept
Definition: option_result.h:199
constexpr auto map_or(Fn &&op, AltType &&alt) &&-> invoke_result< Fn &&, T &&>
Definition: option_result.h:2199
constexpr bool exists(UnaryPredicate &&predicate) const
Definition: option_result.h:647
T storage_value_
Definition: option_result.h:1510
constexpr auto AND(Option< U > &&cmp) &&-> Option< U >
Definition: option_result.h:1052
STX_FORCE_INLINE void no_lref(SourceLocation const &location=SourceLocation::current()) noexcept
panic helper for Option<T>::value() when no value is present
Definition: panic_helpers.h:63
constexpr bool operator!=(Some< U > const &cmp) const
Definition: option_result.h:194
constexpr auto ok() &&-> Option< T >
Definition: option_result.h:2036
std::reference_wrapper< std::add_const_t< std::remove_reference_t< T > >> ConstRef
ConstRef is an always-const Ref.
Definition: common.h:85
constexpr bool operator==(Err< F > const &cmp) const
Definition: option_result.h:350
constexpr bool operator==(Some< U > const &cmp) const
Definition: option_result.h:546
auto expect(std::string_view const &msg) &&-> T
Definition: option_result.h:793
constexpr T value() &&
Definition: option_result.h:185
E error_type
Definition: option_result.h:1659
constexpr auto unwrap_or_else(Fn &&op) &&-> T
Definition: option_result.h:2454
constexpr bool operator!=(Result< U, F > const &cmp) const
Definition: option_result.h:1765
constexpr E const value() const &&
Definition: option_result.h:373
constexpr bool operator==(Result< U, F > const &cmp) const
Definition: option_result.h:1751
constexpr auto map(Fn &&op) &&-> Result< invoke_result< Fn &&, T &&>, E >
Definition: option_result.h:2172
STX_FORCE_INLINE constexpr auto make_some(T value) -> Option< T >
Definition: option_result.h:2767
constexpr auto as_cref() const &noexcept -> Result< ConstRef< T >, ConstRef< E >>
Definition: option_result.h:2084
constexpr auto match(OkFn &&ok_fn, ErrFn &&err_fn) const &-> invoke_result< OkFn &&, T const &>
Definition: option_result.h:2646
constexpr auto as_ref() const &noexcept -> Option< ConstRef< T >>
Definition: option_result.h:756
constexpr bool is_ok() const noexcept
Definition: option_result.h:1792
T value_type
Definition: option_result.h:170
STX_FORCE_INLINE constexpr bool operator==(Err< F > const &cmp, Result< T, E > const &result)
Definition: option_result.h:2720
constexpr T const & value() const &noexcept
Definition: option_result.h:182
constexpr auto unwrap_or_default() &&-> T
Definition: option_result.h:2579
constexpr T & value() &noexcept
Definition: option_result.h:287
STX_FORCE_INLINE void expect_value_failed(std::string_view const &msg, SourceLocation const &location=SourceLocation::current()) noexcept
panic helper for Option<T>::expect() when no value is present
Definition: panic_helpers.h:43
void unwrap_none() &&
Definition: option_result.h:1408
constexpr bool operator!=(Err< F > const &cmp) const
Definition: option_result.h:1741
constexpr auto map_or_else(Fn &&op, AltFn &&alt) &&-> invoke_result< Fn &&, T &&>
Definition: option_result.h:956
constexpr bool operator==(Some< U > const &cmp) const
Definition: option_result.h:188
constexpr auto XOR(Option &&alt) &&-> Option
Definition: option_result.h:1239
constexpr E const & value() const &noexcept
Definition: option_result.h:371
constexpr bool operator!=(NoneType const &) const noexcept
Definition: option_result.h:569
constexpr auto match(SomeFn &&some_fn, NoneFn &&none_fn) &-> invoke_result< SomeFn &&, T &>
Definition: option_result.h:1483
constexpr bool operator!=(Err< F > const &cmp) const
Definition: option_result.h:356
constexpr bool operator==(Ok< F > const &) const noexcept
Definition: option_result.h:362
constexpr T value() &&
Definition: option_result.h:289
Tp && unsafe_value_move(Result< Tp, Er > &)
constexpr E value() &&
Definition: option_result.h:374
constexpr auto filter(UnaryPredicate &&predicate) &&-> Option
Definition: option_result.h:1108
Option & operator=(Option &&rhs)
Definition: option_result.h:472
#define STX_FORCE_INLINE
Definition: config.h:254
constexpr bool err_exists(UnaryPredicate &&predicate) const
Definition: option_result.h:1908
constexpr Option(Some< T > const &some)
Definition: option_result.h:456
Result(Result &&rhs)
Definition: option_result.h:1671
auto replace(T &&replacement) -> Option
Definition: option_result.h:1298
constexpr auto map_or(Fn &&op, A &&alt) &&-> invoke_result< Fn &&, T &&>
Definition: option_result.h:927
Definition: option_result.h:81
Definition: option_result.h:76
constexpr bool operator==(Option< U > const &cmp) const
Definition: option_result.h:522
constexpr auto unwrap_or(T &&alt) &&-> T
Definition: option_result.h:846
constexpr Some(T &&value)
a Some<T> can only be constructed with an r-value of type T
Definition: option_result.h:173
constexpr NoneType const None
value-variant for Option<T> representing no-value
Definition: option_result.h:127
Definition: option_result.h:90
constexpr auto map(Fn &&op) &&-> Option< invoke_result< Fn &&, T &&>>
Definition: option_result.h:900
constexpr auto ok_or_else(Fn &&op) &&-> Result< T, invoke_result< Fn &&>>
Definition: option_result.h:1015
Definition: option_result.h:84
void expect_none(std::string_view const &msg) &&
Definition: option_result.h:1382
constexpr bool operator!=(Some< U > const &cmp) const
Definition: option_result.h:556
STX_FORCE_INLINE auto ok_ref(T &value) noexcept
Definition: option_result.h:2920
constexpr bool operator==(Ok< U > const &cmp) const
Definition: option_result.h:1711
Definition: option_result.h:87
constexpr T const & value() const &noexcept
Definition: option_result.h:286
constexpr bool convertible
Definition: common.h:53
Option(Option &&rhs)
Definition: option_result.h:466
constexpr T const value() const &&
Definition: option_result.h:288
STX_FORCE_INLINE constexpr auto make_err(E err) -> Result< T, E >
Definition: option_result.h:2870
Option(Option const &rhs)
Definition: option_result.h:492
#define STX_CXX20_DESTRUCTOR_CONSTEXPR
Definition: config.h:231
E value_type
Definition: option_result.h:337
STX_FORCE_INLINE constexpr auto make_none() noexcept -> Option< T >
Definition: option_result.h:2798
T storage_value_
Definition: option_result.h:2682
constexpr auto take() -> Option
Definition: option_result.h:1267
constexpr bool operator==(NoneType const &) const noexcept
Definition: option_result.h:107
constexpr Ok(T &&value)
an Ok<T> can only be constructed with an r-value of type T
Definition: option_result.h:255
STX_FORCE_INLINE void expect_err_failed(std::string_view const &msg, SourceLocation const &location=SourceLocation::current()) noexcept
panic helper for Result<T, E>::expect_err() when a value is present
Definition: panic_helpers.h:87
constexpr auto and_then(Fn &&op) &&-> invoke_result< Fn &&, T &&>
Definition: option_result.h:1079
constexpr auto clone() const -> Option
Definition: option_result.h:1353
constexpr bool operator==(Err< U > const &) const noexcept
Definition: option_result.h:277
constexpr auto unwrap_or_default() &&-> T
Definition: option_result.h:1432
STX_FORCE_INLINE auto some_ref(T &value) noexcept
Definition: option_result.h:2895
constexpr Option(Some< T > &&some)
Definition: option_result.h:453
uintptr_t value_type
Definition: option_result.h:441
STX_CXX20_DESTRUCTOR_CONSTEXPR ~Result() noexcept
Definition: option_result.h:1702
constexpr bool operator!=(Some< T > const &) const noexcept
Definition: option_result.h:121
Er && unsafe_err_move(Result< Tp, Er > &)
STX_FORCE_INLINE void no_err_lref(SourceLocation const &location=SourceLocation::current()) noexcept
panic helper for Result<T, E>::err_value() when no value is present
Definition: panic_helpers.h:116
STX_FORCE_INLINE void expect_none_failed(std::string_view const &msg, SourceLocation const &location=SourceLocation::current()) noexcept
panic helper for Option<T>::expect_none() when a value is present
Definition: panic_helpers.h:50
constexpr Option() noexcept
Definition: option_result.h:451
T const & value() const &noexcept
Definition: option_result.h:1959
constexpr auto clone() const -> Result< T, E >
Definition: option_result.h:2669
constexpr auto filter_not(UnaryPredicate &&predicate) &&-> Option
Definition: option_result.h:1139
typename std::invoke_result_t< Fn, Args... > invoke_result
Definition: common.h:40
#define STX_END_NAMESPACE
Definition: config.h:329
constexpr bool operator!=(Err< U > const &) const noexcept
Definition: option_result.h:282
STX_FORCE_INLINE constexpr auto make_ok(T value) -> Result< T, E >
Definition: option_result.h:2835
STX_CXX20_DESTRUCTOR_CONSTEXPR ~Option() noexcept
Definition: option_result.h:515
constexpr bool operator==(Some< T > const &) const noexcept
Definition: option_result.h:116
constexpr auto as_ref() const &noexcept -> Result< ConstRef< T >, ConstRef< E >>
Definition: option_result.h:2129
T const & value() const &noexcept
Definition: option_result.h:698
constexpr auto as_ref() &noexcept -> Option< MutRef< T >>
Definition: option_result.h:748
constexpr T const value() const &&
Definition: option_result.h:184
T value_type
Definition: option_result.h:1658
T value_type
Definition: option_result.h:252
constexpr Result(Err< E > &&err)
Definition: option_result.h:1664
constexpr Err(E &&value)
an Err<E> can only be constructed with an r-value of type E
Definition: option_result.h:340
constexpr auto as_ref() &noexcept -> Result< MutRef< T >, MutRef< E >>
Definition: option_result.h:2120
constexpr bool operator!=(NoneType const &) const noexcept
Definition: option_result.h:203
constexpr Result(Ok< T > &&result)
Definition: option_result.h:1661
constexpr bool operator!=(Option< U > const &cmp) const
Definition: option_result.h:534
STX_FORCE_INLINE auto err_ref(E &value) noexcept
Definition: option_result.h:2945
constexpr bool contains(CmpType const &cmp) const
Definition: option_result.h:624
auto replace(T const &replacement) -> Option
Definition: option_result.h:1329
constexpr auto match(OkFn &&ok_fn, ErrFn &&err_fn) &-> invoke_result< OkFn &&, T &>
Definition: option_result.h:2633
constexpr auto match(OkFn &&ok_fn, ErrFn &&err_fn) &&-> invoke_result< OkFn &&, T &&>
Definition: option_result.h:2620
E storage_err_
Definition: option_result.h:2683
constexpr auto map_err(Fn &&op) &&-> Result< T, invoke_result< Fn &&, E &&>>
Definition: option_result.h:2265
T & value() &noexcept
Definition: option_result.h:676
constexpr E & value() &noexcept
Definition: option_result.h:372
constexpr bool operator!=(Ok< U > const &cmp) const
Definition: option_result.h:1721
#define STX_BEGIN_NAMESPACE
Definition: config.h:325
constexpr bool is_err() const noexcept
Definition: option_result.h:1807
constexpr auto as_cref() const &noexcept -> Option< ConstRef< T >>
Definition: option_result.h:714
constexpr auto match(SomeFn &&some_fn, NoneFn &&none_fn) const &-> invoke_result< SomeFn &&, T const &>
Definition: option_result.h:1496
auto unwrap() &&-> T
Definition: option_result.h:823
constexpr bool is_some() const noexcept
Definition: option_result.h:587
constexpr bool operator!=(Ok< U > const &cmp) const
Definition: option_result.h:271
E & err_value() &noexcept
Definition: option_result.h:1987
constexpr Option(NoneType const &) noexcept
Definition: option_result.h:461
constexpr auto or_else(Fn &&op) &&-> Option
Definition: option_result.h:1205
Result & operator=(Result &&rhs)
Definition: option_result.h:1679
constexpr bool operator==(Err< F > const &cmp) const
Definition: option_result.h:1731
constexpr auto ok_or(E error) &&-> Result< T, E >
Definition: option_result.h:988
constexpr bool operator!=(NoneType const &) const noexcept
Definition: option_result.h:111
constexpr auto map_or_else(Fn &&op, A &&alt_op) &&-> invoke_result< Fn &&, T &&>
Definition: option_result.h:2232
constexpr bool contains_err(ErrCmp const &cmp) const
Definition: option_result.h:1858
Option & operator=(Option const &rhs)
Definition: option_result.h:499
constexpr auto unwrap_or(T &&alt) &&-> T
Definition: option_result.h:2430
constexpr auto or_else(Fn &&op) &&-> invoke_result< Fn &&, E &&>
Definition: option_result.h:2401