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
35namespace lely {
36namespace util {
37
38namespace detail {
39
40template <class T>
41class 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
75template <>
76class Success<void> {
77 public:
78 using value_type = void;
79};
80
81template <class E>
82class 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
116template <class>
118
119template <>
120struct 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
134template <>
135struct 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
149template <>
150struct 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
171success() noexcept {
172 return {};
173}
174
179template <class T>
180inline detail::Success<typename ::std::decay<T>::type>
181success(T&& t) noexcept {
182 return {::std::forward<T>(t)};
183}
184
189template <class E>
190inline detail::Failure<typename ::std::decay<E>::type>
191failure(E&& e) noexcept {
192 return {::std::forward<E>(e)};
193}
194
199template <class T, class E = ::std::error_code>
200class Result {
202
203 public:
205 using value_type = T;
206
208 using error_type = typename error_traits::error_type;
209
211 Result() = default;
212
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
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
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
312template <class T>
313class 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
363template <class E>
364class 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
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
420template <>
421class 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
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
error_type & error() noexcept
Returns a reference to the error, if any.
Definition: result.hpp:297
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
const error_type & error() const noexcept
Returns a reference to the error, if any.
Definition: result.hpp:303
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
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
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
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
STL namespace.
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