LeechCraft 0.6.70-18450-gabe19ee3b0
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 "overloaded.h"
15
16namespace LC::Util
17{
18 template<typename T>
19 struct Left
20 {
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&&>
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
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
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 {
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}
Either(Left< L > &&left)
Definition either.h:66
Either(Left< LL > &&left)
Definition either.h:73
friend bool operator!=(const Either &e1, const Either &e2)
Definition either.h:160
Either(Left< void >, const L &l)
Definition either.h:56
Either(const L &l)
Definition either.h:61
Either(Either &&)=default
std::optional< L > MaybeLeft() const
Definition either.h:121
Either(FromStdExpected_t, std::expected< R, L > &&ex)
Definition either.h:39
Either & operator=(const Either &)=default
Either(const R &r)
Definition either.h:51
const L & GetLeft() const
Definition either.h:93
std::optional< R > MaybeRight() const
Definition either.h:128
bool IsRight() const
Definition either.h:88
R ToRight(F &&f) const
Definition either.h:136
friend bool operator==(const Either &e1, const Either &e2)
Definition either.h:155
auto MapLeft(F &&f) const
Definition either.h:142
bool IsLeft() const
Definition either.h:83
auto MapRight(F &&f) const
Definition either.h:149
const R & GetRight() const
Definition either.h:107
Either(R &&r)
Definition either.h:46
Either(const Either &)=default
constexpr auto AsLeft
Definition either.h:27
struct LC::Util::FromStdExpected_t FromStdExpected
auto Visit(const Either< Left, Right > &either, Args &&... args)
Definition either.h:180
std::pair< Cont< L >, Cont< R > > Partition(const Cont< Either< L, R > > &eithers)
Definition either.h:167