Compare commits

..

No commits in common. "b9f3d3c349bcf1d68e5a7be990e0ee568cf0a41b" and "6cee208e6262007941da9daf8801c4f8b28dfe47" have entirely different histories.

7 changed files with 91 additions and 166 deletions

View File

@ -94,14 +94,14 @@ static usize get_fair_offset_to_split_at(HeapBlock* block, usize min)
return available + block->req_size; return available + block->req_size;
} }
static Option<HeapBlock*> split(HeapBlock* block, usize size) static Result<HeapBlock*> split(HeapBlock* block, usize size)
{ {
const usize available = space_available(block); // How much space can we steal from this block? const usize available = space_available(block); // How much space can we steal from this block?
const usize old_size = const usize old_size =
block->full_size; // Save the old value of this variable since we are going to use it after modifying it block->full_size; // Save the old value of this variable since we are going to use it after modifying it
if (available < (size + sizeof(HeapBlock))) if (available < (size + sizeof(HeapBlock)))
return {}; // This block hasn't got enough free space to hold the requested size. return err(ENONE); // This block hasn't got enough free space to hold the requested size.
const usize offset = get_fair_offset_to_split_at(block, size + sizeof(HeapBlock)); const usize offset = get_fair_offset_to_split_at(block, size + sizeof(HeapBlock));
block->full_size = offset; // shrink the old block to fit this offset block->full_size = offset; // shrink the old block to fit this offset

View File

@ -102,7 +102,7 @@ namespace Scheduler
if (old->is_idle()) if (old->is_idle())
{ {
auto maybe_last = g_threads.last(); auto maybe_last = g_threads.last();
if (!maybe_last.has_value()) // No threads!! if (maybe_last.has_error()) // No threads!!
return &g_idle; return &g_idle;
g_current = old = maybe_last.value(); g_current = old = maybe_last.value();
} }
@ -111,7 +111,7 @@ namespace Scheduler
do { do {
auto maybe_next = g_threads.next(g_current); auto maybe_next = g_threads.next(g_current);
if (!maybe_next.has_value()) g_current = g_threads.expect_first(); if (maybe_next.has_error()) g_current = g_threads.expect_first();
else else
g_current = maybe_next.value(); g_current = maybe_next.value();

View File

@ -1,9 +1,9 @@
#pragma once #pragma once
#include <luna/Option.h> #include <luna/Result.h>
template <typename T> inline Option<T*> nonnull_or_error(T* ptr) template <typename T> inline Result<T*> nonnull_or_error(T* ptr)
{ {
if (ptr == nullptr) return {}; if (ptr == nullptr) return err(ENONE);
else else
return ptr; return ptr;
} }
@ -101,7 +101,7 @@ template <typename T> class DoublyLinkedList
return ptr; return ptr;
} }
Option<T*> first() Result<T*> first()
{ {
return nonnull_or_error((T*)m_start_node); return nonnull_or_error((T*)m_start_node);
} }
@ -111,7 +111,7 @@ template <typename T> class DoublyLinkedList
return first().value(); return first().value();
} }
Option<T*> last() Result<T*> last()
{ {
return nonnull_or_error((T*)m_end_node); return nonnull_or_error((T*)m_end_node);
} }
@ -121,12 +121,12 @@ template <typename T> class DoublyLinkedList
return last().value(); return last().value();
} }
Option<T*> next(T* item) Result<T*> next(T* item)
{ {
return nonnull_or_error((T*)extract_node(item)->get_next()); return nonnull_or_error((T*)extract_node(item)->get_next());
} }
Option<T*> previous(T* item) Result<T*> previous(T* item)
{ {
return nonnull_or_error((T*)extract_node(item)->get_last()); return nonnull_or_error((T*)extract_node(item)->get_last());
} }

View File

@ -1,139 +0,0 @@
#pragma once
#include <luna/Check.h>
#include <luna/Move.h>
#include <luna/PlacementNew.h>
template <typename T> class Option
{
public:
Option(const T& value)
{
m_storage.store_reference(value);
m_has_value = true;
}
Option(T&& value)
{
m_storage.store_moved_reference(move(value));
m_has_value = true;
}
Option(const Option<T>& other)
{
m_has_value = other.has_value();
if (m_has_value) { m_storage.store_reference(other.m_storage.fetch_reference()); }
}
Option(Option<T>&& other)
{
m_has_value = other.has_value();
other.m_has_value = false;
if (m_has_value) { m_storage.store_moved_reference(move(other.m_storage.fetch_reference())); }
}
Option()
{
m_has_value = false;
}
bool has_value() const
{
return m_has_value;
}
T value() const
{
expect(has_value(), "Option::value called on an empty Option");
return m_storage.fetch_reference();
}
T release_value()
{
expect(has_value(), "Option::release_value called on an empty Option");
T item = m_storage.fetch_reference();
m_has_value = false;
m_storage.destroy();
return move(item);
}
T value_or(const T& other) const
{
if (has_value()) return m_storage.fetch_reference();
return other;
}
bool try_set_value(T& ref) const
{
if (!has_value()) return false;
ref = m_storage.fetch_reference();
return true;
}
~Option()
{
if (has_value()) m_storage.destroy();
}
struct ErrorHandle
{
private:
explicit ErrorHandle()
{
}
};
Option(ErrorHandle)
{
m_has_value = false;
}
// For compatibility with TRY()
ErrorHandle release_error()
{
expect(!has_value(), "Option::release_error called on a non-empty Option");
return ErrorHandle{};
}
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_reference(const T& ref)
{
new (buffer) T(ref);
}
void store_moved_reference(T&& ref)
{
new (buffer) T(ref);
}
void destroy()
{
fetch_reference().~T();
}
};
Storage m_storage;
bool m_has_value{false};
};

View File

@ -1,7 +1,6 @@
#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>
@ -19,22 +18,25 @@ struct Error
template <typename T> class Result template <typename T> class Result
{ {
public: public:
Result(const T& value) : m_value(value) Result(const T& 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) : m_value(value) Result(T&& 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) : m_value(other.m_value) Result(const Result<T>& other)
{ {
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;
} }
@ -46,10 +48,11 @@ template <typename T> class Result
} }
} }
Result(Result<T>&& other) : m_value(other.m_value) Result(Result<T>&& other)
{ {
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;
} }
@ -61,7 +64,7 @@ template <typename T> class Result
} }
} }
Result(const Error& err) : m_value() Result(const Error& err)
{ {
m_error = err.error; m_error = err.error;
m_has_error = true; m_has_error = true;
@ -99,39 +102,98 @@ 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_value.value(); return m_storage.fetch_reference();
} }
T expect_value(const char* reason) T expect_value(const char* reason)
{ {
expect(has_value(), reason); expect(has_value(), reason);
return move(m_value.release_value()); return m_storage.fetch_reference();
} }
T value_or(const T& other) T value_or(T other)
{ {
return m_value.value_or(other); if (has_value()) return m_storage.fetch_reference();
return other;
} }
bool try_set_value(T& ref) bool try_set_value(T& ref)
{ {
return m_value.try_set_value(ref); if (!has_value()) return false;
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");
return m_value.release_value(); T item = m_storage.fetch_reference();
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);
return m_value.release_value(); T item = m_storage.fetch_reference();
m_has_value = false;
m_storage.destroy();
return move(item);
}
~Result()
{
if (has_value()) m_storage.destroy();
} }
private: private:
Option<T> m_value; 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;
int m_error; int m_error;
bool m_has_error; bool m_has_error;
bool m_has_value; bool m_has_value;
@ -227,6 +289,6 @@ template <> class Result<void>
#define TRY(expr) \ #define TRY(expr) \
({ \ ({ \
auto _expr_rc = (expr); \ auto _expr_rc = (expr); \
if (!_expr_rc.has_value()) return _expr_rc.release_error(); \ if (_expr_rc.has_error()) 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"); \
}) })

View File

@ -52,7 +52,8 @@
#define ETIMEDOUT 110 // Connection timed out #define ETIMEDOUT 110 // Connection timed out
#define EALREADY 114 // Operation already in progress #define EALREADY 114 // Operation already in progress
// This one is Luna-specific. // These ones are Luna-specific.
#define EFIXME 342 // Functionality not yet implemented #define EFIXME 342 // Functionality not yet implemented
#define ENONE 343 // Internal or insignificant error
const char* error_string(int error); const char* error_string(int error);

View File

@ -55,6 +55,7 @@ const char* error_string(int error)
case ETIMEDOUT: return "Connection timed out"; case ETIMEDOUT: return "Connection timed out";
case EALREADY: return "Operation already in progress"; case EALREADY: return "Operation already in progress";
case EFIXME: return "Functionality not yet implemented"; case EFIXME: return "Functionality not yet implemented";
case ENONE: return "Internal or insignificant error";
default: return "Unknown error"; default: return "Unknown error";
} }
} }