Result: Use Option as backend

This commit is contained in:
apio 2022-12-08 16:08:18 +01:00
parent b58eba63f1
commit 406af68a54
Signed by: apio
GPG Key ID: B8A7D06E42258954

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <luna/Check.h> #include <luna/Check.h>
#include <luna/Move.h> #include <luna/Move.h>
#include <luna/Option.h>
#include <luna/PlacementNew.h> #include <luna/PlacementNew.h>
#include <luna/SystemError.h> #include <luna/SystemError.h>
#include <luna/Types.h> #include <luna/Types.h>
@ -18,25 +19,22 @@ struct Error
template <typename T> class Result template <typename T> class Result
{ {
public: public:
Result(const T& value) Result(const T& value) : m_value(value)
{ {
m_storage.store_reference(value);
m_has_value = true; m_has_value = true;
m_has_error = false; m_has_error = false;
} }
Result(T&& value) Result(T&& value) : m_value(value)
{ {
m_storage.store_movable_reference(move(value));
m_has_value = true; m_has_value = true;
m_has_error = false; m_has_error = false;
} }
Result(const Result<T>& other) Result(const Result<T>& other) : m_value(other.m_value)
{ {
if (!other.m_has_error) if (!other.m_has_error)
{ {
m_storage.store_reference(other.m_storage.fetch_reference());
m_has_value = true; m_has_value = true;
m_has_error = false; m_has_error = false;
} }
@ -48,11 +46,10 @@ template <typename T> class Result
} }
} }
Result(Result<T>&& other) Result(Result<T>&& other) : m_value(other.m_value)
{ {
if (!other.m_has_error) if (!other.m_has_error)
{ {
m_storage.store_movable_reference(move(other.m_storage.fetch_reference()));
m_has_value = true; m_has_value = true;
m_has_error = false; m_has_error = false;
} }
@ -64,7 +61,7 @@ template <typename T> class Result
} }
} }
Result(const Error& err) Result(const Error& err) : m_value()
{ {
m_error = err.error; m_error = err.error;
m_has_error = true; m_has_error = true;
@ -102,98 +99,39 @@ template <typename T> class Result
T value() T value()
{ {
expect(has_value(), "Result::value() called on a Result that holds an error"); expect(has_value(), "Result::value() called on a Result that holds an error");
return m_storage.fetch_reference(); return m_value.value();
} }
T expect_value(const char* reason) T expect_value(const char* reason)
{ {
expect(has_value(), reason); expect(has_value(), reason);
return m_storage.fetch_reference(); return move(m_value.release_value());
} }
T value_or(T other) T value_or(const T& other)
{ {
if (has_value()) return m_storage.fetch_reference(); return m_value.value_or(other);
return other;
} }
bool try_set_value(T& ref) bool try_set_value(T& ref)
{ {
if (!has_value()) return false; return m_value.try_set_value(ref);
ref = m_storage.fetch_reference();
return true;
} }
T release_value() T release_value()
{ {
expect(has_value(), "Result::release_value() called on a Result that holds an error"); expect(has_value(), "Result::release_value() called on a Result that holds an error");
T item = m_storage.fetch_reference(); return m_value.release_value();
m_has_value = false;
m_storage.destroy();
return move(item);
} }
T expect_release_value(const char* reason) T expect_release_value(const char* reason)
{ {
expect(has_value(), reason); expect(has_value(), reason);
T item = m_storage.fetch_reference(); return m_value.release_value();
m_has_value = false;
m_storage.destroy();
return move(item);
}
~Result()
{
if (has_value()) m_storage.destroy();
} }
private: private:
struct Storage Option<T> m_value;
{
u8 buffer[sizeof(T)];
T* fetch_ptr()
{
return (T*)buffer;
}
T& fetch_reference()
{
return *fetch_ptr();
}
const T* fetch_ptr() const
{
return (const T*)buffer;
}
const T& fetch_reference() const
{
return *fetch_ptr();
}
void store_ptr(T* ptr)
{
new (buffer) T(*ptr);
}
void store_reference(const T& ref)
{
new (buffer) T(ref);
}
void store_movable_reference(T&& ref)
{
new (buffer) T(ref);
}
void destroy()
{
fetch_reference().~T();
}
};
Storage m_storage;
int m_error; int m_error;
bool m_has_error; bool m_has_error;
bool m_has_value; bool m_has_value;
@ -289,6 +227,6 @@ template <> class Result<void>
#define TRY(expr) \ #define TRY(expr) \
({ \ ({ \
auto _expr_rc = (expr); \ auto _expr_rc = (expr); \
if (_expr_rc.has_error()) return _expr_rc.release_error(); \ if (!_expr_rc.has_value()) return _expr_rc.release_error(); \
_expr_rc.expect_release_value("sanity check failed: has_error() returned false, yet result has no value"); \ _expr_rc.expect_release_value("sanity check failed: has_error() returned false, yet result has no value"); \
}) })