YACLib
C++ library for concurrent tasks execution
Loading...
Searching...
No Matches
result.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <yaclib/fwd.hpp>
5
6#include <exception>
7#include <utility>
8#include <variant>
9
10namespace yaclib {
11
12/**
13 * Result states \see Result
14 * \enum Value, Exception, Error, Empty
15 */
16enum class [[nodiscard]] ResultState : unsigned char {
17 Value = 0,
18 Exception = 1,
19 Error = 2,
20 Empty = 3,
21};
22
23/**
24 * Default error
25 */
38
40
41/**
42 * \class Exception for Error
43 * \see Result
44 */
45template <typename Error>
46class [[nodiscard]] ResultError final : public std::exception {
47 public:
52
55 explicit ResultError(const Error& error) noexcept(std::is_nothrow_copy_constructible_v<Error>) : _error{error} {
56 }
57
58 [[nodiscard]] Error& Get() & noexcept {
59 return _error;
60 }
62 return _error;
63 }
64
65 const char* what() const noexcept final {
66 return _error.What();
67 }
68
69 private:
70 Error _error;
71};
72
73/**
74 * \class Exception for Empty, invalid state
75 * \see Result
76 */
77struct ResultEmpty final : std::exception {
78 const char* what() const noexcept final {
79 return "yaclib::ResultEmpty";
80 }
81};
82
83/**
84 * Encapsulated return value from caller
85 *
86 * \tparam ValueT type of value that stored in Result
87 * \tparam E type of error that stored in Result
88 */
89template <typename ValueT, typename E>
91 static_assert(Check<ValueT>(), "V should be valid");
92 static_assert(Check<E>(), "E should be valid");
93 static_assert(!std::is_same_v<ValueT, E>, "Result cannot be instantiated with same V and E, because it's ambiguous");
94 static_assert(std::is_constructible_v<E, StopTag>, "Error should be constructable from StopTag");
95 using V = std::conditional_t<std::is_void_v<ValueT>, Unit, ValueT>;
96 using Variant = std::variant<V, std::exception_ptr, E, std::monostate>;
97
98 public:
99 Result(Result&& other) noexcept(std::is_nothrow_move_constructible_v<Variant>) = default;
100 Result(const Result& other) noexcept(std::is_nothrow_copy_constructible_v<Variant>) = default;
101 Result& operator=(Result&& other) noexcept(std::is_nothrow_move_assignable_v<Variant>) = default;
102 Result& operator=(const Result& other) noexcept(std::is_nothrow_copy_assignable_v<Variant>) = default;
103
104 template <typename... Args,
105 typename =
106 std::enable_if_t<(sizeof...(Args) > 1 || !std::is_same_v<std::decay_t<head_t<Args&&...>>, Result>), void>>
107 Result(Args&&... args) noexcept(std::is_nothrow_constructible_v<Variant, std::in_place_type_t<V>, Args&&...>)
108 : Result{std::in_place, std::forward<Args>(args)...} {
109 }
110
111 template <typename... Args>
112 Result(std::in_place_t,
113 Args&&... args) noexcept(std::is_nothrow_constructible_v<Variant, std::in_place_type_t<V>, Args&&...>)
114 : _result{std::in_place_type<V>, std::forward<Args>(args)...} {
115 }
116
117 Result(std::exception_ptr exception) noexcept
118 : _result{std::in_place_type<std::exception_ptr>, std::move(exception)} {
119 }
120
121 Result(E error) noexcept : _result{std::in_place_type<E>, std::move(error)} {
122 }
123
124 Result(StopTag tag) noexcept : _result{std::in_place_type<E>, tag} {
125 }
126
127 Result() noexcept : _result{std::monostate{}} {
128 }
129
130 template <typename Arg, typename = std::enable_if_t<!is_result_v<std::decay_t<Arg>>, void>>
131 Result& operator=(Arg&& arg) noexcept(std::is_nothrow_assignable_v<Variant, Arg>) {
132 _result = std::forward<Arg>(arg);
133 return *this;
134 }
135
136 [[nodiscard]] explicit operator bool() const noexcept {
137 return State() == ResultState::Value;
138 }
139
140 void Ok() & = delete;
141 void Ok() const&& = delete;
142 void Value() & = delete;
143 void Value() const&& = delete;
144 void Exception() & = delete;
146 void Error() & = delete;
147 void Error() const&& = delete;
148
149 [[nodiscard]] V&& Ok() && {
150 return Get(std::move(*this));
151 }
152 [[nodiscard]] const V& Ok() const& {
153 return Get(*this);
154 }
155
157 return ResultState{static_cast<unsigned char>(_result.index())};
158 }
159
160 [[nodiscard]] V&& Value() && noexcept {
161 return std::get<V>(std::move(_result));
162 }
163 [[nodiscard]] const V& Value() const& noexcept {
164 return std::get<V>(_result);
165 }
166
167 [[nodiscard]] std::exception_ptr&& Exception() && noexcept {
168 return std::get<std::exception_ptr>(std::move(_result));
169 }
170 [[nodiscard]] const std::exception_ptr& Exception() const& noexcept {
171 return std::get<std::exception_ptr>(_result);
172 }
173
174 [[nodiscard]] E&& Error() && noexcept {
175 return std::get<E>(std::move(_result));
176 }
178 return std::get<E>(_result);
179 }
180
181 [[nodiscard]] Variant& Internal() {
182 return _result;
183 }
184
185 private:
186 template <typename R>
187 static decltype(auto) Get(R&& r) {
188 switch (r.State()) {
190 return std::forward<R>(r).Value();
192 std::rethrow_exception(std::forward<R>(r).Exception());
194 throw ResultError{std::forward<R>(r).Error()};
195 default:
196 throw ResultEmpty{};
197 }
198 }
199
200 Variant _result;
201};
202
203extern template class Result<>;
204
205} // namespace yaclib
, invalid state
const Error & Get() const &noexcept
Definition result.hpp:61
ResultError(ResultError &&) noexcept(std::is_nothrow_move_constructible_v< Error >)=default
ResultError(const Error &error) noexcept(std::is_nothrow_copy_constructible_v< Error >)
Definition result.hpp:55
const char * what() const noexcept final
Definition result.hpp:65
Error & Get() &noexcept
Definition result.hpp:58
Encapsulated return value from caller.
Definition result.hpp:90
Result(StopTag tag) noexcept
Definition result.hpp:124
Result & operator=(Result &&other) noexcept(std::is_nothrow_move_assignable_v< Variant >)=default
Result & operator=(const Result &other) noexcept(std::is_nothrow_copy_assignable_v< Variant >)=default
const V & Ok() const &
Definition result.hpp:152
Variant & Internal()
Definition result.hpp:181
Result(Result &&other) noexcept(std::is_nothrow_move_constructible_v< Variant >)=default
const std::exception_ptr & Exception() const &noexcept
Definition result.hpp:170
Result(std::in_place_t, Args &&... args) noexcept(std::is_nothrow_constructible_v< Variant, std::in_place_type_t< V >, Args &&... >)
Definition result.hpp:112
void Ok() &=delete
Result(E error) noexcept
Definition result.hpp:121
void Ok() const &&=delete
E && Error() &&noexcept
Definition result.hpp:174
const E & Error() const &noexcept
Definition result.hpp:177
std::exception_ptr && Exception() &&noexcept
Definition result.hpp:167
Result() noexcept
Definition result.hpp:127
Result & operator=(Arg &&arg) noexcept(std::is_nothrow_assignable_v< Variant, Arg >)
Definition result.hpp:131
Result(std::exception_ptr exception) noexcept
Definition result.hpp:117
ResultState State() const noexcept
Definition result.hpp:156
const V & Value() const &noexcept
Definition result.hpp:163
Result(Args &&... args) noexcept(std::is_nothrow_constructible_v< Variant, std::in_place_type_t< V >, Args &&... >)
Definition result.hpp:107
V && Value() &&noexcept
Definition result.hpp:160
Result(const Result &other) noexcept(std::is_nothrow_copy_constructible_v< Variant >)=default
#define YACLIB_DEFINE_VOID_COMPARE(type)
Definition fwd.hpp:5
typename detail::Head< Args... >::Type head_t
Contract< V, E > MakeContract()
Creates related future and promise.
Definition contract.hpp:25
ResultState
Definition result.hpp:16
const char * what() const noexcept final
Definition result.hpp:78
Default error.
Definition result.hpp:26
constexpr StopError(StopError &&) noexcept=default
constexpr StopError(StopTag) noexcept
Definition result.hpp:27