LeechCraft  0.6.70-6645-gcd10d7e
Modular cross-platform feature rich live environment.
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,
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>
151  {
152  return Either<L, RNew>::Right (r);
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<typename L, typename R, typename F, typename = ResultOf_t<F ()>>
167  R RightOr (const Either<L, R>& either, F&& f)
168  {
169  return either.IsRight () ?
170  either.GetRight () :
171  f ();
172  }
173 
174  template<typename L, typename R>
175  R RightOr (const Either<L, R>& either, const R& r)
176  {
177  return either.IsRight () ?
178  either.GetRight () :
179  r;
180  }
181 
182  template<template<typename> class Cont, typename L, typename R>
183  std::pair<Cont<L>, Cont<R>> PartitionEithers (const Cont<Either<L, R>>& eithers)
184  {
185  std::pair<Cont<L>, Cont<R>> result;
186  for (const auto& either : eithers)
187  if (either.IsLeft ())
188  result.first.push_back (either.GetLeft ());
189  else
190  result.second.push_back (either.GetRight ());
191 
192  return result;
193  }
194 
195  template<typename L, typename R>
196  struct InstanceFunctor<Either<L, R>>
197  {
198  template<typename F>
200 
201  template<typename F>
202  static FmapResult_t<F> Apply (const Either<L, R>& either, const F& f)
203  {
204  if (either.IsLeft ())
205  return FmapResult_t<F>::Left (either.GetLeft ());
206 
207  return FmapResult_t<F>::Right (f (either.GetRight ()));
208  }
209  };
210 
211  template<typename L, typename R>
213  {
215 
216  template<typename>
217  struct GSLResult;
218 
219  template<typename V>
220  struct GSLResult<Either<L, V>>
221  {
223  };
224 
225  template<typename RP>
226  static Either<L, RP> Pure (const RP& v)
227  {
228  return Either<L, RP>::Right (v);
229  }
230 
231  template<typename AV>
232  static GSLResult_t<Type_t, AV> GSL (const Type_t& f, const AV& v)
233  {
235 
236  if (f.IsLeft ())
237  return R_t::Left (f.GetLeft ());
238 
239  if (v.IsLeft ())
240  return R_t::Left (v.GetLeft ());
241 
242  return R_t::Right (f.GetRight () (v.GetRight ()));
243  }
244  };
245 
246  template<typename L, typename R>
247  struct InstanceMonad<Either<L, R>>
248  {
249  template<typename F>
251 
252  template<typename F>
253  static BindResult_t<F> Bind (const Either<L, R>& value, const F& f)
254  {
255  using R_t = BindResult_t<F>;
256 
257  if (value.IsLeft ())
258  return R_t::Left (value.GetLeft ());
259 
260  return f (value.GetRight ());
261  }
262  };
263 }
264 }
static Either Right(const R &r)
Definition: either.h:144
friend bool operator!=(const Either &e1, const Either &e2)
Definition: either.h:160
friend bool operator==(const Either &e1, const Either &e2)
Definition: either.h:155
static BindResult_t< F > Bind(const Either< L, R > &value, const F &f)
Definition: either.h:253
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:226
typename std::result_of< T >::type ResultOf_t
Definition: oldcppkludges.h:64
static Either Left(const L &l)
Definition: either.h:139
R ToRight(F &&f) const
Definition: either.h:124
const R & GetRight() const
Definition: either.h:97
typename std::enable_if< B, T >::type EnableIf_t
Definition: oldcppkludges.h:67
R RightOr(const Either< L, R > &either, F &&f)
Definition: either.h:167
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:202
static EnableIf_t<!std::is_convertible< RNew, R >::value, Either< L, RNew > > Right(const RNew &r)
Definition: either.h:150
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:183
static GSLResult_t< Type_t, AV > GSL(const Type_t &f, const AV &v)
Definition: either.h:232
Either(const L &l)
Definition: either.h:57
typename InstanceApplicative< AF >::template GSLResult< AV >::Type_t GSLResult_t
Definition: applicative.h:43
static Either< L, RNew > FromMaybe(const boost::optional< RNew > &maybeRight, const L &left)
Definition: either.h:132
Either(const Either< LPrime, RPrime > &other)
Definition: either.h:70