summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteven Le Rouzic <steven.lerouzic@gmail.com>2024-04-24 23:13:42 +0200
committerSteven Le Rouzic <steven.lerouzic@gmail.com>2024-04-24 23:13:42 +0200
commit08eece258ceff7824250454906bff013a7303c28 (patch)
treeb0aff3b1bceeb748dc176545b6cfdd5c68f908b7
parent31c220c7178f3a8ae7a803e46d3d568d7ff56848 (diff)
Some work on StatusOr
-rw-r--r--deimos/core/status.h134
-rw-r--r--deimos/core/std.h5
-rw-r--r--main/main.cpp14
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");