IceShard 1
A personal game engine project, with development focused on 2D/2.5D games.
Loading...
Searching...
No Matches
expected.hxx
Go to the documentation of this file.
1
3
4#pragma once
5#include <ice/base.hxx>
6#include <ice/build/build.hxx>
7#include <ice/error_codes.hxx>
9#include <type_traits>
10
11namespace ice
12{
13
14 template<typename Value, typename ErrorType = ice::ErrorCode>
16 {
17 public:
18 Expected() noexcept
19 : _state{ 0u }
20 { }
21
22 Expected(ErrorType error) noexcept
23 : _state{ 2u }
24 , _error{ error }
25 {
26 if constexpr (std::is_same_v<ice::ErrorCode, ErrorType>)
27 {
28 ICE_ASSERT_CORE(error == false);
29 }
30 }
31
32 template<typename OtherValue> requires (std::is_convertible_v<OtherValue, Value>)
33 Expected(OtherValue&& value) noexcept
34 : _state{ 1u }
35 , _value{ ice::forward<OtherValue>(value) }
36 {
37 }
38
39 Expected(Expected&& other) noexcept requires (std::is_nothrow_move_constructible_v<Value>)
40 : _state{ other._state } // Don't exchange, we need to destroy the empty value in the old object
41 {
42 if (_state == 1u) // Already checking our state
43 {
44 new (ice::addressof(_value)) Value { ice::forward<Value>(other) };
45 }
46 else
47 {
48 _error = other._error;
49 }
50 }
51
52 template<typename OtherValue> requires (std::is_convertible_v<OtherValue, Value>)
53 auto operator=(OtherValue&& value) noexcept -> Expected& requires (std::is_nothrow_move_assignable_v<Value>)
54 {
55 if (std::exchange(_state, ice::u8(1u)) == 1u)
56 {
57 _value.~Value();
58 }
59
60 new (ice::addressof(_value)) Value { ice::forward<OtherValue>(value) };
61 return *this;
62 }
63
64 auto operator=(ErrorType error) noexcept -> Expected&
65 {
66 if (std::exchange(_state, ice::u8(2u)) == 1u)
67 {
68 _value.~Value();
69 }
70
71 ICE_ASSERT_CORE(error == false); // Errors should not be successes.
72 _error = error;
73 return *this;
74 }
75
76 auto operator=(Expected&& other) noexcept -> Expected& requires (std::is_nothrow_move_assignable_v<Value>)
77 {
78 if (ice::addressof(other) != this)
79 {
80 if (_state == 1u && other._state == 1u) // Already checking our state
81 {
82 _value = ice::move(other._value);
83 }
84 else if (other._state == 1u)
85 {
86 _state = 1u;
87 new (ice::addressof(_value)) Value{ ice::move(other._value) };
88 }
89 else
90 {
91 if (_state == 1u)
92 {
93 _value.~Value();
94 }
95
96 _error = other._error;
97 _state = 2u;
98 }
99 }
100 return *this;
101 }
102
103 ~Expected() noexcept
104 {
105 if (_state == 1u)
106 {
107 _value.~Value();
108 }
109 }
110
111 bool valid() const noexcept { return _state != 0u; }
112 bool succeeded() const noexcept { return _state == 1; }
113 bool failed() const noexcept { return _state == 2; }
114
115 template<typename Self>
116 auto value(this Self&& self) noexcept -> auto&&
117 {
118 ICE_ASSERT_CORE(self._state == 1u);
119 return ice::forward<Self>(self)._value;
120 }
121
122 auto error() const noexcept -> ErrorType
123 {
124 ICE_ASSERT_CORE(_state == 2u);
125 return _error;
126 }
127
128 inline bool operator==(ErrorType error) const noexcept
129 {
130 return _state == 2u && _error == error;
131 }
132
133 inline explicit operator bool() const noexcept
134 {
135 return _state == 1u;
136 }
137
138 inline operator Value&() & noexcept { return this->value(); }
139 inline operator Value&&() && noexcept { return ice::move(*this).value(); }
140 //inline operator Value() const & noexcept { return this->value(); }
141
142 private:
143 union
144 {
145 ErrorType _error;
146 Value _value;
147 };
148
149 ice::u8 _state;
150 };
151
152 template<>
154 {
155 public:
156 Expected() noexcept
157 : _value{ ice::E_Error } // Unknown error if never set
158 { }
159
160 Expected(bool issuccess) noexcept
161 : _value{ issuccess ? ErrorCode{S_Ok} : ErrorCode{E_Fail} }
162 {
163 }
164
166 : _value{ error }
167 {
168 }
169
170 bool valid() const noexcept { return true; }
171
172 auto value() const noexcept -> ice::ErrorCode
173 {
174 return _value;
175 }
176
177 auto error() const noexcept -> ice::ErrorCode
178 {
179 return _value;
180 }
181
182 template<typename ErrorType> requires(std::is_base_of_v<ice::ErrorCode, ErrorType>)
183 inline bool operator==(ErrorType error) const noexcept
184 {
185 return _value == error;
186 }
187
188 inline operator bool() const noexcept
189 {
190 return _value == true;
191 }
192
193 private:
195 };
196
198
199} // namespace ice
200
201template<typename Val>
202struct fmt::formatter<ice::Expected<Val, ice::ErrorCode>>
203{
204 template<typename ParseContext>
205 constexpr auto parse(ParseContext& ctx)
206 {
207 return ctx.begin();
208 }
209
210 template<typename FormatContext>
211 constexpr auto format(ice::Expected<Val, ice::ErrorCode> const& value, FormatContext& ctx) const noexcept
212 {
213 if (value.succeeded())
214 {
215 return fmt::format_to(ctx.out(), "{}", ice::ErrorCode{ ice::S_Ok });
216 }
217 else
218 {
219 return fmt::format_to(ctx.out(), "{}", value.error());
220 }
221 }
222};
#define ICE_ASSERT_CORE(expression)
Definition assert_core.hxx:43
Expected(bool issuccess) noexcept
Definition expected.hxx:160
bool valid() const noexcept
Definition expected.hxx:170
Expected(ice::ErrorCode error) noexcept
Definition expected.hxx:165
Expected() noexcept
Definition expected.hxx:156
auto value() const noexcept -> ice::ErrorCode
Definition expected.hxx:172
auto error() const noexcept -> ice::ErrorCode
Definition expected.hxx:177
Definition expected.hxx:16
ErrorType _error
Definition expected.hxx:145
auto operator=(Expected &&other) noexcept -> Expected &
Definition expected.hxx:76
auto error() const noexcept -> ice::ErrorCode
Definition expected.hxx:122
Expected(Expected &&other) noexcept
Definition expected.hxx:39
bool failed() const noexcept
Definition expected.hxx:113
~Expected() noexcept
Definition expected.hxx:103
bool succeeded() const noexcept
Definition expected.hxx:112
Expected(OtherValue &&value) noexcept
Definition expected.hxx:33
auto value(this Self &&self) noexcept -> auto &&
Definition expected.hxx:116
Expected() noexcept
Definition expected.hxx:18
bool operator==(ErrorType error) const noexcept
Definition expected.hxx:128
Expected(ErrorType error) noexcept
Definition expected.hxx:22
Value _value
Definition expected.hxx:146
bool valid() const noexcept
Definition expected.hxx:111
auto operator=(ErrorType error) noexcept -> Expected &
Definition expected.hxx:64
SPDX-License-Identifier: MIT.
Definition array.hxx:12
static constexpr ice::ErrorCodeError E_Fail
Definition error_codes.hxx:13
static constexpr ice::ErrorCodeError E_Error
Definition error_codes.hxx:14
static constexpr ice::ErrorCodeSuccess S_Ok
Definition error_codes.hxx:10
ice::Expected< ice::ErrorCode > Result
Definition expected.hxx:197
std::uint8_t u8
Definition types.hxx:24
constexpr auto format(ice::Expected< Val, ice::ErrorCode > const &value, FormatContext &ctx) const noexcept
Definition expected.hxx:211
constexpr auto parse(ParseContext &ctx)
Definition expected.hxx:205
Definition error.hxx:19