diff options
| author | a1xd <[email protected]> | 2020-07-29 17:36:33 -0400 |
|---|---|---|
| committer | a1xd <[email protected]> | 2020-07-29 17:36:33 -0400 |
| commit | 2ce052e54d55e9029eff00f0985e399fa1eb2c1a (patch) | |
| tree | 532acd06bce802e13380adf2188ccc7b1bd9d39b | |
| parent | Merge pull request #5 from JacobPalecki/WrapperAndGrapher (diff) | |
| download | rawaccel-2ce052e54d55e9029eff00f0985e399fa1eb2c1a.tar.xz rawaccel-2ce052e54d55e9029eff00f0985e399fa1eb2c1a.zip | |
add sum types
| -rw-r--r-- | common/external/nillable.h | 30 | ||||
| -rw-r--r-- | common/external/tagged-union-single.h | 202 |
2 files changed, 232 insertions, 0 deletions
diff --git a/common/external/nillable.h b/common/external/nillable.h new file mode 100644 index 0000000..40cf01c --- /dev/null +++ b/common/external/nillable.h @@ -0,0 +1,30 @@ +inline constexpr struct nil_t {} nil; + +// Requirements: T is default-constructible and trivially-destructible +template<typename T> +struct nillable { + bool has_value = false; + T value; + + nillable() = default; + + nillable(nil_t) : nillable() {} + nillable(const T& v) : has_value(true), value(v) {} + + nillable& operator=(nil_t) { + has_value = false; + return *this; + } + nillable& operator=(const T& v) { + value = v; + has_value = true; + return *this; + } + + const T* operator->() const { return &value; } + T* operator->() { return &value; } + + explicit operator bool() const { return has_value; } +}; + +template<typename T> nillable(T)->nillable<T>; 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<const T> { typedef T type; }; +template< class T > struct remove_cv<volatile T> { typedef T type; }; +template< class T > struct remove_cv<const volatile T> { typedef T type; }; +template< class T > using remove_cv_t = typename remove_cv<T>::type; + +template< class T > struct remove_reference { typedef T type; }; +template< class T > struct remove_reference<T&> { typedef T type; }; +template< class T > struct remove_reference<T&&> { typedef T type; }; +template< class T > using remove_reference_t = typename remove_reference<T>::type; + +template< class T > +struct remove_cvref { + using type = remove_cv_t<remove_reference_t<T>>; +}; +template< class T > using remove_cvref_t = typename remove_cvref<T>::type; + +namespace detail { + +template <class T> struct type_identity { using type = T; }; + +template <class T> +auto try_add_lvalue_reference(int)->type_identity<T&>; +template <class T> +auto try_add_lvalue_reference(...)->type_identity<T>; + +template <class T> +auto try_add_rvalue_reference(int)->type_identity<T&&>; +template <class T> +auto try_add_rvalue_reference(...)->type_identity<T>; + +} // type_traits::detail + +template <class T> struct add_lvalue_reference : decltype(detail::try_add_lvalue_reference<T>(0)) {}; +template< class T > using add_lvalue_reference_t = typename add_lvalue_reference<T>::type; + +template <class T> struct add_rvalue_reference : decltype(detail::try_add_rvalue_reference<T>(0)) {}; +template< class T > using add_rvalue_reference_t = typename add_rvalue_reference<T>::type; + +template <typename T, typename U> inline constexpr bool is_same_v = false; +template <typename T> inline constexpr bool is_same_v<T, T> = true; +template <typename T> inline constexpr bool is_void_v = is_same_v<remove_cv_t<T>, void>; + +} // type_traits + +template<class T> type_traits::add_rvalue_reference_t<T> declval() noexcept; + +template <typename T> +inline constexpr T maxv(const T& a, const T& b) { + return (b < a) ? a : b; +} + +template <typename T> +inline constexpr T minv(const T& a, const T& b) { + return (a < b) ? a : b; +} + +template <typename T> +inline constexpr T clampv(const T& v, const T& lo, const T& hi) { + return minv(maxv(v, lo), hi); +} + +template <typename T> +inline constexpr const T& select_ref(bool pred, const T& t, const T& f) { + return pred ? t : f; +} + +template <typename First, typename... Rest> +inline constexpr size_t max_size_of = maxv(sizeof(First), max_size_of<Rest...>); + +template <typename T> +inline constexpr size_t max_size_of<T> = sizeof(T); + +template <typename First, typename... Rest> +inline constexpr size_t max_align_of = maxv(alignof(First), max_align_of<Rest...>); + +template <typename T> +inline constexpr size_t max_align_of<T> = alignof(T); + +namespace detail { + +template <typename... Ts> +struct b1_index_of_impl { + + template <typename...> + struct idx { + static constexpr size_t value = 0; + }; + + template <typename T, typename First, typename... Rest> + struct idx <T, First, Rest...> { + static constexpr size_t value = []() { + if constexpr (type_traits::is_same_v<T, First>) { + return sizeof...(Ts) - sizeof...(Rest); + } + return idx<T, Rest...>::value; + }(); + }; +}; + +} // detail + +template <typename T, typename First, typename... Rest> +inline constexpr int base1_index_of = +detail::b1_index_of_impl<First, Rest...>::template idx<T, First, Rest...>::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<std::monostate, First, Rest...> +*/ +template <typename First, typename... Rest> +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<typename Visitor> + inline constexpr auto visit(Visitor vis) { + return visit_impl<Visitor, First, Rest...>(vis); + } + + template<typename Visitor> + inline constexpr auto visit(Visitor vis) const { + return visit_impl<Visitor, First, Rest...>(vis); + } + + template<typename T> + static constexpr int id = base1_index_of<T, First, Rest...>; + + int tag = 0; + + struct storage_t { + alignas(max_align_of<First, Rest...>) char bytes[max_size_of<First, Rest...>]; + + template <typename T> + inline constexpr T& as() { + static_assert(id<T> != 0, "tagged_union can not hold T"); + return reinterpret_cast<T&>(bytes); + } + + template <typename T> + inline constexpr const T& as() const { + static_assert(id<T> != 0, "tagged_union can not hold T"); + return reinterpret_cast<const T&>(bytes); + } + + } storage; + + constexpr tagged_union() noexcept = default; + + template<typename T> + inline constexpr tagged_union(const T& val) noexcept { + tag = id<T>; + storage.template as<T>() = val; + } + + template<typename T> + inline constexpr tagged_union& operator=(const T& val) noexcept { + tag = id<T>; + storage.template as<T>() = val; + return *this; + } + +private: + template<typename Visitor, typename T1, typename... TRest> + inline constexpr auto visit_impl(Visitor vis) const { + if (tag == id<T1>) { + return vis(storage.template as<T1>()); + } + if constexpr (sizeof...(TRest) > 0) { + return visit_impl<Visitor, TRest...>(vis); + } + else { + using ReturnType = decltype(vis(declval<First&>())); + if constexpr (!type_traits::is_void_v<ReturnType>) return ReturnType{}; + } + } + + template<typename Visitor, typename T1, typename... TRest> + inline constexpr auto visit_impl(Visitor vis) { + if (tag == id<T1>) { + return vis(storage.template as<T1>()); + } + if constexpr (sizeof...(TRest) > 0) { + return visit_impl<Visitor, TRest...>(vis); + } + else { + using ReturnType = decltype(vis(declval<First&>())); + if constexpr (!type_traits::is_void_v<ReturnType>) return ReturnType{}; + } + } +}; + +template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; }; +template<class... Ts> overloaded(Ts...)->overloaded<Ts...>; |