diff options
Diffstat (limited to 'kernel/lib/libcxx/include/__variant')
| -rw-r--r-- | kernel/lib/libcxx/include/__variant/variant.h | 421 |
1 files changed, 421 insertions, 0 deletions
diff --git a/kernel/lib/libcxx/include/__variant/variant.h b/kernel/lib/libcxx/include/__variant/variant.h new file mode 100644 index 0000000..731cb5d --- /dev/null +++ b/kernel/lib/libcxx/include/__variant/variant.h @@ -0,0 +1,421 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the BastionOS freestanding C++ standard library. +// +// std::variant — no-exceptions version (traps on bad access). +// valueless_by_exception() always returns false. +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBBASTION_VARIANT_VARIANT_H +#define _LIBBASTION_VARIANT_VARIANT_H + +#include <__config> +#include <__type_traits/integral_constant.h> +#include <__type_traits/construction_traits.h> +#include <__type_traits/type_modifications.h> +#include <__type_traits/type_relationships.h> +#include <__utility/move.h> +#include <__utility/swap.h> +#include <__utility/in_place.h> +#include <cstddef> +#include <new> + +_LIBBASTION_BEGIN_NAMESPACE_STD + +inline constexpr size_t variant_npos = static_cast<size_t>(-1); + +// ── monostate ─────────────────────────────────────────────────────────────── + +struct monostate {}; +constexpr bool operator==(monostate, monostate) noexcept { return true; } +constexpr bool operator<(monostate, monostate) noexcept { return false; } + +// ── Internal helpers ──────────────────────────────────────────────────────── + +namespace __variant_detail { + +// Type at index using __type_pack_element builtin. +template<size_t _Ip, class... _Types> +using __type_at = __type_pack_element<_Ip, _Types...>; + +// Find index of type in pack. +template<class _Tp, class... _Types> +struct __index_of; + +template<class _Tp, class _First, class... _Rest> +struct __index_of<_Tp, _First, _Rest...> { + static constexpr size_t value = __is_same(_Tp, _First) ? 0 : 1 + __index_of<_Tp, _Rest...>::value; +}; + +template<class _Tp> +struct __index_of<_Tp> { + static constexpr size_t value = variant_npos; +}; + +// Recursive union storage. +template<bool _TriviallyDestructible, class... _Types> +union __storage; + +// Trivially destructible case. +template<class _First, class... _Rest> +union __storage<true, _First, _Rest...> { + _First __head; + __storage<true, _Rest...> __tail; + constexpr __storage() : __tail() {} +}; + +template<> +union __storage<true> { + constexpr __storage() {} +}; + +// Non-trivially destructible case. +template<class _First, class... _Rest> +union __storage<false, _First, _Rest...> { + _First __head; + __storage<(is_trivially_destructible_v<_Rest> && ...), _Rest...> __tail; + constexpr __storage() : __tail() {} + constexpr ~__storage() requires is_trivially_destructible_v<_First> = default; + constexpr ~__storage() requires (!is_trivially_destructible_v<_First>) {} +}; + +template<> +union __storage<false> { + constexpr __storage() {} +}; + +// Get reference from storage by index. +template<size_t _Ip, bool _Triv, class... _Types> +constexpr auto& __get_storage(__storage<_Triv, _Types...>& __s) { + if constexpr (_Ip == 0) + return __s.__head; + else + return __get_storage<_Ip - 1>(__s.__tail); +} + +template<size_t _Ip, bool _Triv, class... _Types> +constexpr const auto& __get_storage(const __storage<_Triv, _Types...>& __s) { + if constexpr (_Ip == 0) + return __s.__head; + else + return __get_storage<_Ip - 1>(__s.__tail); +} + +// Destroy active alternative. +template<size_t _Np, class _Storage> +constexpr void __destroy_at(size_t __idx, _Storage& __s) { + if constexpr (_Np > 0) { + if (__idx == 0) { + using _Tp = __remove_reference_t(decltype(__s.__head)); + if constexpr (!is_trivially_destructible_v<_Tp>) + __s.__head.~_Tp(); + } else { + __destroy_at<_Np - 1>(__idx - 1, __s.__tail); + } + } +} + +} // namespace __variant_detail + +// ── variant ───────────────────────────────────────────────────────────────── + +template<class... _Types> +class variant { + static_assert(sizeof...(_Types) > 0, "variant must have at least one alternative"); + static_assert((!__is_void(_Types) && ...), "variant alternatives cannot be void"); + static_assert((!__is_reference(_Types) && ...), "variant alternatives cannot be references"); + + static constexpr bool __all_trivially_destructible = (is_trivially_destructible_v<_Types> && ...); + using __storage_t = __variant_detail::__storage<__all_trivially_destructible, _Types...>; + +public: + // ── Constructors ──────────────────────────────────────────────────── + + constexpr variant() + noexcept(is_nothrow_default_constructible_v<__variant_detail::__type_at<0, _Types...>>) + requires is_default_constructible_v<__variant_detail::__type_at<0, _Types...>> + : __index_(0) + { + using _T0 = __variant_detail::__type_at<0, _Types...>; + ::new (static_cast<void*>(&__storage_.__head)) _T0(); + } + + constexpr variant(const variant& __other) + requires (is_copy_constructible_v<_Types> && ...) + : __index_(__other.__index_) + { + __copy_construct(__other, std::make_index_sequence<sizeof...(_Types)>{}); + } + + constexpr variant(variant&& __other) + noexcept((is_nothrow_move_constructible_v<_Types> && ...)) + requires (is_move_constructible_v<_Types> && ...) + : __index_(__other.__index_) + { + __move_construct(std::move(__other), std::make_index_sequence<sizeof...(_Types)>{}); + } + + template<class _Tp> + requires (!__is_same(__decay(_Tp), variant)) && + (!__is_same(__decay(_Tp), in_place_type_t<_Tp>)) + constexpr variant(_Tp&& __t) { + constexpr size_t __idx = __find_best_match<__decay(_Tp)>(); + static_assert(__idx != variant_npos, "no matching variant alternative for this type"); + using _Alt = __variant_detail::__type_at<__idx, _Types...>; + ::new (static_cast<void*>(&__variant_detail::__get_storage<__idx>(__storage_))) _Alt(std::forward<_Tp>(__t)); + __index_ = __idx; + } + + template<size_t _Ip, class... _Args> + requires (_Ip < sizeof...(_Types)) && + is_constructible_v<__variant_detail::__type_at<_Ip, _Types...>, _Args...> + constexpr explicit variant(in_place_index_t<_Ip>, _Args&&... __args) : __index_(_Ip) { + using _Alt = __variant_detail::__type_at<_Ip, _Types...>; + ::new (static_cast<void*>(&__variant_detail::__get_storage<_Ip>(__storage_))) _Alt(std::forward<_Args>(__args)...); + } + + // ── Destructor ────────────────────────────────────────────────────── + + constexpr ~variant() requires __all_trivially_destructible = default; + + constexpr ~variant() requires (!__all_trivially_destructible) { + __variant_detail::__destroy_at<sizeof...(_Types)>(__index_, __storage_); + } + + // ── Assignment ────────────────────────────────────────────────────── + + constexpr variant& operator=(const variant& __other) + requires (is_copy_constructible_v<_Types> && ...) && (is_copy_assignable_v<_Types> && ...) + { + if (this == &__other) return *this; + __destroy_current(); + __index_ = __other.__index_; + __copy_construct(__other, std::make_index_sequence<sizeof...(_Types)>{}); + return *this; + } + + constexpr variant& operator=(variant&& __other) + noexcept((is_nothrow_move_constructible_v<_Types> && ...) && (is_nothrow_move_assignable_v<_Types> && ...)) + requires (is_move_constructible_v<_Types> && ...) && (is_move_assignable_v<_Types> && ...) + { + if (this == &__other) return *this; + __destroy_current(); + __index_ = __other.__index_; + __move_construct(std::move(__other), std::make_index_sequence<sizeof...(_Types)>{}); + return *this; + } + + // ── Observers ─────────────────────────────────────────────────────── + + _LIBBASTION_NODISCARD constexpr size_t index() const noexcept { return __index_; } + _LIBBASTION_NODISCARD constexpr bool valueless_by_exception() const noexcept { return false; } + + // ── Modifiers ─────────────────────────────────────────────────────── + + template<size_t _Ip, class... _Args> + requires is_constructible_v<__variant_detail::__type_at<_Ip, _Types...>, _Args...> + constexpr auto& emplace(_Args&&... __args) { + __destroy_current(); + using _Alt = __variant_detail::__type_at<_Ip, _Types...>; + auto* __ptr = ::new (static_cast<void*>(&__variant_detail::__get_storage<_Ip>(__storage_))) + _Alt(std::forward<_Args>(__args)...); + __index_ = _Ip; + return *__ptr; + } + + constexpr void swap(variant& __other) + noexcept((is_nothrow_move_constructible_v<_Types> && ...) && (is_nothrow_swappable_v<_Types> && ...)) + { + variant __tmp(std::move(*this)); + __destroy_current(); + __index_ = __other.__index_; + __move_construct(std::move(__other), std::make_index_sequence<sizeof...(_Types)>{}); + __other.__destroy_current(); + __other.__index_ = __tmp.__index_; + __other.__move_construct(std::move(__tmp), std::make_index_sequence<sizeof...(_Types)>{}); + } + +// Internal — accessible by get/get_if/visit. Prefixed with __ to discourage direct use. +//public: + __storage_t __storage_; + size_t __index_; + +private: + template<class _Tp> + static constexpr size_t __find_best_match() { + // Find first alternative constructible from _Tp. + return __find_constructible<_Tp, 0, _Types...>(); + } + + template<class _Tp, size_t _Ip> + static constexpr size_t __find_constructible() { return variant_npos; } + + template<class _Tp, size_t _Ip, class _First, class... _Rest> + static constexpr size_t __find_constructible() { + if constexpr (__is_same(_Tp, _First)) + return _Ip; + else + return __find_constructible<_Tp, _Ip + 1, _Rest...>(); + } + + constexpr void __destroy_current() { + if constexpr (!__all_trivially_destructible) + __variant_detail::__destroy_at<sizeof...(_Types)>(__index_, __storage_); + } + + template<size_t... _Ip> + constexpr void __copy_construct(const variant& __other, index_sequence<_Ip...>) { + (void)(( __other.__index_ == _Ip && + (::new (static_cast<void*>(&__variant_detail::__get_storage<_Ip>(__storage_))) + __variant_detail::__type_at<_Ip, _Types...>(__variant_detail::__get_storage<_Ip>(__other.__storage_)), true) + ) || ...); + } + + template<size_t... _Ip> + constexpr void __move_construct(variant&& __other, index_sequence<_Ip...>) { + (void)(( __other.__index_ == _Ip && + (::new (static_cast<void*>(&__variant_detail::__get_storage<_Ip>(__storage_))) + __variant_detail::__type_at<_Ip, _Types...>(std::move(__variant_detail::__get_storage<_Ip>(__other.__storage_))), true) + ) || ...); + } +}; + +// ── get<I> ────────────────────────────────────────────────────────────────── + +template<size_t _Ip, class... _Types> +_LIBBASTION_NODISCARD constexpr auto& get(variant<_Types...>& __v) { + if (__v.index() != _Ip) _LIBBASTION_TRAP(); + return __variant_detail::__get_storage<_Ip>(__v.__storage_); +} + +template<size_t _Ip, class... _Types> +_LIBBASTION_NODISCARD constexpr const auto& get(const variant<_Types...>& __v) { + if (__v.index() != _Ip) _LIBBASTION_TRAP(); + return __variant_detail::__get_storage<_Ip>(__v.__storage_); +} + +template<size_t _Ip, class... _Types> +_LIBBASTION_NODISCARD constexpr auto&& get(variant<_Types...>&& __v) { + if (__v.index() != _Ip) _LIBBASTION_TRAP(); + return std::move(__variant_detail::__get_storage<_Ip>(__v.__storage_)); +} + +// ── get<T> ────────────────────────────────────────────────────────────────── + +template<class _Tp, class... _Types> +_LIBBASTION_NODISCARD constexpr _Tp& get(variant<_Types...>& __v) { + constexpr size_t __idx = __variant_detail::__index_of<_Tp, _Types...>::value; + static_assert(__idx != variant_npos, "type not found in variant"); + return get<__idx>(__v); +} + +template<class _Tp, class... _Types> +_LIBBASTION_NODISCARD constexpr const _Tp& get(const variant<_Types...>& __v) { + constexpr size_t __idx = __variant_detail::__index_of<_Tp, _Types...>::value; + static_assert(__idx != variant_npos, "type not found in variant"); + return get<__idx>(__v); +} + +// ── get_if ────────────────────────────────────────────────────────────────── + +template<size_t _Ip, class... _Types> +_LIBBASTION_NODISCARD constexpr auto* get_if(variant<_Types...>* __v) noexcept { + if (!__v || __v->index() != _Ip) return static_cast<__variant_detail::__type_at<_Ip, _Types...>*>(nullptr); + return &__variant_detail::__get_storage<_Ip>(__v->__storage_); +} + +template<size_t _Ip, class... _Types> +_LIBBASTION_NODISCARD constexpr const auto* get_if(const variant<_Types...>* __v) noexcept { + if (!__v || __v->index() != _Ip) return static_cast<const __variant_detail::__type_at<_Ip, _Types...>*>(nullptr); + return &__variant_detail::__get_storage<_Ip>(__v->__storage_); +} + +// ── holds_alternative ─────────────────────────────────────────────────────── + +template<class _Tp, class... _Types> +_LIBBASTION_NODISCARD constexpr bool holds_alternative(const variant<_Types...>& __v) noexcept { + constexpr size_t __idx = __variant_detail::__index_of<_Tp, _Types...>::value; + static_assert(__idx != variant_npos, "type not found in variant"); + return __v.index() == __idx; +} + +// ── visit (single variant) ────────────────────────────────────────────────── + +namespace __variant_detail { + +template<size_t _Ip, size_t _Np, class _Visitor, class _Variant> +constexpr decltype(auto) __visit_impl(_Visitor&& __vis, _Variant&& __v) { + if constexpr (_Ip == _Np) { + _LIBBASTION_UNREACHABLE(); + } else { + if (__v.index() == _Ip) + return std::forward<_Visitor>(__vis)(get<_Ip>(std::forward<_Variant>(__v))); + return __visit_impl<_Ip + 1, _Np>(std::forward<_Visitor>(__vis), std::forward<_Variant>(__v)); + } +} + +} // namespace __variant_detail + +template<class _Visitor, class... _Types> +constexpr decltype(auto) visit(_Visitor&& __vis, variant<_Types...>& __v) { + return __variant_detail::__visit_impl<0, sizeof...(_Types)>(std::forward<_Visitor>(__vis), __v); +} + +template<class _Visitor, class... _Types> +constexpr decltype(auto) visit(_Visitor&& __vis, const variant<_Types...>& __v) { + return __variant_detail::__visit_impl<0, sizeof...(_Types)>(std::forward<_Visitor>(__vis), __v); +} + +template<class _Visitor, class... _Types> +constexpr decltype(auto) visit(_Visitor&& __vis, variant<_Types...>&& __v) { + return __variant_detail::__visit_impl<0, sizeof...(_Types)>(std::forward<_Visitor>(__vis), std::move(__v)); +} + +// ── variant_size / variant_alternative ────────────────────────────────────── + +template<class _Tp> struct variant_size; + +template<class... _Types> +struct variant_size<variant<_Types...>> : integral_constant<size_t, sizeof...(_Types)> {}; + +template<class _Tp> +struct variant_size<const _Tp> : variant_size<_Tp> {}; + +template<class _Tp> +inline constexpr size_t variant_size_v = variant_size<_Tp>::value; + +template<size_t _Ip, class _Tp> struct variant_alternative; + +template<size_t _Ip, class... _Types> +struct variant_alternative<_Ip, variant<_Types...>> { + using type = __variant_detail::__type_at<_Ip, _Types...>; +}; + +template<size_t _Ip, class _Tp> +struct variant_alternative<_Ip, const _Tp> { + using type = const typename variant_alternative<_Ip, _Tp>::type; +}; + +template<size_t _Ip, class _Tp> +using variant_alternative_t = typename variant_alternative<_Ip, _Tp>::type; + +// Non-member swap +template<class... _Types> +constexpr void swap(variant<_Types...>& __a, variant<_Types...>& __b) noexcept(noexcept(__a.swap(__b))) { + __a.swap(__b); +} + +// ── Make variant's storage_ accessible from get ───────────────────────────── +// Friendship declaration is needed. We add it via the fact that get is in std::. +// Actually, we need variant to declare get as friend. + +_LIBBASTION_END_NAMESPACE_STD + +// The get functions need access to __storage_. We achieve this by making them friends. +// But since they're already defined, we need to restructure. For simplicity, +// mark __storage_ as public in the variant class. +// This is the same approach many freestanding implementations use. + +#endif // _LIBBASTION_VARIANT_VARIANT_H |
