summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/hle/result.h180
1 files changed, 63 insertions, 117 deletions
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 2c6b24848..29fa4eed2 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -4,11 +4,10 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <new>
8#include <utility>
9#include "common/assert.h" 7#include "common/assert.h"
10#include "common/bit_field.h" 8#include "common/bit_field.h"
11#include "common/common_types.h" 9#include "common/common_types.h"
10#include "common/expected.h"
12 11
13// All the constants in this file come from http://switchbrew.org/index.php?title=Error_codes 12// All the constants in this file come from http://switchbrew.org/index.php?title=Error_codes
14 13
@@ -189,150 +188,97 @@ constexpr ResultCode ResultUnknown(UINT32_MAX);
189template <typename T> 188template <typename T>
190class ResultVal { 189class ResultVal {
191public: 190public:
192 /// Constructs an empty `ResultVal` with the given error code. The code must not be a success 191 constexpr ResultVal() : expected{} {}
193 /// code. 192
194 ResultVal(ResultCode error_code = ResultUnknown) : result_code(error_code) { 193 constexpr ResultVal(ResultCode code) : expected{Common::Unexpected(code)} {}
195 ASSERT(error_code.IsError()); 194
196 } 195 template <typename U>
196 constexpr ResultVal(U&& val) : expected{std::forward<U>(val)} {}
197 197
198 /**
199 * Similar to the non-member function `MakeResult`, with the exception that you can manually
200 * specify the success code. `success_code` must not be an error code.
201 */
202 template <typename... Args> 198 template <typename... Args>
203 [[nodiscard]] static ResultVal WithCode(ResultCode success_code, Args&&... args) { 199 constexpr ResultVal(Args&&... args) : expected{std::in_place, std::forward<Args>(args)...} {}
204 ResultVal<T> result;
205 result.emplace(success_code, std::forward<Args>(args)...);
206 return result;
207 }
208 200
209 ResultVal(const ResultVal& o) noexcept : result_code(o.result_code) { 201 ~ResultVal() = default;
210 if (!o.empty()) {
211 new (&object) T(o.object);
212 }
213 }
214 202
215 ResultVal(ResultVal&& o) noexcept : result_code(o.result_code) { 203 constexpr ResultVal(const ResultVal&) = default;
216 if (!o.empty()) { 204 constexpr ResultVal(ResultVal&&) = default;
217 new (&object) T(std::move(o.object));
218 }
219 }
220 205
221 ~ResultVal() { 206 ResultVal& operator=(const ResultVal&) = default;
222 if (!empty()) { 207 ResultVal& operator=(ResultVal&&) = default;
223 object.~T();
224 }
225 }
226 208
227 ResultVal& operator=(const ResultVal& o) noexcept { 209 [[nodiscard]] constexpr explicit operator bool() const noexcept {
228 if (this == &o) { 210 return expected.has_value();
229 return *this;
230 }
231 if (!empty()) {
232 if (!o.empty()) {
233 object = o.object;
234 } else {
235 object.~T();
236 }
237 } else {
238 if (!o.empty()) {
239 new (&object) T(o.object);
240 }
241 }
242 result_code = o.result_code;
243
244 return *this;
245 } 211 }
246 212
247 ResultVal& operator=(ResultVal&& o) noexcept { 213 [[nodiscard]] constexpr ResultCode Code() const {
248 if (this == &o) { 214 return expected.has_value() ? ResultSuccess : expected.error();
249 return *this;
250 }
251 if (!empty()) {
252 if (!o.empty()) {
253 object = std::move(o.object);
254 } else {
255 object.~T();
256 }
257 } else {
258 if (!o.empty()) {
259 new (&object) T(std::move(o.object));
260 }
261 }
262 result_code = o.result_code;
263
264 return *this;
265 } 215 }
266 216
267 /** 217 [[nodiscard]] constexpr bool Succeeded() const {
268 * Replaces the current result with a new constructed result value in-place. The code must not 218 return expected.has_value();
269 * be an error code.
270 */
271 template <typename... Args>
272 void emplace(ResultCode success_code, Args&&... args) {
273 ASSERT(success_code.IsSuccess());
274 if (!empty()) {
275 object.~T();
276 }
277 new (&object) T(std::forward<Args>(args)...);
278 result_code = success_code;
279 } 219 }
280 220
281 /// Returns true if the `ResultVal` contains an error code and no value. 221 [[nodiscard]] constexpr bool Failed() const {
282 [[nodiscard]] bool empty() const { 222 return !expected.has_value();
283 return result_code.IsError();
284 } 223 }
285 224
286 /// Returns true if the `ResultVal` contains a return value. 225 [[nodiscard]] constexpr T* operator->() {
287 [[nodiscard]] bool Succeeded() const { 226 return std::addressof(expected.value());
288 return result_code.IsSuccess();
289 } 227 }
290 /// Returns true if the `ResultVal` contains an error code and no value. 228
291 [[nodiscard]] bool Failed() const { 229 [[nodiscard]] constexpr const T* operator->() const {
292 return empty(); 230 return std::addressof(expected.value());
293 } 231 }
294 232
295 [[nodiscard]] ResultCode Code() const { 233 [[nodiscard]] constexpr T& operator*() & {
296 return result_code; 234 return *expected;
297 } 235 }
298 236
299 [[nodiscard]] const T& operator*() const { 237 [[nodiscard]] constexpr const T& operator*() const& {
300 return object; 238 return *expected;
301 } 239 }
302 [[nodiscard]] T& operator*() { 240
303 return object; 241 [[nodiscard]] constexpr T&& operator*() && {
242 return *expected;
304 } 243 }
305 [[nodiscard]] const T* operator->() const { 244
306 return &object; 245 [[nodiscard]] constexpr const T&& operator*() const&& {
246 return *expected;
307 } 247 }
308 [[nodiscard]] T* operator->() { 248
309 return &object; 249 [[nodiscard]] constexpr T& Unwrap() & {
250 ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal");
251 return expected.value();
310 } 252 }
311 253
312 /// Returns the value contained in this `ResultVal`, or the supplied default if it is missing. 254 [[nodiscard]] constexpr const T& Unwrap() const& {
313 template <typename U> 255 ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal");
314 [[nodiscard]] T ValueOr(U&& value) const { 256 return expected.value();
315 return !empty() ? object : std::move(value);
316 } 257 }
317 258
318 /// Asserts that the result succeeded and returns a reference to it. 259 [[nodiscard]] constexpr T&& Unwrap() && {
319 [[nodiscard]] T& Unwrap() & {
320 ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal"); 260 ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal");
321 return **this; 261 return std::move(expected.value());
322 } 262 }
323 263
324 [[nodiscard]] T&& Unwrap() && { 264 [[nodiscard]] constexpr const T&& Unwrap() const&& {
325 ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal"); 265 ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal");
326 return std::move(**this); 266 return std::move(expected.value());
267 }
268
269 template <typename U>
270 [[nodiscard]] constexpr T ValueOr(U&& v) const& {
271 return expected.value_or(v);
272 }
273
274 template <typename U>
275 [[nodiscard]] constexpr T ValueOr(U&& v) && {
276 return expected.value_or(v);
327 } 277 }
328 278
329private: 279private:
330 // A union is used to allocate the storage for the value, while allowing us to construct and 280 // TODO: Replace this with std::expected once it is standardized in the STL.
331 // destruct it at will. 281 Common::Expected<T, ResultCode> expected;
332 union {
333 T object;
334 };
335 ResultCode result_code;
336}; 282};
337 283
338/** 284/**
@@ -341,16 +287,16 @@ private:
341 */ 287 */
342template <typename T, typename... Args> 288template <typename T, typename... Args>
343[[nodiscard]] ResultVal<T> MakeResult(Args&&... args) { 289[[nodiscard]] ResultVal<T> MakeResult(Args&&... args) {
344 return ResultVal<T>::WithCode(ResultSuccess, std::forward<Args>(args)...); 290 return ResultVal<T>{std::forward<Args>(args)...};
345} 291}
346 292
347/** 293/**
348 * Deducible overload of MakeResult, allowing the template parameter to be ommited if you're just 294 * Deducible overload of MakeResult, allowing the template parameter to be ommited if you're just
349 * copy or move constructing. 295 * copy or move constructing.
350 */ 296 */
351template <typename Arg> 297template <typename T>
352[[nodiscard]] ResultVal<std::remove_cvref_t<Arg>> MakeResult(Arg&& arg) { 298[[nodiscard]] ResultVal<std::remove_cvref_t<T>> MakeResult(T&& val) {
353 return ResultVal<std::remove_cvref_t<Arg>>::WithCode(ResultSuccess, std::forward<Arg>(arg)); 299 return ResultVal<std::remove_cvref_t<T>>{std::forward<T>(val)};
354} 300}
355 301
356/** 302/**