casa  5.7.0-16
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Try.h
Go to the documentation of this file.
1 /* -*- mode: c++ -*- */
2 //# Try.h
3 //# Copyright (C) 2017
4 //# Associated Universities, Inc. Washington DC, USA.
5 //#
6 //# This library is free software; you can redistribute it and/or modify it
7 //# under the terms of the GNU Library General Public License as published by
8 //# the Free Software Foundation; either version 2 of the License, or (at your
9 //# option) any later version.
10 //#
11 //# This library is distributed in the hope that it will be useful, but WITHOUT
12 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
14 //# License for more details.
15 //#
16 //# You should have received a copy of the GNU Library General Public License
17 //# along with this library; if not, write to the Free Software Foundation,
18 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
19 //#
20 //# Correspondence concerning AIPS++ should be addressed as follows:
21 //# Internet email: aips2-request@nrao.edu.
22 //# Postal address: AIPS++ Project Office
23 //# National Radio Astronomy Observatory
24 //# 520 Edgemont Road
25 //# Charlottesville, VA 22903-2475 USA
26 //#
27 #ifndef TRY_H_
28 #define TRY_H_
29 
30 #include <exception>
31 #include <functional>
32 #include <stdexcept>
33 #include <memory>
34 
35 namespace casa {
36 
37 namespace vi {
38 
40  public std::runtime_error {
41 public:
43  : std::runtime_error("no such element")
44  {}
45 };
46 
47 // TryBase exists to enable tests in Try template methods of whether
48 // Try::value_type is a Try type
49 struct TryBase {};
50 
51 template <typename A>
52 class Try
53  : protected TryBase {
54 
55 public:
56 
57  typedef A value_type;
58 
59  // Constructors
60 
61  Try()
62  : m_isSuccess(false)
63  , m_exception(std::make_exception_ptr(NoSuchElementException())) {}
64 
65  Try(const A& a)
66  : m_isSuccess(true) {
67  m_value.reset(new A(a));
68  }
69 
70  Try(A&& a)
71  : m_isSuccess(true) {
72  m_value.reset(new A(std::move(a)));
73  }
74 
75  Try(const std::exception_ptr& e)
76  : m_isSuccess(false)
77  , m_exception(e) {}
78 
79  Try(std::exception_ptr&& e)
80  : m_isSuccess(false)
81  , m_exception(std::move(e)) {}
82 
83  Try(const Try<A>& ta) {
84  *this = ta;
85  }
86 
87  Try(Try<A>&& ta) {
88  *this = ta;
89  }
90 
91  // Static methods
92 
93  /* from()
94  *
95  * Type F should be callable () -> A
96  */
97  template <typename F,
98  class = std::enable_if<
99  std::is_convertible<std::result_of<F()>,A>::value,A> >
100  static Try<A>
101  from(F&& f) {
102  try {
103  return Try<A>(std::forward<F>(f)());
104  } catch (const std::exception &) {
105  return Try<A>(std::current_exception());
106  }
107  }
108 
109  /* lift
110  *
111  * Type F should be callable const A& -> B (for some B)
112  */
113  template <typename F,
114  typename B = typename std::result_of<F(const A&)>::type>
115 #if __cplusplus >= 201402L
116  static auto
117 #else
118  static std::function<Try<B>(const Try<A>&)>
119 #endif
120  lift(F f) {
121  return [f](const Try<A>& ta) {
122  return ta.map(f);
123  };
124  }
125 
126  // Instance methods
127 
128  /* copy assignment
129  */
130  Try<A>& operator=(const Try<A>& ta) {
132  if (ta.m_isSuccess) m_value.reset(new A(*ta.m_value));
133  else m_exception = ta.m_exception;
134  return *this;
135  }
136 
137  /* move assignment
138  */
140  m_isSuccess = ta.m_isSuccess;
141  m_value = ta.m_value;
142  m_exception = std::move(ta.m_exception);
143  return *this;
144  }
145 
146  /* equality operator
147  */
148  bool operator==(const Try<A> &ta) const {
149  return (
151  && ((m_isSuccess && *m_value == *ta.m_value)
152  || (!m_isSuccess && m_exception == ta.m_exception)));
153  }
154 
155  bool operator!=(const Try<A> &ta) const {
156  return !(*this == ta);
157  }
158 
159  /* andThen()
160  *
161  * Type F should be callable () -> Try<B> (for some B)
162  */
163  template <typename F,
164  typename TB = typename std::result_of<F()>::type,
166  TB
167  andThen(F&& f) const {
168  return flatMap([&f](const A&){ return f(); });
169  }
170 
171  /* filter()
172  *
173  * Type F should be callable const A& -> bool
174  */
175  template <typename F,
176  class = std::enable_if<
177  std::is_convertible<std::result_of<F(const A&)>,bool>::value> >
178  Try<A>
179  filter(F&& f) const {
180  if (m_isSuccess) {
181  try {
182  if (std::forward<F>(f)(*m_value)) return *this;
183  return Try<A>();
184  } catch (std::exception &) {
185  return Try<A>(std::current_exception());
186  }
187  } else {
188  return *this;
189  }
190  }
191 
192  /* flatMap()
193  *
194  * Type F should be callable const A& -> Try<B> (for some B)
195  */
196  template <typename F,
197  typename TB = typename std::result_of<F(const A&)>::type,
199  TB
200  flatMap(F&& f) const {
201  return map(std::forward<F>(f)).flatten();
202  };
203 
204  /* flatten()
205  *
206  * May only flatten instances of Try<Try<...> >, removes one level of Try
207  */
209  A
210  flatten() const {
211  if (m_isSuccess) return *m_value;
213  }
214 
215  /* fold()
216  *
217  * Type Err should be callable const std::exception_ptr & -> B (for some B)
218  *
219  * Type Val should be callable const A& -> B
220  */
221  template <typename Err,
222  typename Val,
224  typename C = typename std::result_of<Val(const A&)>::type,
226  B
227  fold(Err&& err, Val&& val) const {
228  if (m_isSuccess) return std::forward<Val>(val)(*m_value);
229  else return std::forward<Err>(err)(m_exception);
230  };
231 
232  /* foreach()
233  *
234  * Type F should be callable const A& -> anything
235  */
236  template <typename F>
237  void
238  foreach(F&& f) const {
239  if (m_isSuccess) std::forward<F>(f)(*m_value);
240  }
241 
242  /* get()
243  *
244  * Get value from Try instance, throws exception if failure
245  */
246  A
247  get() const {
248  if (m_isSuccess) return *m_value;
249  else std::rethrow_exception(m_exception);
250  }
251 
252  /* getOrElse()
253  *
254  * Type F should be callable () -> B (for some B)
255  */
256  template <typename F,
257  typename B = typename std::result_of<F()>::type,
259  B
260  getOrElse(F&& f) const {
261  if (m_isSuccess) return *m_value;
262  else return std::forward<F>(f)();
263  };
264 
265  /* getOrElse_()
266  *
267  * Non-lazy version of getOrElse
268  */
269  template <typename B,
271  B
272  getOrElse_(const B& b) const {
273  return getOrElse([&b](){ return b; });
274  };
275 
276  bool
277  isSuccess() const {
278  return m_isSuccess;
279  }
280 
281  /* map()
282  *
283  * Type F should be callable const A& -> B (for some B)
284  */
285  template <typename F,
286  typename B = typename std::result_of<F(const A&)>::type>
287  Try<B>
288  map(F&& f) const {
289  if (m_isSuccess) {
290  try {
291  return Try<B>(std::forward<F>(f)(*m_value));
292  } catch (std::exception &) {
293  return Try<B>(std::current_exception());
294  }
295  } else {
296  return Try<B>(m_exception);
297  }
298  };
299 
300  /* orElse
301  *
302  * Type F should be callable () -> Try<B> (for some B)
303  */
304  template <typename F,
305  typename TB = typename std::result_of<F()>::type,
307  class = std::enable_if<
308  std::is_base_of<typename TB::value_type,A>::value> >
309  TB
310  orElse(F&& f) const {
311  if (m_isSuccess)
312  return Try<typename TB::value_type>(*m_value);
313  else
314  return std::forward<F>(f)();
315  };
316 
317  /* orElse_
318  *
319  * Non-lazy version of orElse
320  */
321  template <typename TB,
323  class = std::enable_if<
324  std::is_base_of<typename TB::value_type,A>::value> >
325  TB
326  orElse_(const TB& tb) const {
327  return orElse([&tb](){ return tb; });
328  };
329 
330  /* recoverWith()
331  *
332  * Type F should be callable const std::exception_ptr& -> A
333  */
334  template <typename F,
335  class = std::enable_if<
336  std::is_convertible<
337  std::result_of<F(const std::exception&)>,A>::value> >
338  Try<A>
339  recoverWith(F&& f) const {
340  if (m_isSuccess) {
341  return *this;
342  } else {
343  auto e = m_exception;
344  return Try<A>::from([f, e](){ return f(e); });
345  }
346  }
347 
348  /* transform()
349  *
350  * Type Err should be callable const std::exception_ptr & -> Try<B> (for
351  * some B)
352  *
353  * Type Val should be callable const A& -> Try<B>
354  */
355  template <typename Err, typename Val,
357  typename TC = typename std::result_of<Val(const A&)>::type,
359  class = std::enable_if<std::is_base_of<TryBase,TC>::value>,
360  class = std::enable_if<std::is_same<TB,TC>::value > >
361  TB
362  transform(Err&& err, Val&& val) const {
363  Try<TB> folded = fold(
364  std::forward<Err>(err),
365  std::forward<Val>(val));
366  return folded.flatten();
367  };
368 
369  /* operator|()
370  *
371  * Type F should be callable const A& -> B (for some B)
372  */
373  template <typename F,
374  typename B = typename std::result_of<F(const A&)>::type>
375  Try<B>
376  operator|(F&&f) const {
377  return map(std::forward<F>(f));
378  }
379 
380  /* operator>>=()
381  *
382  * Type F should be callable const A& -> Try<B> (for some B)
383  */
384  template <typename F,
385  typename TB = typename std::result_of<F(const A&)>::type,
387  TB
388  operator>>=(F&& f) const {
389  return flatMap(std::forward<F>(f));
390  }
391 
392  /* operator>>()
393  *
394  * Type F should be callable () -> Try<B> (for some B)
395  */
396  template <typename F,
397  typename TB = typename std::result_of<F()>::type,
399  TB
400  operator>>(F&& f) const {
401  return andThen(std::forward<F>(f));
402  }
403 
404 private:
406 
407  std::unique_ptr<A> m_value;
408 
409  std::exception_ptr m_exception;
410 };
411 
412 template <typename F,
413  typename A = typename std::result_of<F()>::type>
414 Try<A>
415 try_(F&& f) {
416  return Try<A>::from(f);
417 }
418 
419 } // end namespace vi
420 
421 } // end namespace casa
422 
423 #endif /* TRY_H_ */
Try< B > operator|(F &&f) const
Definition: Try.h:376
Try< B > map(F &&f) const
Definition: Try.h:288
TB flatMap(F &&f) const
Definition: Try.h:200
Try(Try< A > &&ta)
Definition: Try.h:87
Try< A > & operator=(Try< A > &&ta)
Definition: Try.h:139
bool m_isSuccess
Definition: Try.h:405
static std::function< Try< B >const Try< A > &)> lift(F f)
Definition: Try.h:120
Try< A > try_(F &&f)
Definition: Try.h:415
Try< A > filter(F &&f) const
Definition: Try.h:179
Try(const std::exception_ptr &e)
Definition: Try.h:75
TB transform(Err &&err, Val &&val) const
Definition: Try.h:362
Try()
Constructors.
Definition: Try.h:61
bool operator==(const Try< A > &ta) const
Definition: Try.h:148
virtual void move(double dx, double dy, casacore::String system="")
Implements RegionShape::move.
virtual casacore::String type() const
Implements RegionShape::type.
Definition: RegionShapes.h:548
Try< A > & operator=(const Try< A > &ta)
Instance methods.
Definition: Try.h:130
A flatten() const
Definition: Try.h:210
TB andThen(F &&f) const
Definition: Try.h:167
B getOrElse_(const B &b) const
Definition: Try.h:272
Try(std::exception_ptr &&e)
Definition: Try.h:79
B fold(Err &&err, Val &&val) const
Definition: Try.h:227
Try(A &&a)
Definition: Try.h:70
std::exception_ptr m_exception
Definition: Try.h:409
std::unique_ptr< A > m_value
Definition: Try.h:407
TB orElse(F &&f) const
Definition: Try.h:310
TB operator>>=(F &&f) const
Definition: Try.h:388
B getOrElse(F &&f) const
Definition: Try.h:260
bool isSuccess() const
Definition: Try.h:277
Try(const Try< A > &ta)
Definition: Try.h:83
const Double e
e and functions thereof:
TB orElse_(const TB &tb) const
Definition: Try.h:326
TB operator>>(F &&f) const
Definition: Try.h:400
static Try< A > from(F &&f)
Static methods.
Definition: Try.h:101
TryBase exists to enable tests in Try template methods of whether Try::value_type is a Try type...
Definition: Try.h:49
bool operator!=(const Try< A > &ta) const
Definition: Try.h:155
A value_type
Definition: Try.h:57
Try(const A &a)
Definition: Try.h:65
LatticeExprNode value(const LatticeExprNode &expr)
This function returns the value of the expression without a mask.
Try< A > recoverWith(F &&f) const
Definition: Try.h:339