LeechCraft 0.6.70-17609-g3dde4097dd
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 T>
21 struct Left
22 {
24 };
25
26 template<>
27 struct Left<void> {};
28
29 constexpr auto AsLeft = Left<void> {};
30
31 template<typename L, typename R>
32 class Either
33 {
34 using Either_t = std::variant<L, R>;
35 Either_t This_;
36
37 enum { LeftVal, RightVal };
38
39 static_assert (!std::is_same<L, R>::value, "Types cannot be the same.");
40 public:
41 using L_t = L;
42 using R_t = R;
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_ { l }
58 {
59 }
60
61 explicit Either (const L& l)
62 : This_ { l }
63 {
64 }
65
66 Either (Left<L>&& left)
67 : This_ { std::move (left.Value_) }
68 {
69 }
70
71 template<typename LL>
72 requires std::is_constructible_v<L, LL&&>
74 : This_ { 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 This_.index () == LeftVal;
86 }
87
88 bool IsRight () const
89 {
90 return This_.index () == RightVal;
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 std::get<L> (This_);
98 }
99
100 const R& GetRight () const
101 {
102 if (!IsRight ())
103 throw std::runtime_error { "Tried accessing Right for a Left Either" };
104 return std::get<R> (This_);
105 }
106
107 std::optional<L> MaybeLeft () const
108 {
109 if (!IsLeft ())
110 return {};
111 return GetLeft ();
112 }
113
114 std::optional<R> MaybeRight () const
115 {
116 if (!IsRight ())
117 return {};
118 return GetRight ();
119 }
120
121 std::variant<L, R> AsVariant () const &
122 {
123 return This_;
124 }
125
126 std::variant<L, R> AsVariant () &&
127 {
128 return std::move (This_);
129 }
130
131 template<typename F>
132 R ToRight (F&& f) const
133 {
134 return IsRight () ?
135 GetRight () :
136 f (GetLeft ());
137 }
138
139 template<typename F>
140 auto MapLeft (F&& f) const
141 {
142 using Result = Either<std::invoke_result_t<F, L>, R>;
143 return IsRight () ? Result { GetRight () } : Result { AsLeft, std::forward<F> (f) (GetLeft ()) };
144 }
145
146 template<typename F>
147 auto MapRight (F&& f) const
148 {
150 return IsRight () ? Result { std::forward<F> (f) (GetRight ()) } : Result { AsLeft, GetLeft () };
151 }
152
153 // TODO remove this method
154 static auto EmbeddingLeft ()
155 {
156 return []<typename LL, typename RR> (const Either<LL, RR>& other)
157 {
158 static_assert (std::is_convertible_v<LL, L>,
159 "Other's Either's Left type is not convertible to this Left type.");
160 return other.IsLeft () ?
161 Either { AsLeft, other.GetLeft () }:
162 Either { other.GetRight () };
163 };
164 }
165
166 friend bool operator== (const Either& e1, const Either& e2)
167 {
168 return e1.This_ == e2.This_;
169 }
170
171 friend bool operator!= (const Either& e1, const Either& e2)
172 {
173 return !(e1 == e2);
174 }
175 };
176
177 template<typename L, typename R, typename F, typename = std::invoke_result_t<F>>
178 R RightOr (const Either<L, R>& either, F&& f)
179 {
180 return either.IsRight () ?
181 either.GetRight () :
182 f ();
183 }
184
185 template<typename L, typename R>
186 R RightOr (const Either<L, R>& either, const R& r)
187 {
188 return either.IsRight () ?
189 either.GetRight () :
190 r;
191 }
192
193 template<template<typename> class Cont, typename L, typename R>
194 std::pair<Cont<L>, Cont<R>> Partition (const Cont<Either<L, R>>& eithers)
195 {
196 std::pair<Cont<L>, Cont<R>> result;
197 for (const auto& either : eithers)
198 if (either.IsLeft ())
199 result.first.push_back (either.GetLeft ());
200 else
201 result.second.push_back (either.GetRight ());
202
203 return result;
204 }
205
206 template<typename Left, typename Right, typename... Args>
207 auto Visit (const Either<Left, Right>& either, Args&&... args)
208 {
209 return Visit (either.AsVariant (), std::forward<Args> (args)...);
210 }
211
212 template<typename Left, typename Right, typename... Args>
213 auto Visit (Either<Left, Right>&& either, Args&&... args)
214 {
215 return Visit (std::move (either).AsVariant (), std::forward<Args> (args)...);
216 }
217}
218}
Either(Left< L > &&left)
Definition either.h:66
friend bool operator!=(const Either &e1, const Either &e2)
Definition either.h:171
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:107
std::variant< L, R > AsVariant() const &
Definition either.h:121
static auto EmbeddingLeft()
Definition either.h:154
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:114
bool IsRight() const
Definition either.h:88
R ToRight(F &&f) const
Definition either.h:132
Either(Left< LL > &&left)
Definition either.h:73
friend bool operator==(const Either &e1, const Either &e2)
Definition either.h:166
auto MapLeft(F &&f) const
Definition either.h:140
bool IsLeft() const
Definition either.h:83
auto MapRight(F &&f) const
Definition either.h:147
const R & GetRight() const
Definition either.h:100
Either(R &&r)
Definition either.h:46
Either(const Either &)=default
std::variant< L, R > AsVariant() &&
Definition either.h:126
constexpr auto AsLeft
Definition either.h:29
auto Visit(const Either< Left, Right > &either, Args &&... args)
Definition either.h:207
std::pair< Cont< L >, Cont< R > > Partition(const Cont< Either< L, R > > &eithers)
Definition either.h:194
R RightOr(const Either< L, R > &either, F &&f)
Definition either.h:178
Definition constants.h:15