#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; } }