diff --git a/BAN/include/BAN/Variant.h b/BAN/include/BAN/Variant.h index 423342a01a..0522f9febc 100644 --- a/BAN/include/BAN/Variant.h +++ b/BAN/include/BAN/Variant.h @@ -11,14 +11,19 @@ namespace BAN { template - constexpr size_t max_size() { return sizeof(T); } - template - constexpr size_t max_size() { return sizeof(T0) > sizeof(T1) ? max_size() : max_size(); } + constexpr size_t size_ref_as_ptr() { return is_lvalue_reference_v ? sizeof(remove_reference_t*) : sizeof(T); } + template + constexpr size_t align_ref_as_ptr() { return is_lvalue_reference_v ? alignof(remove_reference_t*) : alignof(T); } template - constexpr size_t max_align() { return alignof(T); } + constexpr size_t max_size_ref_as_ptr() { return size_ref_as_ptr(); } template - constexpr size_t max_align() { return alignof(T0) > alignof(T1) ? max_align() : max_align(); } + constexpr size_t max_size_ref_as_ptr() { return size_ref_as_ptr() > size_ref_as_ptr() ? max_size_ref_as_ptr() : max_size_ref_as_ptr(); } + + template + constexpr size_t max_align_ref_as_ptr() { return align_ref_as_ptr(); } + template + constexpr size_t max_align_ref_as_ptr() { return align_ref_as_ptr() > align_ref_as_ptr() ? max_align_ref_as_ptr() : max_align_ref_as_ptr(); } template constexpr size_t index() @@ -35,7 +40,9 @@ namespace BAN void destruct(size_t index, uint8_t* data) { if (index == 0) - reinterpret_cast(data)->~T(); + if constexpr(!is_lvalue_reference_v) + reinterpret_cast(data)->~T(); + else; else if constexpr(sizeof...(Ts) > 0) destruct(index - 1, data); else @@ -89,7 +96,7 @@ namespace BAN } template - requires (!is_lvalue_reference_v && ...) + requires (!is_const_v && ...) class Variant { private: @@ -114,14 +121,14 @@ namespace BAN } template - Variant(T&& value) requires (can_have()) + Variant(T&& value) requires (can_have() && !is_lvalue_reference_v) : m_index(detail::index()) { new (m_storage) T(move(value)); } template - Variant(const T& value) requires (can_have()) + Variant(const T& value) requires (can_have() && !is_lvalue_reference_v) : m_index(detail::index()) { new (m_storage) T(value); @@ -164,14 +171,14 @@ namespace BAN } template - Variant& operator=(T&& value) requires (can_have()) + Variant& operator=(T&& value) requires (can_have() && !is_lvalue_reference_v) { *this = Variant(move(value)); return *this; } template - Variant& operator=(const T& value) requires (can_have()) + Variant& operator=(const T& value) requires (can_have() && !is_lvalue_reference_v) { *this = Variant(value); return *this; @@ -184,7 +191,7 @@ namespace BAN } template - void set(T&& value) requires (can_have()) + void set(T&& value) requires (can_have() && !is_lvalue_reference_v) { if (has()) get() = move(value); @@ -197,7 +204,7 @@ namespace BAN } template - void set(const T& value) requires (can_have()) + void set(const T& value) requires (can_have() && !is_lvalue_reference_v) { if (has()) get() = value; @@ -210,19 +217,41 @@ namespace BAN } template - T& get() requires (can_have()) + void set(T value) requires (can_have() && is_lvalue_reference_v) + { + clear(); + m_index = detail::index(); + *reinterpret_cast**>(m_storage) = &value; + } + + template + T& get() requires (can_have() && !is_lvalue_reference_v) { ASSERT(has()); return *reinterpret_cast(m_storage); } template - const T& get() const requires (can_have()) + const T& get() const requires (can_have() && !is_lvalue_reference_v) { ASSERT(has()); return *reinterpret_cast(m_storage); } + template + T get() requires (can_have() && is_lvalue_reference_v) + { + ASSERT(has()); + return **reinterpret_cast**>(m_storage); + } + + template + const T get() const requires (can_have() && is_lvalue_reference_v) + { + ASSERT(has()); + return **reinterpret_cast**>(m_storage); + } + void clear() { if (m_index != invalid_index()) @@ -233,7 +262,7 @@ namespace BAN } private: - alignas(detail::max_align()) uint8_t m_storage[detail::max_size()] {}; + alignas(detail::max_align_ref_as_ptr()) uint8_t m_storage[detail::max_size_ref_as_ptr()] {}; size_t m_index { invalid_index() }; };