ROSE  0.11.145.0
Result.h
1 // WARNING: Changes to this file must be contributed back to Sawyer or else they will
2 // be clobbered by the next update from Sawyer. The Sawyer repository is at
3 // https://github.com/matzke1/sawyer.
4 
5 
6 
7 
8 #ifndef Sawyer_Result_H
9 #define Sawyer_Result_H
10 
11 #include <Sawyer/Optional.h>
12 
13 #include <boost/lexical_cast.hpp>
14 #include <boost/serialization/access.hpp>
15 #include <boost/serialization/nvp.hpp>
16 #include <boost/serialization/split_member.hpp>
17 #include <boost/variant.hpp>
18 #include <exception>
19 #include <string>
20 #include <type_traits>
21 
22 namespace Sawyer {
23 
24 template <class F, class... Args>
26 {
27  template <class U>
28  static auto test(U* p) -> decltype((*p)(std::declval<Args>()...), void(), std::true_type());
29  template <class U>
30  static auto test(...) -> decltype(std::false_type());
31 
32  static constexpr bool value = decltype(test<F>(0))::value;
33 };
34 
35 
37 template<class T>
38 class Ok {
39 public:
40  using Value = T;
41 
42 private:
43  Value ok_;
44 
45 private:
46  friend class boost::serialization::access;
47 
48  template<class S>
49  void serialize(S &s, const unsigned /*version*/) {
50  s & BOOST_SERIALIZATION_NVP(ok_);
51  }
52 
53 public:
54  Ok() = delete;
55 
57  Ok(const Ok &other)
58  : ok_(other.ok_) {}
59 
61  explicit Ok(const Value &ok)
62  : ok_(ok) {}
63 
67  Ok& operator=(const Ok &other) {
68  ok_ = other.ok_;
69  return *this;
70  }
71  Ok& operator=(const Value &ok) {
72  ok_ = ok;
73  return *this;
74  }
78  const Value& operator*() const {
79  return ok_;
80  }
81 
83  const Value* operator->() const {
84  return &ok_;
85  }
86 };
87 
88 // Specialization for Ok that stores string literals, as in Ok("foo"). These get treated as std::string instead.
89 template<size_t N>
90 class Ok<char[N]> {
91 public:
92  using Value = std::string;
93 
94 private:
95  std::string ok_;
96 
97 private:
98  friend class boost::serialization::access;
99 
100  template<class S>
101  void serialize(S &s, const unsigned /*version*/) {
102  s & BOOST_SERIALIZATION_NVP(ok_);
103  }
104 
105 public:
106  Ok() = delete;
107 
108  explicit Ok(const Value &s)
109  : ok_(s) {}
110 
111  Ok& operator=(const Ok &other) {
112  ok_ = other.ok_;
113  return *this;
114  }
115 
116  Ok& operator=(const Value &ok) {
117  ok_ = ok;
118  return *this;
119  }
120 
121  const Value& operator*() const {
122  return ok_;
123  }
124 
125  const Value* operator->() const {
126  return &ok_;
127  }
128 };
129 
134 template<class T>
135 Ok<T> makeOk(const T &value) {
136  return Ok<T>(value);
137 }
138 
139 // Specialization for string literals, as in makeOk("foo") so they get treated as std::string instead.
140 inline Ok<std::string> makeOk(const char *s) {
141  return Ok<std::string>(std::string(s));
142 }
143 inline Ok<std::string> makeOk(char *s) {
144  return Ok<std::string>(std::string(s));
145 }
146 
148 template<class E>
149 class Error {
150 public:
151  using Value = E;
152 
153 private:
154  Value error_;
155 
156 private:
157  friend class boost::serialization::access;
158 
159  template<class S>
160  void serialize(S &s, const unsigned /*version*/) {
161  s & BOOST_SERIALIZATION_NVP(error_);
162  }
163 
164 public:
165  Error() = delete;
166 
168  Error(const Error &other)
169  : error_(other.error_) {}
170 
172  explicit Error(const E &error)
173  : error_(error) {}
174 
178  Error& operator=(const Error &other) {
179  error_ = other.error_;
180  return *this;
181  }
182  Error& operator=(const Value &error) {
183  error_ = error;
184  return *this;
185  }
189  const Value& operator*() const {
190  return error_;
191  }
192 
194  const Value* operator->() const {
195  return &error_;
196  }
197 };
198 
199 // Specialization for Error that stores string literals as in Error("syntax error"). It stores them as std::string instead.
200 template<size_t N>
201 class Error<char[N]> {
202 public:
203  using Value = std::string;
204 
205 private:
206  std::string error_;
207 
208 private:
209  friend class boost::serialization::access;
210 
211  template<class S>
212  void serialize(S &s, const unsigned /*version*/) {
213  s & BOOST_SERIALIZATION_NVP(error_);
214  }
215 
216 public:
217  Error() = delete;
218 
220  explicit Error(const Error &other)
221  : error_(other.error_) {}
222 
224  explicit Error(const Value &error)
225  : error_(error) {}
226 
230  Error& operator=(const Error &other) {
231  error_ = other.error_;
232  return *this;
233  }
234  Error& operator=(const Value &error) {
235  error_ = error;
236  return *this;
237  }
241  const Value& operator*() const {
242  return error_;
243  }
244 
246  const Value* operator->() const {
247  return &error_;
248  }
249 };
250 
255 template<class T>
256 Error<T> makeError(const T &value) {
257  return Error<T>(value);
258 }
259 
260 // Specialization for string literals, as in makeError("foo") so they get treated as std::string instead.
261 inline Error<std::string> makeError(const char *s) {
262  return Error<std::string>(std::string(s));
263 }
264 inline Error<std::string> makeError(char *s) {
265  return Error<std::string>(std::string(s));
266 }
267 
269 template<class T, class E>
270 class Result {
271 public:
272  using OkValue = T;
273  using ErrorValue = E;
274  using OkType = Ok<T>;
275  using ErrorType = Error<E>;
276 
277 private:
278  boost::variant<Ok<T>, Error<E>> result_;
279 
280 private:
281  friend class boost::serialization::access;
282 
283  template<class S>
284  void save(S &s, const unsigned /*version*/) const {
285  s <<boost::serialization::make_nvp("isOk", isOk());
286  if (isOk()) {
287  s <<boost::serialization::make_nvp("ok", unwrap());
288  } else {
289  s <<boost::serialization::make_nvp("error", unwrapError());
290  }
291  }
292 
293  template<class S>
294  void load(S &s, const unsigned /*version*/) {
295  bool isOk;
296  s >>boost::serialization::make_nvp("isOk", isOk);
297  if (isOk) {
298  T ok;
299  s >>boost::serialization::make_nvp("ok", ok);
300  result_ = OkType(ok);
301  } else {
302  E error;
303  s >>boost::serialization::make_nvp("error", error);
304  result_ = ErrorType(error);
305  }
306  }
307 
308  BOOST_SERIALIZATION_SPLIT_MEMBER();
309 
310 public:
311  template<class U = T>
312  /*implicit*/ Result(const Ok<U> &ok)
313  : result_(OkType(*ok)) {}
314 
315  template<class F = E>
316  /*implicit*/ Result(const Error<F> &error)
317  : result_(ErrorType(*error)) {}
318 
320  template<class U = T>
321  Result& operator=(const Ok<U> &ok) {
322  result_ = OkType(*ok);
323  return *this;
324  }
325 
327  template<class F = E>
328  Result& operator=(const Error<F> &error) {
329  result_ = ErrorType(*error);
330  return *this;
331  }
332 
334  template<class U = T>
335  bool operator==(const Ok<U> &ok) const {
336  return isOk() && *this->ok() == *ok;
337  }
338 
340  template<class U = T>
341  bool operator!=(const Ok<U> &ok) const {
342  return !(*this == ok);
343  }
344 
346  template<class F = E>
347  bool operator==(const Error<F> &error) const {
348  return isError() && *this->error() == *error;
349  }
350 
352  template<class F = E>
353  bool operator!=(const Error<F> &error) const {
354  return !(*this == error);
355  }
356 
358  template<class U, class F>
359  bool operator==(const Result<U, F> &other) const {
360  return ((isOk() && other.isOk() && *ok() == *other.ok()) ||
361  (isError() && other.isError() && *error() == *other.error()));
362  }
363 
365  template<class U, class F>
366  bool operator!=(const Result<U, F> &other) const {
367  return !(*this == other);
368  }
369 
373  bool isOk() const {
374  return result_.which() == 0;
375  }
376  explicit operator bool() const {
377  return isOk();
378  }
382  bool isError() const {
383  return !isOk();
384  }
385 
389  const Sawyer::Optional<T> ok() const {
390  if (isOk()) {
391  return *boost::get<OkType>(result_);
392  } else {
393  return Sawyer::Nothing();
394  }
395  }
396 
400  const Sawyer::Optional<E> error() const {
401  if (isOk()) {
402  return Sawyer::Nothing();
403  } else {
404  return *boost::get<ErrorType>(result_);
405  }
406  }
407 
411  const T& expect(const std::string &mesg) const {
412  if (isOk()) {
413  return *boost::get<OkType>(result_);
414  } else {
415  throw std::runtime_error(mesg);
416  }
417  }
418 
424  const T& unwrap() const {
425  return expect("result is not okay");
426  }
427  const T& operator*() const {
428  return unwrap();
429  }
433  const T orElse(const T &dflt) const {
434  return isOk() ? unwrap() : dflt;
435  }
436 
441  template<class Fn>
442  typename std::enable_if<is_invocable<Fn, ErrorValue>::value, const Result>::type
443  orElse(Fn fn) const {
444  if (isOk()) {
445  return *this;
446  } else {
447  return fn(*error());
448  }
449  }
450 
454  template<class F>
455  const Result<T, F> orElse(const Result<T, F> &other) const {
456  if (isOk()) {
457  return boost::get<OkType>(result_);
458  } else {
459  return other;
460  }
461  }
462 
464  const T& orDefault() const {
465  static T dflt = T();
466  return isOk() ? unwrap() : dflt;
467  }
468 
473  template<class Exception = E>
474  const T& orThrow() const {
475  if (isOk()) {
476  return unwrap();
477  } else {
478  throw Exception(*error());
479  }
480  }
481 
483  template<class Exception = E>
484  const T& orThrow(const Exception &e) const {
485  if (isOk()) {
486  return unwrap();
487  } else {
488  throw e;
489  }
490  }
491 
496  template<class Fn>
497  typename std::enable_if<is_invocable<Fn, OkValue>::value, const Result>::type
498  andThen(Fn fn) const {
499  if (isOk()) {
500  return fn(*ok());
501  } else {
502  return *this;
503  }
504  }
505 
509  template<class U>
510  const Result<U, E> andThen(const Result<U, E> &other) const {
511  if (isOk()) {
512  return other;
513  } else {
514  return boost::get<ErrorType>(result_);
515  }
516  }
517 
521  const E& expectError(const std::string &mesg) const {
522  if (isOk()) {
523  throw std::runtime_error(mesg);
524  } else {
525  return *boost::get<ErrorType>(result_);
526  }
527  }
528 
532  const E& unwrapError() const {
533  return expectError("result is not an error");
534  }
535 
537  template<class U>
538  bool contains(const U &value) const {
539  return isOk() ? unwrap() == value : false;
540  }
541 
543  template<class F>
544  bool containsError(const F &error) const {
545  return isOk() ? false : unwrapError() == error;
546  }
547 
548 #if 0 // [Robb Matzke 2022-08-17]
549 
555  transpose() const {
556  if (isOk()) {
557  if (unwrap().isEmpty()) {
558  return Sawyer::Nothing();
559  } else {
560  return OkType(*unwrap());
561  }
562  } else {
563  return ErrorType(unwrapError());
564  }
565  }
566 
568  Result<typename OkValue::OkValue, E> flatten() const {
569  if (isOk()) {
570  if (unwrap().isOk()) {
571  return OkValue::OkType(unwrap().unwrap());
572  } else {
573  return ErrorType(unwrap().unwrapError());
574  }
575  } else {
576  return ErrorType(unwrapError());
577  }
578  }
579 #endif
580 
584  template<class U>
585  bool assignTo(U &out) const {
586  if (isOk()) {
587  out = unwrap();
588  return true;
589  } else {
590  return false;
591  }
592  }
593 };
594 
595 } // namespace
596 #endif
Error(const E &error)
Construct from a value.
Definition: Result.h:172
bool operator!=(const Result< U, F > &other) const
Test whether this result is unequal to the other result.
Definition: Result.h:366
Success value.
Definition: Result.h:38
const T & expect(const std::string &mesg) const
Returns the success value or throws an exception.
Definition: Result.h:411
Error value.
Definition: Result.h:149
const Value * operator->() const
Dereference to obtain pointer to error.
Definition: Result.h:194
const T & orDefault() const
Returns the okay value or a default constructed value.
Definition: Result.h:464
const T & orThrow() const
Returns the value or throws an exception.
Definition: Result.h:474
const Value & operator*() const
Dereference to obtain value.
Definition: Result.h:78
Result & operator=(const Ok< U > &ok)
Assign an Ok value to this result.
Definition: Result.h:321
Ok< T > makeOk(const T &value)
Conventient way to constructo an Ok value before C++17.
Definition: Result.h:135
Error(const Value &error)
Construct from a value.
Definition: Result.h:224
const Sawyer::Optional< T > ok() const
Convert to Optional.
Definition: Result.h:389
Holds a value or nothing.
Definition: Optional.h:49
Error< T > makeError(const T &value)
Conventient way to constructo an Error value before C++17.
Definition: Result.h:256
Error & operator=(const Error &other)
Assignment.
Definition: Result.h:178
Result containing a value or an error.
Definition: Result.h:270
const Result< T, F > orElse(const Result< T, F > &other) const
Returns this value or the other result.
Definition: Result.h:455
bool operator!=(const Ok< U > &ok) const
Test whether this result does not have the specified Ok value.
Definition: Result.h:341
const Value * operator->() const
Dereference to obtain pointer to error.
Definition: Result.h:246
bool containsError(const F &error) const
Returns true if this result contains the specified error value.
Definition: Result.h:544
Name space for the entire library.
Definition: FeasiblePath.h:767
bool assignTo(U &out) const
Conditionally save a value.
Definition: Result.h:585
const E & unwrapError() const
Returns the error value or throws an exception.
Definition: Result.h:532
Error & operator=(const Value &error)
Assignment.
Definition: Result.h:182
bool isError() const
Returns true if the result is an error.
Definition: Result.h:382
Error(const Error &other)
Copy constructor.
Definition: Result.h:168
Error & operator=(const Error &other)
Assignment.
Definition: Result.h:230
std::enable_if< is_invocable< Fn, ErrorValue >::value, const Result >::type orElse(Fn fn) const
Returns the contained Ok value, or calls a function.
Definition: Result.h:443
const T & operator*() const
Returns the success value or throws an exception.
Definition: Result.h:427
bool isOk() const
Returns true if the result is okay.
Definition: Result.h:373
const T orElse(const T &dflt) const
Returns the contained Ok value or a provided default.
Definition: Result.h:433
Ok(const Ok &other)
Copy constructor.
Definition: Result.h:57
Ok & operator=(const Value &ok)
Assignment.
Definition: Result.h:71
bool contains(const U &value) const
Returns true if this result contains the specified okay value.
Definition: Result.h:538
bool operator!=(const Error< F > &error) const
Test whether this result does not have the specified Error value.
Definition: Result.h:353
const Value & operator*() const
Dereference to obtain error.
Definition: Result.h:241
bool operator==(const Result< U, F > &other) const
Test whether this result is equal to the other result.
Definition: Result.h:359
Ok & operator=(const Ok &other)
Assignment.
Definition: Result.h:67
std::enable_if< is_invocable< Fn, OkValue >::value, const Result >::type andThen(Fn fn) const
Returns the contained Error value, or calls a function.
Definition: Result.h:498
const Sawyer::Optional< E > error() const
Convert to Optional.
Definition: Result.h:400
Result & operator=(const Error< F > &error)
Assign an Error value to this result.
Definition: Result.h:328
const E & expectError(const std::string &mesg) const
Returns the error value or throws an exception.
Definition: Result.h:521
Error & operator=(const Value &error)
Assignment.
Definition: Result.h:234
Represents no value.
Definition: Optional.h:32
Error(const Error &other)
Copy constructor.
Definition: Result.h:220
const T & unwrap() const
Returns the success value or throws an exception.
Definition: Result.h:424
bool operator==(const Ok< U > &ok) const
Test whether this result has the specified Ok value.
Definition: Result.h:335
const T & orThrow(const Exception &e) const
Returns the value or throws an exception constructed from the specified value.
Definition: Result.h:484
const Value & operator*() const
Dereference to obtain error.
Definition: Result.h:189
const Result< U, E > andThen(const Result< U, E > &other) const
Returns this error or the other result.
Definition: Result.h:510
Ok(const Value &ok)
Construct from an value.
Definition: Result.h:61
bool operator==(const Error< F > &error) const
Test whether this result has the specified Error value.
Definition: Result.h:347
const Value * operator->() const
Dereference to obtain pointer.
Definition: Result.h:83