From 10b6d51522e9590a12a748439193c4bc46e0f0b4 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Wed, 22 Feb 2023 01:17:21 +0200 Subject: [PATCH] BAN: implement Variant<> for two types --- BAN/include/BAN/Assert.h | 8 +++ BAN/include/BAN/Variant.h | 147 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 BAN/include/BAN/Assert.h create mode 100644 BAN/include/BAN/Variant.h diff --git a/BAN/include/BAN/Assert.h b/BAN/include/BAN/Assert.h new file mode 100644 index 00000000..24114702 --- /dev/null +++ b/BAN/include/BAN/Assert.h @@ -0,0 +1,8 @@ +#pragma once + +#if defined(__is_kernel) + #include + #define ASSERT(cond) do { if (!(cond)) Kernel::panic("ASSERT("#cond") failed"); } while(false) +#else + #error "NOT IMPLEMENTED" +#endif \ No newline at end of file diff --git a/BAN/include/BAN/Variant.h b/BAN/include/BAN/Variant.h new file mode 100644 index 00000000..cf6d4d20 --- /dev/null +++ b/BAN/include/BAN/Variant.h @@ -0,0 +1,147 @@ +#pragma once + +#include +#include +#include + +namespace BAN +{ + + template + class Variant + { + public: + static_assert(!is_same_v); + + Variant() = default; + + Variant(const T1& value) { set(value); } + Variant(T1&& value) { set(move(value)); } + Variant(const T2& value) { set(value); } + Variant(T2&& value) { set(move(value)); } + + Variant(const Variant& other) { *this = other; } + Variant(Variant&& other) { *this = move(other); } + + ~Variant() { clear(); } + + Variant& operator=(const Variant& other); + Variant& operator=(Variant&& other); + + template + bool is() const; + + template + void set(U&&); + template + void set(const U& value) { set(move(U(value))); } + + template + const U& get() const; + template + U& get(); + + void clear(); + + private: + static constexpr uint32_t m_size = Math::max(sizeof(T1), sizeof(T2)); + uint8_t m_storage[m_size] = {}; + uint32_t m_index = 0; + }; + + template + Variant& Variant::operator=(const Variant& other) + { + clear(); + if (other.is()) + set(other.get()); + if (other.is()) + set(other.get()); + return *this; + } + + template + Variant& Variant::operator=(Variant&& other) + { + clear(); + if (other.is()) + set(move(other.get())); + if (other.is()) + set(move(other.get())); + other.clear(); + return *this; + } + + template + template + bool Variant::is() const + { + if constexpr(is_same_v) + return m_index == 1; + if constexpr(is_same_v) + return m_index == 2; + return false; + } + + + template + template + void Variant::set(U&& value) + { + static_assert(is_same_v || is_same_v); + clear(); + if constexpr(is_same_v) + { + new (m_storage) T1(move(value)); + m_index = 1; + } + if constexpr(is_same_v) + { + new (m_storage) T2(move(value)); + m_index = 2; + } + } + + template + template + const U& Variant::get() const + { + static_assert(is_same_v || is_same_v); + if constexpr(is_same_v) + { + ASSERT(m_index == 1); + return *(T1*)m_storage; + } + if constexpr(is_same_v) + { + ASSERT(m_index == 2); + return *(T2*)m_storage; + } + } + + template + template + U& Variant::get() + { + static_assert(is_same_v || is_same_v); + if constexpr(is_same_v) + { + ASSERT(m_index == 1); + return *(T1*)m_storage; + } + if constexpr(is_same_v) + { + ASSERT(m_index == 2); + return *(T2*)m_storage; + } + } + + template + void Variant::clear() + { + if (is()) ((T1*)m_storage)->~T1(); + if (is()) ((T2*)m_storage)->~T2(); + m_index = 0; + } + +} \ No newline at end of file