LeechCraft 0.6.70-18808-g3467692359
Modular cross-platform feature rich live environment.
Loading...
Searching...
No Matches
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 <variant>
15#include "overloaded.h"
16
17namespace LC::Util
18{
19 template<typename T>
20 struct Left
21 {
23 };
24
25 template<>
26 struct Left<void> {};
27
28 constexpr auto AsLeft = Left<void> {};
29
31
32 template<typename L, typename R>
33 class Either
34 {
35 std::expected<R, L> This_;
36 public:
37 using L_t = L;
38 using R_t = R;
39
40 Either (FromStdExpected_t, std::expected<R, L>&& ex)
41 : This_ { std::move (ex) }
42 {
43 }
44
45 Either () = delete;
46
47 Either (R&& r)
48 : This_ { std::move (r) }
49 {
50 }
51
52 Either (const R& r)
53 : This_ { r }
54 {
55 }
56
57 Either (Left<void>, const L& l)
58 : This_ { std::unexpect, l }
59 {
60 }
61
62 explicit Either (const L& l) requires (!std::is_same_v<L, R>)
63 : This_ { std::unexpect, l }
64 {
65 }
66
67 Either (Left<L>&& left)
68 : This_ { std::unexpect, std::move (left.Value_) }
69 {
70 }
71
72 template<typename LL>
73 requires std::is_constructible_v<L, LL&&>
75 : This_ { std::unexpect, L { std::move (left.Value_) } }
76 {
77 }
78
79 Either (const Either&) = default;
80 Either (Either&&) = default;
81 Either& operator= (const Either&) = default;
82 Either& operator= (Either&&) = default;
83
84 bool IsLeft () const
85 {
86 return !IsRight ();
87 }
88
89 bool IsRight () const
90 {
91 return This_.has_value ();
92 }
93
94 const L& GetLeft () const
95 {
96 if (!IsLeft ())
97 throw std::runtime_error { "Tried accessing Left for a Right Either" };
98 return This_.error ();
99 }
100
102 {
103 if (!IsLeft ())
104 throw std::runtime_error { "Tried accessing Left for a Right Either" };
105 return This_.error ();
106 }
107
108 const R& GetRight () const
109 {
110 if (!IsRight ())
111 throw std::runtime_error { "Tried accessing Right for a Left Either" };
112 return This_.value ();
113 }
114
116 {
117 if (!IsRight ())
118 throw std::runtime_error { "Tried accessing Right for a Left Either" };
119 return This_.value ();
120 }
121
122 std::optional<L> MaybeLeft () const
123 {
124 if (!IsLeft ())
125 return {};
126 return GetLeft ();
127 }
128
129 std::optional<R> MaybeRight () const
130 {
131 if (!IsRight ())
132 return {};
133 return GetRight ();
134 }
135
136 template<typename F>
137 R ToRight (F&& f) const
138 {
139 return IsRight () ? GetRight () : std::forward<F> (f) (GetLeft ());
140 }
141
142 template<typename F>
143 auto MapLeft (F&& f) const
144 {
145 using Result = Either<std::invoke_result_t<F, L>, R>;
146 return Result { FromStdExpected, This_.transform_error (std::forward<F> (f)) };
147 }
148
149 template<typename F>
150 auto MapRight (F&& f) const
151 {
153 return Result { This_.transform (std::forward<F> (f)) };
154 }
155
156 friend bool operator== (const Either& e1, const Either& e2)
157 {
158 return e1.This_ == e2.This_;
159 }
160
161 friend bool operator!= (const Either& e1, const Either& e2)
162 {
163 return !(e1 == e2);
164 }
165 };
166
167 template<typename L, typename R>
168 Either<L, R> EitherFromSwapped (const std::variant<R, L>& variant)
169 {
170 if (variant.index () == 0)
171 return std::get<0> (variant);
172 return Left<L> { std::get<1> (variant) };
173 }
174
175 template<template<typename> class Cont, typename L, typename R>
176 std::pair<Cont<L>, Cont<R>> Partition (const Cont<Either<L, R>>& eithers)
177 {
178 std::pair<Cont<L>, Cont<R>> result;
179 for (const auto& either : eithers)
180 if (either.IsLeft ())
181 result.first.push_back (either.GetLeft ());
182 else
183 result.second.push_back (either.GetRight ());
184
185 return result;
186 }
187
188 template<typename Left, typename Right, typename... Args>
189 auto Visit (const Either<Left, Right>& either, Args&&... args)
190 {
191 Overloaded visitor { std::forward<Args> (args)... };
192 return either.IsRight () ?
193 std::move (visitor) (either.GetRight ()) :
194 std::move (visitor) (either.GetLeft ());
195 }
196
197 template<typename Left, typename Right, typename... Args>
198 auto Visit (Either<Left, Right>&& either, Args&&... args)
199 {
200 Overloaded visitor { std::forward<Args> (args)... };
201 return either.IsRight () ?
202 std::move (visitor) (std::move (either.GetRight ())) :
203 std::move (visitor) (std::move (either.GetLeft ()));
204 }
205}
Either(Left< L > &&left)
Definition either.h:67
friend bool operator!=(const Either &e1, const Either &e2)
Definition either.h:161
Either(Left< void >, const L &l)
Definition either.h:57
Either(const L &l)
Definition either.h:62
Either(Either &&)=default
std::optional< L > MaybeLeft() const
Definition either.h:122
Either(FromStdExpected_t, std::expected< R, L > &&ex)
Definition either.h:40
Either & operator=(const Either &)=default
Either(const R &r)
Definition either.h:52
const L & GetLeft() const
Definition either.h:94
std::optional< R > MaybeRight() const
Definition either.h:129
bool IsRight() const
Definition either.h:89
R ToRight(F &&f) const
Definition either.h:137
Either(Left< LL > &&left)
Definition either.h:74
friend bool operator==(const Either &e1, const Either &e2)
Definition either.h:156
auto MapLeft(F &&f) const
Definition either.h:143
bool IsLeft() const
Definition either.h:84
auto MapRight(F &&f) const
Definition either.h:150
const R & GetRight() const
Definition either.h:108
Either(R &&r)
Definition either.h:47
Either(const Either &)=default
constexpr auto AsLeft
Definition either.h:28
struct LC::Util::FromStdExpected_t FromStdExpected
Either< L, R > EitherFromSwapped(const std::variant< R, L > &variant)
Definition either.h:168
auto Visit(const Either< Left, Right > &either, Args &&... args)
Definition either.h:189
std::pair< Cont< L >, Cont< R > > Partition(const Cont< Either< L, R > > &eithers)
Definition either.h:176