Lely core libraries  2.3.4
result.hpp
Go to the documentation of this file.
1 
27 #ifndef LELY_UTIL_RESULT_HPP_
28 #define LELY_UTIL_RESULT_HPP_
29 
30 #include <lely/util/error.hpp>
31 
32 #include <type_traits>
33 #include <utility>
34 
35 namespace lely {
36 namespace util {
37 
38 namespace detail {
39 
40 template <class T>
41 class Success {
42  public:
43  using value_type = T;
44 
45  Success() = default;
46 
47  template <class U, class = typename ::std::enable_if<!::std::is_same<
48  typename ::std::decay<U>::type, Success>::value>::type>
49  Success(U&& u) : value_(::std::forward<U>(u)) {}
50 
51  value_type&
52  value() & {
53  return value_;
54  }
55 
56  const value_type&
57  value() const& {
58  return value_;
59  }
60 
61  value_type&&
62  value() && {
63  return ::std::move(value_);
64  }
65 
66  const value_type&&
67  value() const&& {
68  return ::std::move(value_);
69  }
70 
71  private:
72  value_type value_;
73 };
74 
75 template <>
76 class Success<void> {
77  public:
78  using value_type = void;
79 };
80 
81 template <class E>
82 class Failure {
83  public:
84  using error_type = E;
85 
86  Failure() = delete;
87 
88  template <class U, class = typename ::std::enable_if<!::std::is_same<
89  typename ::std::decay<U>::type, Failure>::value>::type>
90  Failure(U&& u) : error_(::std::forward<U>(u)) {}
91 
92  error_type&
93  error() & {
94  return error_;
95  }
96 
97  const error_type&
98  error() const& {
99  return error_;
100  }
101 
102  error_type&&
103  error() && {
104  return ::std::move(error_);
105  }
106 
107  const error_type&&
108  error() const&& {
109  return ::std::move(error_);
110  }
111 
112  private:
113  error_type error_;
114 };
115 
116 template <class>
118 
119 template <>
120 struct error_traits<int> {
121  using error_type = int;
122 
123  static constexpr bool
124  is_error(error_type error) noexcept {
125  return error != 0;
126  }
127 
128  static void
129  throw_error(error_type error, const char* what_arg) {
130  throw_errc(what_arg, error);
131  }
132 };
133 
134 template <>
135 struct error_traits<::std::error_code> {
136  using error_type = ::std::error_code;
137 
138  static bool
139  is_error(error_type error) noexcept {
140  return error.value() != 0;
141  }
142 
143  static void
144  throw_error(error_type error, const char* what_arg) {
145  throw ::std::system_error(error, what_arg);
146  }
147 };
148 
149 template <>
150 struct error_traits<::std::exception_ptr> {
151  using error_type = ::std::exception_ptr;
152 
153  static bool
154  is_error(const error_type& error) noexcept {
155  return error != nullptr;
156  }
157 
158  static void
159  throw_error(error_type error, const char* /*what_arg*/) {
160  ::std::rethrow_exception(::std::move(error));
161  }
162 };
163 
164 } // namespace detail
165 
171 success() noexcept {
172  return {};
173 }
174 
179 template <class T>
180 inline detail::Success<typename ::std::decay<T>::type>
181 success(T&& t) noexcept {
182  return {::std::forward<T>(t)};
183 }
184 
189 template <class E>
190 inline detail::Failure<typename ::std::decay<E>::type>
191 failure(E&& e) noexcept {
192  return {::std::forward<E>(e)};
193 }
194 
199 template <class T, class E = ::std::error_code>
200 class Result {
202 
203  public:
205  using value_type = T;
206 
208  using error_type = typename error_traits::error_type;
209 
211  Result() = default;
212 
214  Result(const detail::Success<void>& /*s*/) {}
215 
217  template <class U>
218  Result(const detail::Success<U>& s) : value_{s.value()} {}
219 
221  template <class U>
222  Result(detail::Success<U>&& s) : value_{::std::move(s).value()} {}
223 
225  template <class U>
226  Result(const detail::Failure<U>& f) : error_{f.error()} {}
227 
229  template <class U>
230  Result(detail::Failure<U>&& f) : error_{::std::move(f).error()} {}
231 
236  template <class U>
237  Result(U&& u, typename ::std::enable_if<
238  ::std::is_constructible<value_type, U>::value &&
239  !::std::is_constructible<error_type, U>::value,
240  bool>::type /*SFINAE*/
241  = false)
242  : value_{::std::forward<U>(u)} {}
243 
248  template <class U>
249  Result(U&& u, typename ::std::enable_if<
250  !::std::is_constructible<value_type, U>::value &&
251  ::std::is_constructible<error_type, U>::value,
252  bool>::type /*SFINAE*/
253  = false)
254  : error_{::std::forward<U>(u)} {}
255 
257  explicit operator bool() const noexcept { return has_value(); }
258 
264  bool
265  has_value() const noexcept {
266  return !has_error();
267  }
268 
273  value_type&
274  value() {
275  if (has_error()) error_traits::throw_error(error_, "value");
276  return value_;
277  }
278 
283  const value_type&
284  value() const {
285  if (has_error()) error_traits::throw_error(error_, "value");
286  return value_;
287  }
288 
290  bool
291  has_error() const noexcept {
292  return error_traits::is_error(error_);
293  }
294 
296  error_type&
297  error() noexcept {
298  return error_;
299  }
300 
302  const error_type&
303  error() const noexcept {
304  return error_;
305  }
306 
307  private:
308  value_type value_{};
309  error_type error_{};
310 };
311 
312 template <class T>
313 class Result<T, typename ::std::enable_if<!::std::is_void<T>::value>::type> {
314  public:
315  using value_type = T;
316  using error_type = void;
317 
318  Result() = default;
319 
320  Result(const detail::Success<void>& /*s*/) {}
321 
322  template <class U>
323  Result(const detail::Success<U>& s) : value_{s.value()} {}
324 
325  template <class U>
326  Result(detail::Success<U>&& s) : value_{::std::move(s).value()} {}
327 
328  template <class U, typename = typename ::std::enable_if<
329  ::std::is_constructible<value_type, U>::value>::type>
330  // NOLINTNEXTLINE(readability/nolint)
331  // NOLINTNEXTLINE(misc-forwarding-reference-overload)
332  Result(U&& u) : value_{::std::forward<U>(u)} {}
333 
334  explicit operator bool() const noexcept { return has_value(); }
335 
336  bool
337  has_value() const noexcept {
338  return !has_error();
339  }
340 
341  value_type&
342  value() noexcept {
343  return value_;
344  }
345 
346  const value_type&
347  value() const noexcept {
348  return value_;
349  }
350 
351  bool
352  has_error() const noexcept {
353  return false;
354  }
355 
356  void
357  error() const noexcept {}
358 
359  private:
360  value_type value_{};
361 };
362 
363 template <class E>
364 class Result<void, E> {
366 
367  public:
368  using value_type = void;
369  using error_type = typename error_traits::error_type;
370 
371  Result() = default;
372 
373  Result(const detail::Success<void>&) {}
374 
376 
377  template <class U>
378  Result(const detail::Failure<U>& f) : error_{f.error()} {}
379 
380  template <class U>
381  Result(detail::Failure<U>&& f) : error_{::std::move(f).error()} {}
382 
383  template <class U, typename = typename ::std::enable_if<
384  ::std::is_constructible<error_type, U>::value>::type>
385  // NOLINTNEXTLINE(readability/nolint)
386  // NOLINTNEXTLINE(misc-forwarding-reference-overload)
387  Result(U&& u) : error_{::std::forward<U>(u)} {}
388 
389  explicit operator bool() const noexcept { return has_value(); }
390 
391  bool
392  has_value() const noexcept {
393  return !has_error();
394  }
395 
396  void
397  value() const {
398  if (has_error()) error_traits::throw_error(error_, "value");
399  }
400 
401  bool
402  has_error() const noexcept {
403  return error_traits::is_error(error_);
404  }
405 
406  error_type&
407  error() noexcept {
408  return error_;
409  }
410 
411  const error_type&
412  error() const noexcept {
413  return error_;
414  }
415 
416  private:
417  error_type error_{};
418 };
419 
420 template <>
421 class Result<void, void> {
422  public:
423  using value_type = void;
424  using error_type = void;
425 
426  Result() = default;
427 
428  template <class U>
429  Result(U&&) noexcept {}
430 
431  explicit operator bool() const noexcept { return has_value(); }
432 
433  bool
434  has_value() const noexcept {
435  return !has_error();
436  }
437 
438  void
439  value() const noexcept {}
440 
441  bool
442  has_error() const noexcept {
443  return false;
444  }
445 
446  void
447  error() const noexcept {}
448 };
449 
450 } // namespace util
451 } // namespace lely
452 
453 #endif // !LELY_UTIL_RESULT_HPP_
The type of objects thrown as exceptions to report a system error with an associated error code.
Definition: exception.hpp:54
A type capable of representing both the successful and failure result of an operation.
Definition: result.hpp:200
Result(const detail::Success< U > &s)
Constructs a successful result with the specified value.
Definition: result.hpp:218
const error_type & error() const noexcept
Returns a reference to the error, if any.
Definition: result.hpp:303
bool has_error() const noexcept
Returns true if *this contains a non-zero error.
Definition: result.hpp:291
Result()=default
Constructs a successful result with an empty value.
Result(const detail::Failure< U > &f)
Constructs a failure result with the specified error.
Definition: result.hpp:226
Result(const detail::Success< void > &)
Constructs a successful result with an empty value.
Definition: result.hpp:214
const value_type & value() const
Returns a reference to the value if *this contains a value, and throws an exception if *this contains...
Definition: result.hpp:284
T value_type
The value type on success.
Definition: result.hpp:205
bool has_value() const noexcept
Returns true if *this contains a value (and not a non-zero error).
Definition: result.hpp:265
typename error_traits::error_type error_type
The error type on failure.
Definition: result.hpp:208
Result(detail::Success< U > &&s)
Constructs a successful result with the specified value.
Definition: result.hpp:222
Result(U &&u, typename ::std::enable_if< ::std::is_constructible< value_type, U >::value &&!::std::is_constructible< error_type, U >::value, bool >::type=false)
Constructs a successful result with value u if U is constructible to value_type and not constructible...
Definition: result.hpp:237
value_type & value()
Returns a reference to the value if *this contains a value, and throws an exception if *this contains...
Definition: result.hpp:274
Result(detail::Failure< U > &&f)
Constructs a failure result with the specified error.
Definition: result.hpp:230
Result(U &&u, typename ::std::enable_if< !::std::is_constructible< value_type, U >::value &&::std::is_constructible< error_type, U >::value, bool >::type=false)
Constructs a failure result with error u if U is constructible to error_type and not constructible to...
Definition: result.hpp:249
error_type & error() noexcept
Returns a reference to the error, if any.
Definition: result.hpp:297
This header file is part of the utilities library; it contains C++ convenience functions for creating...
void throw_errc(int errc=get_errc())
Throws an std::system_error exception corresponding to the specified or current (thread-specific) nat...
Definition: error.hpp:73
detail::Success< void > success() noexcept
Returns an object that can be used to implicitly construct a successful lely::util::Result with a def...
Definition: result.hpp:171
detail::Failure< typename ::std::decay< E >::type > failure(E &&e) noexcept
Returns an object that can be used to implicitly construct a failure lely::util::Result with the spec...
Definition: result.hpp:191