#pragma once using size_t = decltype(alignof(char)); namespace type_traits { template< class T > struct remove_cv { typedef T type; }; template< class T > struct remove_cv { typedef T type; }; template< class T > struct remove_cv { typedef T type; }; template< class T > struct remove_cv { typedef T type; }; template< class T > using remove_cv_t = typename remove_cv::type; template< class T > struct remove_reference { typedef T type; }; template< class T > struct remove_reference { typedef T type; }; template< class T > struct remove_reference { typedef T type; }; template< class T > using remove_reference_t = typename remove_reference::type; template< class T > struct remove_cvref { using type = remove_cv_t>; }; template< class T > using remove_cvref_t = typename remove_cvref::type; namespace detail { template struct type_identity { using type = T; }; template auto try_add_lvalue_reference(int)->type_identity; template auto try_add_lvalue_reference(...)->type_identity; template auto try_add_rvalue_reference(int)->type_identity; template auto try_add_rvalue_reference(...)->type_identity; } // type_traits::detail template struct add_lvalue_reference : decltype(detail::try_add_lvalue_reference(0)) {}; template< class T > using add_lvalue_reference_t = typename add_lvalue_reference::type; template struct add_rvalue_reference : decltype(detail::try_add_rvalue_reference(0)) {}; template< class T > using add_rvalue_reference_t = typename add_rvalue_reference::type; template inline constexpr bool is_same_v = false; template inline constexpr bool is_same_v = true; template inline constexpr bool is_void_v = is_same_v, void>; } // type_traits template type_traits::add_rvalue_reference_t declval() noexcept; template inline constexpr T maxv(const T& a, const T& b) { return (b < a) ? a : b; } template inline constexpr T minv(const T& a, const T& b) { return (a < b) ? a : b; } template inline constexpr T clampv(const T& v, const T& lo, const T& hi) { return minv(maxv(v, lo), hi); } template inline constexpr const T& select_ref(bool pred, const T& t, const T& f) { return pred ? t : f; } template inline constexpr size_t max_size_of = maxv(sizeof(First), max_size_of); template inline constexpr size_t max_size_of = sizeof(T); template inline constexpr size_t max_align_of = maxv(alignof(First), max_align_of); template inline constexpr size_t max_align_of = alignof(T); namespace detail { template struct b1_index_of_impl { template struct idx { static constexpr size_t value = 0; }; template struct idx { static constexpr size_t value = []() { if constexpr (type_traits::is_same_v) { return sizeof...(Ts) - sizeof...(Rest); } return idx::value; }(); }; }; } // detail template inline constexpr int base1_index_of = detail::b1_index_of_impl::template idx::value; /* Requirements: Every type is trivially-copyable and is not an array type Can be initialized to an empty state as if by using std::variant */ template struct tagged_union { // Requirements: The return type of Visitor is default-constructible (or void) // Returns a value-initialized object when in an empty or invalid state template inline constexpr auto visit(Visitor vis) { return visit_impl(vis); } template inline constexpr auto visit(Visitor vis) const { return visit_impl(vis); } template static constexpr int id = base1_index_of; int tag = 0; struct storage_t { alignas(max_align_of) char bytes[max_size_of]; template inline constexpr T& as() { static_assert(id != 0, "tagged_union can not hold T"); return reinterpret_cast(bytes); } template inline constexpr const T& as() const { static_assert(id != 0, "tagged_union can not hold T"); return reinterpret_cast(bytes); } } storage; constexpr tagged_union() noexcept = default; template inline constexpr tagged_union(const T& val) noexcept { tag = id; storage.template as() = val; } template inline constexpr tagged_union& operator=(const T& val) noexcept { tag = id; storage.template as() = val; return *this; } private: template inline constexpr auto visit_impl(Visitor vis) const { if (tag == id) { return vis(storage.template as()); } if constexpr (sizeof...(TRest) > 0) { return visit_impl(vis); } else { using ReturnType = decltype(vis(declval())); if constexpr (!type_traits::is_void_v) return ReturnType{}; } } template inline constexpr auto visit_impl(Visitor vis) { if (tag == id) { return vis(storage.template as()); } if constexpr (sizeof...(TRest) > 0) { return visit_impl(vis); } else { using ReturnType = decltype(vis(declval())); if constexpr (!type_traits::is_void_v) return ReturnType{}; } } }; template struct overloaded : Ts... { using Ts::operator()...; }; template overloaded(Ts...)->overloaded;