LeechCraft  0.6.70-18450-gabe19ee3b0
Modular cross-platform feature rich live environment.
either.h
Go to the documentation of this file.
1 /**********************************************************************
2  * LeechCraft - modular cross-platform feature rich internet client.
3  * Copyright (C) 2006-2014 Georg Rudoy
4  *
5  * Distributed under the Boost Software License, Version 1.0.
6  * (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt)
7  **********************************************************************/
8 
9 #pragma once
10 
11 #include <expected>
12 #include <optional>
13 #include <type_traits>
14 #include "overloaded.h"
15 
16 namespace LC::Util
17 {
18  template<typename T>
19  struct Left
20  {
21  T Value_;
22  };
23 
24  template<>
25  struct Left<void> {};
26 
27  constexpr auto AsLeft = Left<void> {};
28 
30 
31  template<typename L, typename R>
32  class Either
33  {
34  std::expected<R, L> This_;
35  public:
36  using L_t = L;
37  using R_t = R;
38 
39  Either (FromStdExpected_t, std::expected<R, L>&& ex)
40  : This_ { std::move (ex) }
41  {
42  }
43 
44  Either () = delete;
45 
46  Either (R&& r)
47  : This_ { std::move (r) }
48  {
49  }
50 
51  Either (const R& r)
52  : This_ { r }
53  {
54  }
55 
56  Either (Left<void>, const L& l)
57  : This_ { std::unexpect, l }
58  {
59  }
60 
61  explicit Either (const L& l) requires (!std::is_same_v<L, R>)
62  : This_ { std::unexpect, l }
63  {
64  }
65 
66  Either (Left<L>&& left)
67  : This_ { std::unexpect, std::move (left.Value_) }
68  {
69  }
70 
71  template<typename LL>
72  requires std::is_constructible_v<L, LL&&>
73  Either (Left<LL>&& left)
74  : This_ { std::unexpect, L { std::move (left.Value_) } }
75  {
76  }
77 
78  Either (const Either&) = default;
79  Either (Either&&) = default;
80  Either& operator= (const Either&) = default;
81  Either& operator= (Either&&) = default;
82 
83  bool IsLeft () const
84  {
85  return !IsRight ();
86  }
87 
88  bool IsRight () const
89  {
90  return This_.has_value ();
91  }
92 
93  const L& GetLeft () const
94  {
95  if (!IsLeft ())
96  throw std::runtime_error { "Tried accessing Left for a Right Either" };
97  return This_.error ();
98  }
99 
100  L& GetLeft ()
101  {
102  if (!IsLeft ())
103  throw std::runtime_error { "Tried accessing Left for a Right Either" };
104  return This_.error ();
105  }
106 
107  const R& GetRight () const
108  {
109  if (!IsRight ())
110  throw std::runtime_error { "Tried accessing Right for a Left Either" };
111  return This_.value ();
112  }
113 
114  R& GetRight ()
115  {
116  if (!IsRight ())
117  throw std::runtime_error { "Tried accessing Right for a Left Either" };
118  return This_.value ();
119  }
120 
121  std::optional<L> MaybeLeft () const
122  {
123  if (!IsLeft ())
124  return {};
125  return GetLeft ();
126  }
127 
128  std::optional<R> MaybeRight () const
129  {
130  if (!IsRight ())
131  return {};
132  return GetRight ();
133  }
134 
135  template<typename F>
136  R ToRight (F&& f) const
137  {
138  return IsRight () ? GetRight () : std::forward<F> (f) (GetLeft ());
139  }
140 
141  template<typename F>
142  auto MapLeft (F&& f) const
143  {
144  using Result = Either<std::invoke_result_t<F, L>, R>;
145  return Result { FromStdExpected, This_.transform_error (std::forward<F> (f)) };
146  }
147 
148  template<typename F>
149  auto MapRight (F&& f) const
150  {
151  using Result = Either<L, std::invoke_result_t<F, R>>;
152  return Result { This_.transform (std::forward<F> (f)) };
153  }
154 
155  friend bool operator== (const Either& e1, const Either& e2)
156  {
157  return e1.This_ == e2.This_;
158  }
159 
160  friend bool operator!= (const Either& e1, const Either& e2)
161  {
162  return !(e1 == e2);
163  }
164  };
165 
166  template<template<typename> class Cont, typename L, typename R>
167  std::pair<Cont<L>, Cont<R>> Partition (const Cont<Either<L, R>>& eithers)
168  {
169  std::pair<Cont<L>, Cont<R>> result;
170  for (const auto& either : eithers)
171  if (either.IsLeft ())
172  result.first.push_back (either.GetLeft ());
173  else
174  result.second.push_back (either.GetRight ());
175 
176  return result;
177  }
178 
179  template<typename Left, typename Right, typename... Args>
180  auto Visit (const Either<Left, Right>& either, Args&&... args)
181  {
182  Overloaded visitor { std::forward<Args> (args)... };
183  return either.IsRight () ?
184  std::move (visitor) (either.GetRight ()) :
185  std::move (visitor) (either.GetLeft ());
186  }
187 
188  template<typename Left, typename Right, typename... Args>
189  auto Visit (Either<Left, Right>&& either, Args&&... args)
190  {
191  Overloaded visitor { std::forward<Args> (args)... };
192  return either.IsRight () ?
193  std::move (visitor) (std::move (either.GetRight ())) :
194  std::move (visitor) (std::move (either.GetLeft ()));
195  }
196 }
struct LC::Util::FromStdExpected_t FromStdExpected
R ToRight(F &&f) const
Definition: either.h:136
Either(Left< void >, const L &l)
Definition: either.h:56
Either(Left< L > &&left)
Definition: either.h:66
bool IsRight() const
Definition: either.h:88
auto MapLeft(F &&f) const
Definition: either.h:142
auto Visit(const Either< Left, Right > &either, Args &&... args)
Definition: either.h:180
constexpr detail::ExprTree< detail::ExprType::LeafStaticPlaceholder, detail::MemberPtrs< Ptr > > f
Definition: oral.h:1083
const L & GetLeft() const
Definition: either.h:93
const R & GetRight() const
Definition: either.h:107
auto MapRight(F &&f) const
Definition: either.h:149
Either(R &&r)
Definition: either.h:46
Either & operator=(const Either &)=default
requires(Tup1Size==Tup2Size) const expr auto ZipWith(Tup1 &&tup1
constexpr auto AsLeft
Definition: either.h:27
Either(const L &l) requires(!std
Definition: either.h:61
friend bool operator!=(const Either &e1, const Either &e2)
Definition: either.h:160
bool IsLeft() const
Definition: either.h:83
requires std::is_constructible_v< L, LL && > Either(Left< LL > &&left)
Definition: either.h:73
L & GetLeft()
Definition: either.h:100
std::optional< L > MaybeLeft() const
Definition: either.h:121
Either(FromStdExpected_t, std::expected< R, L > &&ex)
Definition: either.h:39
std::optional< R > MaybeRight() const
Definition: either.h:128
std::pair< Cont< L >, Cont< R > > Partition(const Cont< Either< L, R >> &eithers)
Definition: either.h:167
friend bool operator==(const Either &e1, const Either &e2)
Definition: either.h:155
R & GetRight()
Definition: either.h:114
Either(const R &r)
Definition: either.h:51