Add an Option type and get rid of ENONE #19
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include <luna/Check.h>
|
||||
#include <luna/Move.h>
|
||||
#include <luna/Option.h>
|
||||
#include <luna/PlacementNew.h>
|
||||
#include <luna/SystemError.h>
|
||||
#include <luna/Types.h>
|
||||
@ -18,25 +19,22 @@ struct Error
|
||||
template <typename T> class Result
|
||||
{
|
||||
public:
|
||||
Result(const T& value)
|
||||
Result(const T& value) : m_value(value)
|
||||
{
|
||||
m_storage.store_reference(value);
|
||||
m_has_value = true;
|
||||
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_error = false;
|
||||
}
|
||||
|
||||
Result(const Result<T>& other)
|
||||
Result(const Result<T>& other) : m_value(other.m_value)
|
||||
{
|
||||
if (!other.m_has_error)
|
||||
{
|
||||
m_storage.store_reference(other.m_storage.fetch_reference());
|
||||
m_has_value = true;
|
||||
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)
|
||||
{
|
||||
m_storage.store_movable_reference(move(other.m_storage.fetch_reference()));
|
||||
m_has_value = true;
|
||||
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_has_error = true;
|
||||
@ -102,98 +99,39 @@ template <typename T> class Result
|
||||
T value()
|
||||
{
|
||||
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)
|
||||
{
|
||||
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 other;
|
||||
return m_value.value_or(other);
|
||||
}
|
||||
|
||||
bool try_set_value(T& ref)
|
||||
{
|
||||
if (!has_value()) return false;
|
||||
ref = m_storage.fetch_reference();
|
||||
return true;
|
||||
return m_value.try_set_value(ref);
|
||||
}
|
||||
|
||||
T release_value()
|
||||
{
|
||||
expect(has_value(), "Result::release_value() called on a Result that holds an error");
|
||||
T item = m_storage.fetch_reference();
|
||||
m_has_value = false;
|
||||
m_storage.destroy();
|
||||
return move(item);
|
||||
return m_value.release_value();
|
||||
}
|
||||
|
||||
T expect_release_value(const char* reason)
|
||||
{
|
||||
expect(has_value(), reason);
|
||||
T item = m_storage.fetch_reference();
|
||||
m_has_value = false;
|
||||
m_storage.destroy();
|
||||
return move(item);
|
||||
}
|
||||
|
||||
~Result()
|
||||
{
|
||||
if (has_value()) m_storage.destroy();
|
||||
return m_value.release_value();
|
||||
}
|
||||
|
||||
private:
|
||||
struct Storage
|
||||
{
|
||||
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;
|
||||
Option<T> m_value;
|
||||
int m_error;
|
||||
bool m_has_error;
|
||||
bool m_has_value;
|
||||
@ -289,6 +227,6 @@ template <> class Result<void>
|
||||
#define TRY(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"); \
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user