LeechCraft  0.6.70-9312-g4cc613a2df
Modular cross-platform feature rich live environment.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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  * Boost Software License - Version 1.0 - August 17th, 2003
6  *
7  * Permission is hereby granted, free of charge, to any person or organization
8  * obtaining a copy of the software and accompanying documentation covered by
9  * this license (the "Software") to use, reproduce, display, distribute,
10  * execute, and transmit the Software, and to prepare derivative works of the
11  * Software, and to permit third-parties to whom the Software is furnished to
12  * do so, all subject to the following:
13  *
14  * The copyright notices in the Software and this entire statement, including
15  * the above license grant, this restriction and the following disclaimer,
16  * must be included in all copies of the Software, in whole or in part, and
17  * all derivative works of the Software, unless such copies or derivative
18  * works are solely in the form of machine-executable object code generated by
19  * a source language processor.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
24  * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
25  * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
26  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  **********************************************************************/
29 
30 #pragma once
31 
32 #include <type_traits>
33 #include <boost/variant.hpp>
34 #include "functor.h"
35 #include "applicative.h"
36 #include "monad.h"
37 
38 namespace LeechCraft
39 {
40 namespace Util
41 {
42  template<typename L, typename R>
43  class Either
44  {
45  using Either_t = boost::variant<L, R>;
46  Either_t This_;
47 
48  enum { LeftVal, RightVal };
49 
50  static_assert (!std::is_same<L, R>::value, "Types cannot be the same.");
51  public:
52  using L_t = L;
53  using R_t = R;
54 
55  Either () = delete;
56 
57  explicit Either (const L& l)
58  : This_ { l }
59  {
60  }
61 
62  explicit Either (const R& r)
63  : This_ { r }
64  {
65  }
66 
67  template<typename LPrime, typename RPrime,
68  typename = std::enable_if_t<std::is_convertible<LPrime, L>::value &&
69  std::is_convertible<RPrime, R>::value>>
71  : This_ { other.AsVariant () }
72  {
73  }
74 
75  Either (const Either&) = default;
76  Either (Either&&) = default;
77  Either& operator= (const Either&) = default;
78  Either& operator= (Either&&) = default;
79 
80  bool IsLeft () const
81  {
82  return This_.which () == LeftVal;
83  }
84 
85  bool IsRight () const
86  {
87  return This_.which () == RightVal;
88  }
89 
90  const L& GetLeft () const
91  {
92  if (!IsLeft ())
93  throw std::runtime_error { "Tried accessing Left for a Right Either" };
94  return boost::get<L> (This_);
95  }
96 
97  const R& GetRight () const
98  {
99  if (!IsRight ())
100  throw std::runtime_error { "Tried accessing Right for a Left Either" };
101  return boost::get<R> (This_);
102  }
103 
104  boost::optional<L> MaybeLeft () const
105  {
106  if (!IsLeft ())
107  return {};
108  return GetLeft ();
109  }
110 
111  boost::optional<R> MaybeRight () const
112  {
113  if (!IsRight ())
114  return {};
115  return GetRight ();
116  }
117 
118  boost::variant<L, R> AsVariant () const
119  {
120  return This_;
121  }
122 
123  template<typename F>
124  R ToRight (F&& f) const
125  {
126  return IsRight () ?
127  GetRight () :
128  f (GetLeft ());
129  }
130 
131  template<typename RNew>
132  static Either<L, RNew> FromMaybe (const boost::optional<RNew>& maybeRight, const L& left)
133  {
134  return maybeRight ?
135  Either<L, RNew>::Right (*maybeRight) :
136  Either<L, RNew>::Left (left);
137  }
138 
139  static Either Left (const L& l)
140  {
141  return Either { l };
142  }
143 
144  static Either Right (const R& r)
145  {
146  return Either { r };
147  }
148 
149  template<typename RNew>
150  static std::enable_if_t<!std::is_convertible<RNew, R>::value, Either<L, RNew>> Right (const RNew& r)
151  {
152  return Either<L, RNew>::Right (r);
153  }
154 
155  static auto EmbeddingLeft ()
156  {
157  return [] (const auto& other)
158  {
159  static_assert (std::is_convertible<decltype (other.GetLeft ()), L>::value,
160  "Other's Either's Left type is not convertible to this Left type.");
161  return other.IsLeft () ?
162  Either<L, R>::Left (other.GetLeft ()) :
163  Either<L, R>::Right (other.GetRight ());
164  };
165  }
166 
167  friend bool operator== (const Either& e1, const Either& e2)
168  {
169  return e1.This_ == e2.This_;
170  }
171 
172  friend bool operator!= (const Either& e1, const Either& e2)
173  {
174  return !(e1 == e2);
175  }
176  };
177 
178  template<typename L, typename R, typename F, typename = std::result_of_t<F ()>>
179  R RightOr (const Either<L, R>& either, F&& f)
180  {
181  return either.IsRight () ?
182  either.GetRight () :
183  f ();
184  }
185 
186  template<typename L, typename R>
187  R RightOr (const Either<L, R>& either, const R& r)
188  {
189  return either.IsRight () ?
190  either.GetRight () :
191  r;
192  }
193 
194  template<template<typename> class Cont, typename L, typename R>
195  std::pair<Cont<L>, Cont<R>> PartitionEithers (const Cont<Either<L, R>>& eithers)
196  {
197  std::pair<Cont<L>, Cont<R>> result;
198  for (const auto& either : eithers)
199  if (either.IsLeft ())
200  result.first.push_back (either.GetLeft ());
201  else
202  result.second.push_back (either.GetRight ());
203 
204  return result;
205  }
206 
207  template<typename L, typename R>
208  struct InstanceFunctor<Either<L, R>>
209  {
210  template<typename F>
212 
213  template<typename F>
214  static FmapResult_t<F> Apply (const Either<L, R>& either, const F& f)
215  {
216  if (either.IsLeft ())
217  return FmapResult_t<F>::Left (either.GetLeft ());
218 
219  return FmapResult_t<F>::Right (f (either.GetRight ()));
220  }
221  };
222 
223  template<typename L, typename R>
225  {
227 
228  template<typename>
229  struct GSLResult;
230 
231  template<typename V>
232  struct GSLResult<Either<L, V>>
233  {
235  };
236 
237  template<typename RP>
238  static Either<L, RP> Pure (const RP& v)
239  {
240  return Either<L, RP>::Right (v);
241  }
242 
243  template<typename AV>
244  static GSLResult_t<Type_t, AV> GSL (const Type_t& f, const AV& v)
245  {
246  using R_t = GSLResult_t<Type_t, AV>;
247 
248  if (f.IsLeft ())
249  return R_t::Left (f.GetLeft ());
250 
251  if (v.IsLeft ())
252  return R_t::Left (v.GetLeft ());
253 
254  return R_t::Right (f.GetRight () (v.GetRight ()));
255  }
256  };
257 
258  template<typename L, typename R>
259  struct InstanceMonad<Either<L, R>>
260  {
261  template<typename F>
262  using BindResult_t = std::result_of_t<F (R)>;
263 
264  template<typename F>
265  static BindResult_t<F> Bind (const Either<L, R>& value, const F& f)
266  {
267  using R_t = BindResult_t<F>;
268 
269  if (value.IsLeft ())
270  return R_t::Left (value.GetLeft ());
271 
272  return f (value.GetRight ());
273  }
274  };
275 }
276 }
static Either Right(const R &r)
Definition: either.h:144
friend bool operator!=(const Either &e1, const Either &e2)
Definition: either.h:172
friend bool operator==(const Either &e1, const Either &e2)
Definition: either.h:167
static BindResult_t< F > Bind(const Either< L, R > &value, const F &f)
Definition: either.h:265
bool IsRight() const
Definition: either.h:85
bool IsLeft() const
Definition: either.h:80
static Either< L, RP > Pure(const RP &v)
Definition: either.h:238
static Either Left(const L &l)
Definition: either.h:139
static std::enable_if_t<!std::is_convertible< RNew, R >::value, Either< L, RNew > > Right(const RNew &r)
Definition: either.h:150
R ToRight(F &&f) const
Definition: either.h:124
const R & GetRight() const
Definition: either.h:97
R RightOr(const Either< L, R > &either, F &&f)
Definition: either.h:179
const L & GetLeft() const
Definition: either.h:90
boost::optional< L > MaybeLeft() const
Definition: either.h:104
static FmapResult_t< F > Apply(const Either< L, R > &either, const F &f)
Definition: either.h:214
Either(const R &r)
Definition: either.h:62
boost::optional< R > MaybeRight() const
Definition: either.h:111
Either & operator=(const Either &)=default
boost::variant< L, R > AsVariant() const
Definition: either.h:118
std::pair< Cont< L >, Cont< R > > PartitionEithers(const Cont< Either< L, R >> &eithers)
Definition: either.h:195
static GSLResult_t< Type_t, AV > GSL(const Type_t &f, const AV &v)
Definition: either.h:244
Either(const L &l)
Definition: either.h:57
typename InstanceApplicative< AF >::template GSLResult< AV >::Type_t GSLResult_t
Definition: applicative.h:42
static auto EmbeddingLeft()
Definition: either.h:155
static Either< L, RNew > FromMaybe(const boost::optional< RNew > &maybeRight, const L &left)
Definition: either.h:132
The Functor class is used for types that can be mapped over.
Definition: functor.h:54
Either(const Either< LPrime, RPrime > &other)
Definition: either.h:70