LeechCraft 0.6.70-16373-g319c272718
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 <variant>
12#include <optional>
13#include <type_traits>
14#include "visitor.h"
15
16namespace LC
17{
18namespace Util
19{
20 template<typename L, typename R>
21 class Either
22 {
23 using Either_t = std::variant<L, R>;
24 Either_t This_;
25
26 enum { LeftVal, RightVal };
27
28 static_assert (!std::is_same<L, R>::value, "Types cannot be the same.");
29 public:
30 using L_t = L;
31 using R_t = R;
32
33 Either () = delete;
34
35 explicit Either (const L& l)
36 : This_ { l }
37 {
38 }
39
40 explicit Either (R&& r)
41 : This_ { std::move (r) }
42 {
43 }
44
45 explicit Either (const R& r)
46 : This_ { r }
47 {
48 }
49
50 Either (const Either&) = default;
51 Either (Either&&) = default;
52 Either& operator= (const Either&) = default;
53 Either& operator= (Either&&) = default;
54
55 bool IsLeft () const
56 {
57 return This_.index () == LeftVal;
58 }
59
60 bool IsRight () const
61 {
62 return This_.index () == RightVal;
63 }
64
65 const L& GetLeft () const
66 {
67 if (!IsLeft ())
68 throw std::runtime_error { "Tried accessing Left for a Right Either" };
69 return std::get<L> (This_);
70 }
71
72 const R& GetRight () const
73 {
74 if (!IsRight ())
75 throw std::runtime_error { "Tried accessing Right for a Left Either" };
76 return std::get<R> (This_);
77 }
78
79 std::optional<L> MaybeLeft () const
80 {
81 if (!IsLeft ())
82 return {};
83 return GetLeft ();
84 }
85
86 std::optional<R> MaybeRight () const
87 {
88 if (!IsRight ())
89 return {};
90 return GetRight ();
91 }
92
93 std::variant<L, R> AsVariant () const &
94 {
95 return This_;
96 }
97
98 std::variant<L, R> AsVariant () &&
99 {
100 return std::move (This_);
101 }
102
103 template<typename F>
104 R ToRight (F&& f) const
105 {
106 return IsRight () ?
107 GetRight () :
108 f (GetLeft ());
109 }
110
111 template<typename RNew>
112 static Either<L, RNew> FromMaybe (const std::optional<RNew>& maybeRight, const L& left)
113 {
114 return maybeRight ?
117 }
118
119 static Either Left (const L& l)
120 {
121 return Either { l };
122 }
123
124 static Either Right (R&& r)
125 {
126 return Either { std::move (r) };
127 }
128
129 static Either Right (const R& r)
130 {
131 return Either { r };
132 }
133
134 template<typename... Vars>
135 static Either LeftLift (const std::variant<Vars...>& var)
136 {
137 return Either { std::visit ([] (auto&& arg) { return L { std::forward<decltype (arg)> (arg) }; }, var) };
138 }
139
140 template<typename... Vars>
141 static Either LeftLift (const Either<std::variant<Vars...>, R>& either)
142 {
143 return either.IsRight () ?
144 Right (either.GetRight ()) :
145 LeftLift (either.GetLeft ());
146 }
147
148 template<typename LPrime, typename = std::enable_if_t<std::is_convertible_v<LPrime, L>>>
150 {
151 return either.IsRight () ?
152 Right (either.GetRight ()) :
153 Left (either.GetLeft ());
154 }
155
156 template<typename RNew>
157 static std::enable_if_t<!std::is_convertible<RNew, R>::value, Either<L, RNew>> Right (const RNew& r)
158 {
159 return Either<L, RNew>::Right (r);
160 }
161
162 static auto EmbeddingLeft ()
163 {
164 return [] (const auto& other)
165 {
166 static_assert (std::is_convertible<std::decay_t<decltype (other.GetLeft ())>, L>::value,
167 "Other's Either's Left type is not convertible to this Left type.");
168 return other.IsLeft () ?
169 Either<L, R>::Left (other.GetLeft ()) :
170 Either<L, R>::Right (other.GetRight ());
171 };
172 }
173
174 friend bool operator== (const Either& e1, const Either& e2)
175 {
176 return e1.This_ == e2.This_;
177 }
178
179 friend bool operator!= (const Either& e1, const Either& e2)
180 {
181 return !(e1 == e2);
182 }
183 };
184
185 template<typename L, typename R, typename F, typename = std::result_of_t<F ()>>
187 {
188 return either.IsRight () ?
189 either.GetRight () :
190 f ();
191 }
192
193 template<typename L, typename R>
194 R RightOr (const Either<L, R>& either, const R& r)
195 {
196 return either.IsRight () ?
197 either.GetRight () :
198 r;
199 }
200
201 template<template<typename> class Cont, typename L, typename R>
202 std::pair<Cont<L>, Cont<R>> PartitionEithers (const Cont<Either<L, R>>& eithers)
203 {
204 std::pair<Cont<L>, Cont<R>> result;
205 for (const auto& either : eithers)
206 if (either.IsLeft ())
207 result.first.push_back (either.GetLeft ());
208 else
209 result.second.push_back (either.GetRight ());
210
211 return result;
212 }
213
214 template<typename Left, typename Right, typename... Args>
216 {
217 return Visit (either.AsVariant (), std::forward<Args> (args)...);
218 }
219
220 template<typename Left, typename Right, typename... Args>
222 {
223 return Visit (std::move (either).AsVariant (), std::forward<Args> (args)...);
224 }
225}
226}
friend bool operator!=(const Either &e1, const Either &e2)
Definition either.h:179
static Either Right(const R &r)
Definition either.h:129
Either(const L &l)
Definition either.h:35
Either(Either &&)=default
std::optional< L > MaybeLeft() const
Definition either.h:79
std::variant< L, R > AsVariant() const &
Definition either.h:93
static auto EmbeddingLeft()
Definition either.h:162
static Either Left(const L &l)
Definition either.h:119
Either & operator=(const Either &)=default
Either(const R &r)
Definition either.h:45
static Either LeftLift(const Either< std::variant< Vars... >, R > &either)
Definition either.h:141
static std::enable_if_t<!std::is_convertible< RNew, R >::value, Either< L, RNew > > Right(const RNew &r)
Definition either.h:157
static Either Right(R &&r)
Definition either.h:124
const L & GetLeft() const
Definition either.h:65
std::optional< R > MaybeRight() const
Definition either.h:86
static Either LeftLift(const std::variant< Vars... > &var)
Definition either.h:135
bool IsRight() const
Definition either.h:60
R ToRight(F &&f) const
Definition either.h:104
friend bool operator==(const Either &e1, const Either &e2)
Definition either.h:174
static Either LeftLift(const Either< LPrime, R > &either)
Definition either.h:149
static Either< L, RNew > FromMaybe(const std::optional< RNew > &maybeRight, const L &left)
Definition either.h:112
bool IsLeft() const
Definition either.h:55
const R & GetRight() const
Definition either.h:72
Either(R &&r)
Definition either.h:40
Either(const Either &)=default
std::variant< L, R > AsVariant() &&
Definition either.h:98
Container< T > Filter(const Container< T > &c, F f)
Definition prelude.h:118
auto Visit(const Either< Left, Right > &either, Args &&... args)
Definition either.h:215
std::pair< Cont< L >, Cont< R > > PartitionEithers(const Cont< Either< L, R > > &eithers)
Definition either.h:202
R RightOr(const Either< L, R > &either, F &&f)
Definition either.h:186
Definition constants.h:15
STL namespace.