From 3226272a2d49bcbaec72ec735c22b4e0cc2a5c57 Mon Sep 17 00:00:00 2001 From: Jacob Palecki Date: Mon, 27 Jul 2020 19:31:09 -0700 Subject: skeleton --- common/external/tagged-union-single.h | 202 ++++++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 common/external/tagged-union-single.h (limited to 'common/external') diff --git a/common/external/tagged-union-single.h b/common/external/tagged-union-single.h new file mode 100644 index 0000000..bcfc1cf --- /dev/null +++ b/common/external/tagged-union-single.h @@ -0,0 +1,202 @@ +#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; -- cgit v1.2.3