LeechCraft 0.6.70-17335-ge406ffdcaf
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 F>
112 auto MapLeft (F&& f) const
113 {
114 using Result = Either<std::invoke_result_t<F, L>, R>;
115 return IsRight () ? Result::Right (GetRight ()) : Result::Left (std::forward<F> (f) (GetLeft ()));
116 }
117
118 template<typename F>
119 auto MapRight (F&& f) const
120 {
122 return IsRight () ? Result::Right (std::forward<F> (f) (GetRight ())) : Result::Left (GetLeft ());
123 }
124
125 template<typename LL = L>
126 static Either Left (const LL& l)
127 {
128 if constexpr (std::is_same_v<std::decay_t<LL>, std::decay_t<L>>)
129 return Either { l };
130 else
131 return Either { L { l } };
132 }
133
134 static Either Right (R&& r)
135 {
136 return Either { std::move (r) };
137 }
138
139 static Either Right (const R& r)
140 {
141 return Either { r };
142 }
143
144 template<typename RNew>
145 requires (!std::is_convertible_v<RNew, R>)
146 static auto Right (const RNew& r)
147 {
148 return Either<L, RNew>::Right (r);
149 }
150
151 static auto EmbeddingLeft ()
152 {
153 return [] (const auto& other)
154 {
155 static_assert (std::is_convertible<std::decay_t<decltype (other.GetLeft ())>, L>::value,
156 "Other's Either's Left type is not convertible to this Left type.");
157 return other.IsLeft () ?
158 Either<L, R>::Left (other.GetLeft ()) :
159 Either<L, R>::Right (other.GetRight ());
160 };
161 }
162
163 friend bool operator== (const Either& e1, const Either& e2)
164 {
165 return e1.This_ == e2.This_;
166 }
167
168 friend bool operator!= (const Either& e1, const Either& e2)
169 {
170 return !(e1 == e2);
171 }
172 };
173
174 template<typename L, typename R, typename F, typename = std::invoke_result_t<F>>
175 R RightOr (const Either<L, R>& either, F&& f)
176 {
177 return either.IsRight () ?
178 either.GetRight () :
179 f ();
180 }
181
182 template<typename L, typename R>
183 R RightOr (const Either<L, R>& either, const R& r)
184 {
185 return either.IsRight () ?
186 either.GetRight () :
187 r;
188 }
189
190 template<template<typename> class Cont, typename L, typename R>
191 std::pair<Cont<L>, Cont<R>> PartitionEithers (const Cont<Either<L, R>>& eithers)
192 {
193 std::pair<Cont<L>, Cont<R>> result;
194 for (const auto& either : eithers)
195 if (either.IsLeft ())
196 result.first.push_back (either.GetLeft ());
197 else
198 result.second.push_back (either.GetRight ());
199
200 return result;
201 }
202
203 template<typename Left, typename Right, typename... Args>
204 auto Visit (const Either<Left, Right>& either, Args&&... args)
205 {
206 return Visit (either.AsVariant (), std::forward<Args> (args)...);
207 }
208
209 template<typename Left, typename Right, typename... Args>
210 auto Visit (Either<Left, Right>&& either, Args&&... args)
211 {
212 return Visit (std::move (either).AsVariant (), std::forward<Args> (args)...);
213 }
214}
215}
friend bool operator!=(const Either &e1, const Either &e2)
Definition either.h:168
static Either Left(const LL &l)
Definition either.h:126
static Either Right(const R &r)
Definition either.h:139
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:151
Either & operator=(const Either &)=default
Either(const R &r)
Definition either.h:45
static Either Right(R &&r)
Definition either.h:134
const L & GetLeft() const
Definition either.h:65
std::optional< R > MaybeRight() const
Definition either.h:86
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:163
auto MapLeft(F &&f) const
Definition either.h:112
bool IsLeft() const
Definition either.h:55
auto MapRight(F &&f) const
Definition either.h:119
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
auto Visit(const Either< Left, Right > &either, Args &&... args)
Definition either.h:204
std::pair< Cont< L >, Cont< R > > PartitionEithers(const Cont< Either< L, R > > &eithers)
Definition either.h:191
R RightOr(const Either< L, R > &either, F &&f)
Definition either.h:175
Definition constants.h:15