diff options
author | Steven Le Rouzic <steven.lerouzic@gmail.com> | 2024-04-24 23:13:42 +0200 |
---|---|---|
committer | Steven Le Rouzic <steven.lerouzic@gmail.com> | 2024-04-24 23:13:42 +0200 |
commit | 08eece258ceff7824250454906bff013a7303c28 (patch) | |
tree | b0aff3b1bceeb748dc176545b6cfdd5c68f908b7 | |
parent | 31c220c7178f3a8ae7a803e46d3d568d7ff56848 (diff) |
Some work on StatusOr
-rw-r--r-- | deimos/core/status.h | 134 | ||||
-rw-r--r-- | deimos/core/std.h | 5 | ||||
-rw-r--r-- | main/main.cpp | 14 |
3 files changed, 144 insertions, 9 deletions
diff --git a/deimos/core/status.h b/deimos/core/status.h index 6601ad7..912d4c8 100644 --- a/deimos/core/status.h +++ b/deimos/core/status.h @@ -46,7 +46,7 @@ public: Ref();
}
- Status(Status&& other) : m_rep{std::exchange(other.m_rep, 0U)} {}
+ Status(Status&& other) : m_rep{std::exchange(other.m_rep, CodeToRep(StatusCode::kOk))} {}
Status& operator=(const Status& other)
{
@@ -64,7 +64,7 @@ public: if (this != &other)
{
Unref();
- this->m_rep = std::exchange(other.m_rep, 0U);
+ this->m_rep = std::exchange(other.m_rep, CodeToRep(StatusCode::kOk));
}
return *this;
@@ -106,5 +106,135 @@ inline Status InternalError(StringView message = {}) return Status(StatusCode::kInternal, message);
}
+namespace statusor_internals
+{
+};
+
+template<typename T>
+class StatusOr
+{
+ deimos_StaticAssert(!std::is_constructible_v<T, Status>);
+
+ struct Dummy{};
+
+ Status m_status;
+
+ union {
+ Dummy m_dummy;
+ T m_value;
+ };
+
+ void Clear()
+ {
+ if constexpr (!std::is_trivially_destructible_v<T>)
+ {
+ if (m_status.ok())
+ {
+ (&m_value)->~T();
+ }
+ }
+ }
+
+public:
+ explicit StatusOr() requires std::is_default_constructible_v<T> :
+ m_value{}
+ {}
+
+ template<typename... Args>
+ StatusOr(Args&&... args) requires std::is_constructible_v<T, Args...> : // NOLINT
+ m_value{std::forward<Args>(args)...}
+ {}
+
+ StatusOr(const Status& status) : m_status{status} // NOLINT
+ {
+ if (m_status.ok())
+ {
+ deimos_Panic("Cannot construct a StatusOr from OK");
+ m_status = InternalError("StatusOr constructed from OK");
+ }
+ }
+
+ StatusOr(Status&& status) : m_status{std::move(status)} // NOLINT
+ {
+ if (m_status.ok())
+ {
+ deimos_Panic("Cannot construct a StatusOr from OK");
+ m_status = InternalError("StatusOr constructed from OK");
+ }
+ }
+
+ StatusOr(const StatusOr& other) requires std::is_copy_constructible_v<T> :
+ m_status{other.m_status}
+ {
+ if (m_status.ok())
+ {
+ new (&m_value) T(other.m_value);
+ }
+ }
+
+ StatusOr(StatusOr&& other) requires std::is_move_constructible_v<T> :
+ m_status{std::move(other.m_status)}
+ {
+ if (m_status.ok())
+ {
+ new (&m_value) T(std::move(other.m_value));
+ }
+ }
+
+ ~StatusOr()
+ {
+ Clear();
+ }
+
+ StatusOr& operator=(const StatusOr& other) requires std::is_copy_assignable_v<T>
+ {
+ if (this != &other)
+ {
+ if (m_status.ok() && other.m_status.ok())
+ {
+ m_value = other.m_value;
+ }
+ else if (!m_status.ok() && other.m_status.ok())
+ {
+ new (&m_value) T(other.m_value);
+ }
+ else if (m_status.ok() && !other.m_status.ok())
+ {
+ Clear();
+ }
+ m_status = other.m_status;
+ }
+ return *this;
+ }
+
+ StatusOr& operator=(StatusOr&& other) requires std::is_move_assignable_v<T>
+ {
+ if (this != &other)
+ {
+ if (m_status.ok() && other.m_status.ok())
+ {
+ m_value = std::move(other.m_value);
+ }
+ else if (!m_status.ok() && other.m_status.ok())
+ {
+ new (&m_value) T(std::move(other.m_value));
+ }
+ else if (m_status.ok() && !other.m_status.ok())
+ {
+ Clear();
+ }
+ m_status = other.m_status;
+ }
+ return *this;
+ }
+
+ constexpr bool ok() const { return m_status.ok(); }
+
+ friend void DeimosFormat(IWriter* writer, const StatusOr<T>& status)
+ {
+ DeimosFormat(writer, status.m_status);
+ }
+};
+
} // namespace deimos
diff --git a/deimos/core/std.h b/deimos/core/std.h index 0e0336e..47f161a 100644 --- a/deimos/core/std.h +++ b/deimos/core/std.h @@ -25,6 +25,11 @@ template<typename T> concept unsigned_integral = integral<T> && __is_unsigned(T) template<typename T> constexpr bool is_trivially_destructible_v = __is_trivially_destructible(T);
template<typename T, typename... Args> constexpr bool is_constructible_v = __is_constructible(T, Args...);
+template<typename T> constexpr bool is_default_constructible_v = __is_constructible(T);
+template<typename T> constexpr bool is_copy_constructible_v = __is_constructible(T, const T&);
+template<typename T> constexpr bool is_move_constructible_v = __is_constructible(T, T&&);
+template<typename T> constexpr bool is_copy_assignable_v = __is_assignable(T, const T&);
+template<typename T> constexpr bool is_move_assignable_v = __is_assignable(T, T&&);
template<typename T> constexpr bool is_trivially_copyable_v = __is_trivially_copyable(T);
template<typename U, typename V> constexpr bool _is_same_helper = false;
diff --git a/main/main.cpp b/main/main.cpp index 4fa058c..ca1e063 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -9,7 +9,7 @@ using namespace deimos; static LogApi* log_api;
[[nodiscard]]
-Status CreateInstance(VulkanApi* vk, VkInstance* instance)
+StatusOr<VkInstance> CreateInstance(VulkanApi* vk)
{
const VkApplicationInfo application_info{
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
@@ -42,13 +42,14 @@ Status CreateInstance(VulkanApi* vk, VkInstance* instance) .ppEnabledExtensionNames = extensions,
};
- const VkResult res = vk->CreateInstance(&create_info, nullptr, instance);
+ VkInstance instance{};
+ const VkResult res = vk->CreateInstance(&create_info, nullptr, &instance);
if (res != VK_SUCCESS)
{
- return UnknownError();
+ return InternalError("vkCreateInstance failed");
}
- return {};
+ return instance;
}
int main(int /* argc */, char* /* argv */[])
@@ -61,11 +62,10 @@ int main(int /* argc */, char* /* argv */[]) auto* vulkan_loader_api = api_registry->Get<VulkanLoaderApi>(); auto* vk = vulkan_loader_api->LoadEntry();
- VkInstance instance{};
- const Status s = CreateInstance(vk, &instance);
+ const StatusOr<VkInstance> s = CreateInstance(vk);
if (!s.ok())
{
- log_api->LogError("Couldn't create Vulkan instance: $", s);
+ log_api->LogError("$", s);
}
log_api->LogInfo("OK");
|