#pragma once #include "assert.hpp" #include "enum.hpp" #include "tagged_union.hpp" #include "type_traits.hpp" #include "types.hpp" #include #include #include #include #include namespace util { namespace detail { template using nth_type = typename std::tuple_element>::type; template consteval std::size_t locate(std::size_t ind) { return static_cast(-1); } template consteval std::size_t locate(std::size_t ind = 0) { if (std::is_same::value) { return ind; } else { return locate(ind + 1); } } template struct index_of : std::integral_constant>> {}; template inline constexpr std::size_t index_of_v = index_of::value; template struct is_in : std::false_type {}; template struct is_in : std::integral_constant::value || is_in::value> {}; template concept in_types = is_in::value; template inline constexpr auto max_all_inner(T arg) -> T { return arg; } template inline constexpr auto max_all_inner(T arg, Ts... args) -> decltype(max_all_inner(arg)){ return std::max(arg, max_all_inner(args...)); } template inline constexpr auto max_all(Ts... args) -> usize { return max_all_inner(args...); } template class variadic_union { std::vector m_data; std::optional m_type_index; public: variadic_union() : m_data(detail::max_all(sizeof(Ts)...)), m_type_index(std::nullopt) {} template variadic_union(Us&&... args) : m_data(detail::max_all(sizeof(Ts)...)), m_type_index(I) { *reinterpret_cast*>(m_data.data()) = detail::nth_type{std::forward(args)...}; } template requires (std::same_as>) variadic_union(const U& value) : m_data(detail::max_all(sizeof(Ts)...)), m_type_index(I) { *reinterpret_cast*>(m_data.data()) = value; } template requires (std::same_as>) variadic_union(U&& value) : m_data(detail::max_all(sizeof(Ts)...)), m_type_index(I) { *reinterpret_cast*>(m_data.data()) = std::move(value); } template requires (in_types) variadic_union(U&& value) : m_data(detail::max_all(sizeof(Ts)...)), m_type_index(index_of_v) { *reinterpret_cast(m_data.data()) = std::move(value); } template requires (in_types) variadic_union(const U& value) : m_data(detail::max_all(sizeof(Ts)...)), m_type_index(index_of_v) { *reinterpret_cast(m_data.data()) = value; } template constexpr auto get() -> U& { util::assert_eq(m_type_index.value(), index_of_v); return reinterpret_cast(m_data.data()); } }; } // namespace detail #define NTH(Is, Ts) typename detail::nth_type<, Ts...> element_##I; template class TaggedUnion { Tag tag; detail::variadic_union inner; public: template requires (detail::in_types) TaggedUnion(const Tag& tag, const U& value) : tag(tag), inner(detail::variadic_union(value)) {} }; } // namespace util