From 06916f56be8f67bb9df5cc71073139568294c726 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Tue, 18 Apr 2023 19:53:34 +0300 Subject: [PATCH] BAN: Variant now works with references References can be assigned with the set() method. Construction nor assigment operators cannot be used with references to avoid ambiguity with what assignment to reference does. You can set the underlying reference with the set() method and access it with the get() method. The references are stored as pointers to the object under the hood which means that size of a reference is sizeof pointer. --- BAN/include/BAN/Variant.h | 61 +++++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/BAN/include/BAN/Variant.h b/BAN/include/BAN/Variant.h index 423342a0..0522f9fe 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() }; };