diff --git a/kernel/src/memory/Heap.cpp b/kernel/src/memory/Heap.cpp index f47fd530..10f558aa 100644 --- a/kernel/src/memory/Heap.cpp +++ b/kernel/src/memory/Heap.cpp @@ -94,14 +94,14 @@ static usize get_fair_offset_to_split_at(HeapBlock* block, usize min) return available + block->req_size; } -static Result split(HeapBlock* block, usize size) +static Option split(HeapBlock* block, usize size) { const usize available = space_available(block); // How much space can we steal from this block? const usize old_size = 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))) - return err(ENONE); // This block hasn't got enough free space to hold the requested size. + return {}; // 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)); block->full_size = offset; // shrink the old block to fit this offset diff --git a/kernel/src/thread/Scheduler.cpp b/kernel/src/thread/Scheduler.cpp index 2413f37b..03e2be9c 100644 --- a/kernel/src/thread/Scheduler.cpp +++ b/kernel/src/thread/Scheduler.cpp @@ -102,7 +102,7 @@ namespace Scheduler if (old->is_idle()) { auto maybe_last = g_threads.last(); - if (maybe_last.has_error()) // No threads!! + if (!maybe_last.has_value()) // No threads!! return &g_idle; g_current = old = maybe_last.value(); } @@ -111,7 +111,7 @@ namespace Scheduler do { auto maybe_next = g_threads.next(g_current); - if (maybe_next.has_error()) g_current = g_threads.expect_first(); + if (!maybe_next.has_value()) g_current = g_threads.expect_first(); else g_current = maybe_next.value(); diff --git a/luna/include/luna/LinkedList.h b/luna/include/luna/LinkedList.h index 698e5a9a..47a07cbf 100644 --- a/luna/include/luna/LinkedList.h +++ b/luna/include/luna/LinkedList.h @@ -1,9 +1,9 @@ #pragma once -#include +#include -template inline Result nonnull_or_error(T* ptr) +template inline Option nonnull_or_error(T* ptr) { - if (ptr == nullptr) return err(ENONE); + if (ptr == nullptr) return {}; else return ptr; } @@ -101,7 +101,7 @@ template class DoublyLinkedList return ptr; } - Result first() + Option first() { return nonnull_or_error((T*)m_start_node); } @@ -111,7 +111,7 @@ template class DoublyLinkedList return first().value(); } - Result last() + Option last() { return nonnull_or_error((T*)m_end_node); } @@ -121,12 +121,12 @@ template class DoublyLinkedList return last().value(); } - Result next(T* item) + Option next(T* item) { return nonnull_or_error((T*)extract_node(item)->get_next()); } - Result previous(T* item) + Option previous(T* item) { return nonnull_or_error((T*)extract_node(item)->get_last()); } diff --git a/luna/include/luna/Option.h b/luna/include/luna/Option.h new file mode 100644 index 00000000..49d58ee7 --- /dev/null +++ b/luna/include/luna/Option.h @@ -0,0 +1,139 @@ +#pragma once +#include +#include +#include + +template 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& other) + { + m_has_value = other.has_value(); + if (m_has_value) { m_storage.store_reference(other.m_storage.fetch_reference()); } + } + + Option(Option&& 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}; +}; \ No newline at end of file diff --git a/luna/include/luna/Result.h b/luna/include/luna/Result.h index a923bff4..1b93b37e 100644 --- a/luna/include/luna/Result.h +++ b/luna/include/luna/Result.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include #include #include @@ -18,25 +19,22 @@ struct Error template 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& other) + Result(const Result& 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 class Result } } - Result(Result&& other) + Result(Result&& 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 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 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 m_value; int m_error; bool m_has_error; bool m_has_value; @@ -289,6 +227,6 @@ template <> class Result #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"); \ }) diff --git a/luna/include/luna/SystemError.h b/luna/include/luna/SystemError.h index 16bef760..0c952b57 100644 --- a/luna/include/luna/SystemError.h +++ b/luna/include/luna/SystemError.h @@ -52,8 +52,7 @@ #define ETIMEDOUT 110 // Connection timed out #define EALREADY 114 // Operation already in progress -// These ones are Luna-specific. +// This one is Luna-specific. #define EFIXME 342 // Functionality not yet implemented -#define ENONE 343 // Internal or insignificant error const char* error_string(int error); \ No newline at end of file diff --git a/luna/src/SystemError.cpp b/luna/src/SystemError.cpp index 27aa0853..2e1f63ad 100644 --- a/luna/src/SystemError.cpp +++ b/luna/src/SystemError.cpp @@ -55,7 +55,6 @@ const char* error_string(int error) case ETIMEDOUT: return "Connection timed out"; case EALREADY: return "Operation already in progress"; case EFIXME: return "Functionality not yet implemented"; - case ENONE: return "Internal or insignificant error"; default: return "Unknown error"; } } \ No newline at end of file