From 8db26a7350aad53ed73a127f9b8eb6ef15bf0be1 Mon Sep 17 00:00:00 2001 From: Steven Le Rouzic Date: Thu, 11 Apr 2024 23:49:22 +0200 Subject: Implement Status --- deimos/core/BUILD | 2 + deimos/core/allocator.cpp | 4 +- deimos/core/allocator.h | 8 ++-- deimos/core/api_registry.cpp | 2 + deimos/core/base.h | 27 +++++++++++ deimos/core/status.cpp | 70 +++++++++++++++++++++++++++ deimos/core/status.h | 111 +++++++++++++++++++++++++++++++++++++++++++ deimos/core/std.h | 2 + deimos/core/temp_allocator.h | 10 ++++ 9 files changed, 230 insertions(+), 6 deletions(-) create mode 100644 deimos/core/status.cpp create mode 100644 deimos/core/status.h create mode 100644 deimos/core/temp_allocator.h (limited to 'deimos/core') diff --git a/deimos/core/BUILD b/deimos/core/BUILD index 08f1ada..e4bfee8 100644 --- a/deimos/core/BUILD +++ b/deimos/core/BUILD @@ -10,6 +10,7 @@ cc_library( "io.h", "log.h", "os.h", + "status.h", "std.h", "format.h", ], @@ -20,6 +21,7 @@ cc_library( "io.cpp", "log.cpp", "os_win32.cpp", + "status.cpp", ], visibility = ["//:__subpackages__"], ) diff --git a/deimos/core/allocator.cpp b/deimos/core/allocator.cpp index b42861c..cd3de9e 100644 --- a/deimos/core/allocator.cpp +++ b/deimos/core/allocator.cpp @@ -8,8 +8,8 @@ namespace deimos class SystemAllocatorImpl : public IAllocator { public: - gsl::owner Reallocate( - gsl::owner old_ptr, int64_t /* old_size */, int64_t new_size, + void* Reallocate( + void* old_ptr, int64_t /* old_size */, int64_t new_size, MemoryScope /* scope */, const SourceLocation& /* source_location */) override { if (old_ptr == nullptr) diff --git a/deimos/core/allocator.h b/deimos/core/allocator.h index e65f316..8f00610 100644 --- a/deimos/core/allocator.h +++ b/deimos/core/allocator.h @@ -40,7 +40,7 @@ public: constexpr IAllocator* allocator() const { return m_allocator; } [[nodiscard]] - constexpr gsl::owner Allocate( + constexpr void* Allocate( int64_t new_size, const SourceLocation& source_location = {}) { @@ -48,15 +48,15 @@ public: } [[nodiscard]] - gsl::owner Reallocate( - gsl::owner old_ptr, int64_t old_size, int64_t new_size, + void* Reallocate( + void* old_ptr, int64_t old_size, int64_t new_size, const SourceLocation& source_location = {}) { return m_allocator->Reallocate(old_ptr, old_size, new_size, m_scope, source_location); } constexpr void Free( - gsl::owner old_ptr, int64_t old_size, + void* old_ptr, int64_t old_size, const SourceLocation& source_location = {}) { (void)m_allocator->Reallocate(old_ptr, old_size, 0, m_scope, source_location); diff --git a/deimos/core/api_registry.cpp b/deimos/core/api_registry.cpp index 81dabf0..41c0257 100644 --- a/deimos/core/api_registry.cpp +++ b/deimos/core/api_registry.cpp @@ -9,6 +9,7 @@ namespace deimos AllocatorApi* BootstrapAllocatorApi(); void RegisterOsApi(ApiRegistry*); void RegisterLogApi(ApiRegistry*); +void InitializeStatus(ApiRegistry*); struct ApiEntry { @@ -56,6 +57,7 @@ ApiRegistry* InitializeGlobalApiRegistry() api_registry->Set(g_allocator_api); + InitializeStatus(api_registry); RegisterOsApi(api_registry); RegisterLogApi(api_registry); diff --git a/deimos/core/base.h b/deimos/core/base.h index 64d1ed9..1022ae8 100644 --- a/deimos/core/base.h +++ b/deimos/core/base.h @@ -104,5 +104,32 @@ inline Span AsBytes(Span span) return { reinterpret_cast(span.data()), span.size() * (int64_t)sizeof(T) }; } +class StringView +{ + const char* m_begin = nullptr; + int64_t m_size = 0; + +public: + constexpr StringView() = default; + + deimos_DEFAULT_COPY_MOVE(StringView); + ~StringView() = default; + + constexpr StringView(gsl::czstring str) : // NOLINT(*-explicit-conversions) + m_begin{str}, m_size{(int64_t)__builtin_strlen(str)} + {} + + constexpr StringView(const char* begin, int64_t size) : + m_begin{begin}, m_size{size} + {} + + constexpr const char* data() const { return m_begin; } + + constexpr int64_t size() const { return m_size; } +}; + +deimos_StaticAssert(std::is_trivially_destructible_v); +deimos_StaticAssert(std::is_trivially_copyable_v); + } // namespace deimos diff --git a/deimos/core/status.cpp b/deimos/core/status.cpp new file mode 100644 index 0000000..ed1a665 --- /dev/null +++ b/deimos/core/status.cpp @@ -0,0 +1,70 @@ +#include "deimos/core/status.h" + +#include "deimos/core/api_registry.h" +#include "deimos/core/allocator.h" + +static deimos::AllocatorApi* allocator_api; + +namespace deimos +{ + +Status::Status(StatusCode code, StringView message) +{ + if (code == StatusCode::kOk) + { + m_rep = CodeToRep(StatusCode::kOk); + } + else + { + void* ptr = allocator_api->system->Allocate((int64_t)sizeof(StatusRep) + message.size() + 1); + auto* rep = new(ptr) StatusRep; + + char* message_ptr = (char*)ptr + sizeof(StatusRep); // NOLINT + MemoryCopy(message_ptr, message.data(), message.size()); + message_ptr[message.size()] = '\0'; // NOLINT + + rep->ref_count = 1; + rep->code = code; + rep->message = StringView(message_ptr, message.size()); + + m_rep = std::bit_cast(rep); + Ensures((m_rep & 1U) == 0); + } +} + +void Status::Ref() const +{ + if (!IsInline()) + { + auto* rep = std::bit_cast(m_rep); + + Expects(rep->ref_count > 0); + rep->ref_count += 1; + } +} + +void Status::Unref() const +{ + if (!IsInline()) + { + auto* rep = std::bit_cast(m_rep); + + Expects(rep->ref_count > 0); + rep->ref_count -= 1; + + if (rep->ref_count == 0) + { + deimos_StaticAssert(std::is_trivially_destructible_v); + allocator_api->system->Free( + rep, (int64_t)sizeof(StatusRep) + rep->message.size() + 1); + } + } +} + +void InitializeStatus(ApiRegistry* api_registry) +{ + allocator_api = api_registry->Get(); +} + +} // namespace deimos + diff --git a/deimos/core/status.h b/deimos/core/status.h new file mode 100644 index 0000000..f866182 --- /dev/null +++ b/deimos/core/status.h @@ -0,0 +1,111 @@ +#pragma once + +#include "deimos/core/base.h" + +namespace deimos +{ + +enum class StatusCode : uint32_t +{ + kOk = 0, + kUnknown, + kInvalidArgument, + kUnimplemented, + kInternal, +}; + +struct StatusRep +{ + // @Todo Make this atomic + int32_t ref_count{}; + StatusCode code{}; + StringView message; +}; + +class Status +{ + uintptr_t m_rep; + + constexpr bool IsInline() const + { + return (m_rep & 1U) == 1U; + } + + static constexpr uintptr_t CodeToRep(StatusCode code) + { + return ((uint32_t)code << 1U) | 1U; + } + + void Ref() const; + void Unref() const; + +public: + constexpr Status() : Status(StatusCode::kOk) {} + constexpr explicit Status(StatusCode code) : m_rep{CodeToRep(code)} {} + Status(StatusCode code, StringView message); + + Status(const Status& other) : m_rep{other.m_rep} + { + Ref(); + } + + Status(Status&& other) : m_rep{std::exchange(other.m_rep, 0U)} {} + + Status& operator=(const Status& other) + { + if (this != &other) + { + Unref(); + this->m_rep = other.m_rep; + Ref(); + } + return *this; + } + + Status& operator=(Status&& other) + { + if (this != &other) + { + Unref(); + this->m_rep = std::exchange(other.m_rep, 0U); + + } + return *this; + } + + ~Status() + { + Unref(); + } + + constexpr bool ok() const { return m_rep == CodeToRep(StatusCode::kOk); } + + StatusCode code() const + { + if (IsInline()) { return (StatusCode)(m_rep >> 1U); } + return std::bit_cast(m_rep)->code; + } +}; + +inline Status UnknownError(StringView message = {}) +{ + return Status(StatusCode::kUnknown, message); +} + +inline Status InvalidArgumentError(StringView message = {}) +{ + return Status(StatusCode::kInvalidArgument, message); +} + +inline Status UnimplementedError(StringView message = {}) +{ + return Status(StatusCode::kUnimplemented, message); +} + +inline Status InternalError(StringView message = {}) +{ + return Status(StatusCode::kInternal, message); +} + +} // namespace deimos + diff --git a/deimos/core/std.h b/deimos/core/std.h index 42bedbe..4bb2983 100644 --- a/deimos/core/std.h +++ b/deimos/core/std.h @@ -11,8 +11,10 @@ using int32_t = signed int; using int64_t = signed long long; using size_t = uint64_t; +using uintptr_t = uint64_t; static_assert(sizeof(size_t) == sizeof(void*), "size_t should be pointer size"); +static_assert(sizeof(uintptr_t) == sizeof(void*), "size_t should be pointer size"); namespace std { diff --git a/deimos/core/temp_allocator.h b/deimos/core/temp_allocator.h new file mode 100644 index 0000000..4f80192 --- /dev/null +++ b/deimos/core/temp_allocator.h @@ -0,0 +1,10 @@ +#pragma once + +#include "deimos/core/base.h" +#include "deimos/core/id_name.h" + +namespace deimos +{ + +} // namespace deimos + -- cgit