Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #ifndef VARIANT_H
- #define VARIANT_H
- #include <iostream>
- #include <utility>
- #include <typeinfo>
- #include <type_traits>
- #include <functional>
- #include "storage.h"
- #include "util.h"
- /////////////////////////////////////////////////////// ALTERNATIVE
- template<typename A, typename ... As>
- struct variant;
- template<size_t N, typename A>
- struct variant_alternative;
- template<size_t N, typename A, typename ... As>
- struct variant_alternative<N, variant<A, As...>> {
- using type = typename variant_alternative<N - 1, variant<As...>>::type;
- };
- template<typename A, typename ... As>
- struct variant_alternative<0, variant<A, As...>> {
- using type = A;
- };
- template <size_t N, typename A>
- using variant_alternative_t = typename variant_alternative<N, A>::type;
- struct empty;
- template<size_t N, typename ... As>
- struct variant_alternative<N, variant<As...>> {
- using type = empty;
- };
- template <typename ... As>
- inline const size_t variant_size_v = sizeof ... (As);
- template<typename U, typename ... Ts>
- inline const bool is_unique_v = count_type<U, Ts...>::value <= 1;
- template<typename T>
- struct single_type {
- static T f(T);
- };
- template<typename T, typename ... Ts>
- struct select_type : single_type<T>, select_type<Ts...> {
- using select_type<Ts...>::f;
- using single_type<T>::f;
- };
- template<typename T>
- struct select_type<T> : single_type<T> {
- using single_type<T>::f;
- };
- template<typename U, typename T, typename ... Ts>
- using select_type_t = decltype(select_type<T, Ts...>::f(std::declval<U>()));
- template<typename T>
- struct is_in_place_index_specialization {
- static const bool value = false;
- };
- template<size_t N>
- struct is_in_place_index_specialization<std::in_place_index_t<N>> {
- static const bool value = true;
- };
- class bad_variant_access : std::exception {};
- template <size_t N, typename ... Ts>
- decltype(auto) get(variant<Ts...>& v) {
- if (v.index() != N) {
- throw bad_variant_access();
- }
- return get_storage_data(pos<N>(), v.get_storage());
- }
- template <size_t N, typename ... Ts>
- variant_alternative_t<N, variant<Ts...>>&& get(variant<Ts...>&& v) {
- if (v.index() != N) {
- throw bad_variant_access();
- }
- return get_storage_data(pos<N>(), std::move(v).get_storage());
- }
- template <size_t N, typename ... Ts>
- decltype(auto) get(const variant<Ts...> & v) {
- if (v.index() != N) {
- throw bad_variant_access();
- }
- return get_storage_data(pos<N>(), v.get_storage());
- }
- template <size_t N, typename ... Ts>
- decltype(auto) get(const variant<Ts...>&& v) {
- if (v.index() != N) {
- throw bad_variant_access();
- }
- return get_storage_data(pos<N>(), std::move(v).get_storage());
- }
- template <typename T, typename ... Ts,
- size_t N = get_type_index<T, Ts...>::value>
- decltype(auto) get(variant<Ts...>& v) {
- return get<N>(v);
- }
- template <typename T, typename ... Ts,
- size_t N = get_type_index<T, Ts...>::value>
- decltype(auto) get(variant<Ts...>&& v) {
- return get<N>(std::move(v));
- }
- template <typename T, typename ... Ts,
- size_t N = get_type_index<T, Ts...>::value>
- decltype(auto) get(variant<Ts...> const& v) {
- return get<N>(v);
- }
- template <typename T, typename ... Ts,
- size_t N = get_type_index<T, Ts...>::value>
- decltype(auto) get(variant<Ts...> const&& v) {
- return get<N>(std::move(v));
- }
- template<typename T0, typename... Ts>
- struct variant: copy_assignable_storage_t<T0, Ts...> {
- private:
- using data = copy_assignable_storage_t<T0, Ts...>;
- using data::valueless_by_exception_impl;
- using data::set_index;
- using data::ind;
- using data::reset;
- using data::move_constructor;
- using data::build_at;
- template <size_t N>
- using get_type_t = variant_alternative_t<N, variant>;
- public:
- template<typename = std::enable_if_t<std::is_default_constructible_v<T0>>>
- variant(): data(pos<0>()) {}
- template <typename T, typename varT = select_type_t<T, T0, Ts...>,
- typename = std::enable_if_t<
- !std::is_same_v<std::decay_t<T>, variant> &&
- std::is_constructible_v<varT, T> &&
- is_unique_v<varT, T0, Ts...> >,
- size_t N = get_type_index<varT, T0, Ts...>::value>
- variant(T&& t): data(pos<N>(), std::forward<T>(t)) {}
- template <typename T, typename ...Args,
- size_t N = get_type_index<T, T0, Ts...>::value,
- typename = std::enable_if_t<
- (N != -1) &&
- std::is_constructible_v<T, Args...> &&
- is_unique_v<std::in_place_type<T>, T0, Ts...> >>
- variant(std::in_place_type_t<T> t, Args&&... args):
- data(pos<N>(), std::forward<Args>(args)...) {}
- template <size_t N, typename ...Args, typename T = get_type_t<N>,
- typename = std::enable_if_t<
- (N != -1) &&
- std::is_constructible_v<T, Args...>
- >
- >
- variant(std::in_place_index_t<N>, Args&&... args):
- data(pos<N>(), std::forward<Args>(args)...) {}
- template<typename T, typename varT = select_type_t<T, T0, Ts...>,
- typename = std::enable_if_t<std::is_constructible_v<varT, T> && std::is_assignable_v<varT&, T>&&
- is_unique_v<varT, T0, Ts...> >,
- size_t N = get_type_index<varT, T0, Ts...>::value>
- variant& operator=(T&& t) {
- if(N == index()) {
- get<N>(*this) = std::forward<T>(t);
- return *this;
- }
- return this->operator=(variant(std::forward<T>(t)));
- }
- size_t index() const {
- return ind();
- // -1
- }
- template <typename T, typename... Args, size_t N = get_type_index<T, T0, Ts...>::value,
- typename = std::enable_if_t<std::is_constructible_v<T, Args...> && is_unique_v<T, T0, Ts...> >>
- T& emplace(Args&&... args) {
- reset(index());
- build_at(index(), std::forward<Args>(args)...);
- return get_storage_data(pos<N>(), *this);
- }
- template <size_t N, typename... Args, typename T = get_type_t<N>,
- typename = std::enable_if_t<std::is_constructible_v<T, Args...>>>
- variant_alternative_t<N, variant>& emplace(Args&&... args) {
- return emplace<T>(std::forward<Args>(args)...);
- }
- bool valueless_by_exception() const {
- return valueless_by_exception_impl();
- }
- };
- template <typename T, typename ... Types>
- bool holds_alternative(const variant<Types...>& v) {
- return !v.valueless_by_exception() && v.index() == get_type_index<T, Types...>::value;
- }
- template <size_t N, typename ... Ts>
- decltype(auto) get_if(variant<Ts...>* pv) {
- if (N >= sizeof... (Ts)) {
- throw bad_variant_access();
- }
- if (pv != nullptr && pv->index() != N) {
- return &get<N>(*pv);
- }
- return nullptr;
- }
- template <size_t N, typename ... Ts>
- decltype(auto) get_if(const variant<Ts...>* pv) {
- if (N >= sizeof...(Ts)) {
- throw bad_variant_access();
- }
- if (pv != nullptr && pv->index() != N) {
- return &get<N>(*pv);
- }
- return nullptr;
- }
- template <typename T, typename ... Ts, typename = std::enable_if_t<is_unique_v<T, Ts...> > >
- decltype(auto) get_if(variant<Ts...>* pv) {
- size_t N = get_type_index<T, Ts...>();
- return get_if<N>(pv);
- }
- template <typename T, typename ... Ts, typename = std::enable_if_t<is_unique_v<T, Ts...> > >
- decltype(auto) get_if(const variant<Ts...>* pv) {
- size_t N = get_type_index<T, Ts...>();
- return get_if<N>(pv);
- }
- template<typename T, size_t... dimensions>
- struct multi_array {
- constexpr const T& access() const{
- return data;
- }
- T data;
- };
- template<typename T, size_t first, size_t... rest>
- struct multi_array<T, first, rest...> {
- template<typename... Args>
- constexpr const T& access(size_t first_index, Args... rest_indices) const {
- return arr[first_index].access(rest_indices...);
- }
- multi_array<T, rest...> arr[first];
- };
- template<typename array_type, typename variant_tuple, typename index_seq>
- struct gen_vtable_impl;
- template<typename result_type, typename visitor, size_t... dimensions, typename... variants, size_t... indices>
- struct gen_vtable_impl<
- multi_array<result_type (*)(visitor, variants...), dimensions...>,
- std::tuple<variants...>, std::index_sequence<indices...> > {
- using next = std::remove_reference_t<typename nth_type<sizeof...(indices),variants...>::type>;
- using array_type = multi_array<result_type (*)(visitor, variants...), dimensions...>;
- static constexpr array_type apply()
- {
- array_type vtable{};
- apply_all(vtable, std::make_index_sequence<variant_size_v<next>>());
- return vtable;
- }
- template<size_t... var_indices>
- static constexpr void apply_all(array_type& vtable, std::index_sequence<var_indices...>) {
- (apply_single<var_indices>(vtable.arr[var_indices]), ...);
- }
- template<size_t index, typename T>
- static constexpr void apply_single(T& element) {
- element = gen_vtable_impl<
- std::remove_reference_t<decltype(element)>,
- std::tuple<variants...>,
- std::index_sequence<indices..., index>>::apply();
- }
- };
- template<typename result_type, typename visitor, typename... variants, size_t... indices>
- struct gen_vtable_impl<
- multi_array<result_type (*)(visitor, variants...)>,
- std::tuple<variants...>,
- std::index_sequence<indices...> > {
- using array_type = multi_array<result_type (*)(visitor&&, variants...)>;
- decltype(auto) static constexpr visit_invoke(visitor&& vis, variants... vars) {
- return std::invoke(std::forward<visitor>(vis), get<indices>(std::forward<variants>(vars))...);
- }
- static constexpr auto apply() {
- return array_type{&visit_invoke};
- }
- };
- template<typename result_type, typename visitor, typename... variants>
- struct gen_vtable {
- using func_ptr = result_type (*)(visitor&&, variants...);
- using array_type = multi_array<func_ptr, variant_size_v<std::remove_reference_t<variants>>...>;
- static constexpr array_type apply()
- {
- return gen_vtable_impl<array_type, std::tuple<variants...>, std::index_sequence<>>::apply();
- }
- static constexpr auto vtable = apply();
- };
- template<typename Visitor, typename... Variants>
- constexpr decltype(auto) visit(Visitor&& visitor, Variants&& ... variants) {
- if ((variants.valueless_by_exception() || ...)) {
- throw bad_variant_access();
- }
- using result_type = decltype(std::forward<Visitor>(visitor)(get<0>(std::forward<Variants>(variants))...));
- constexpr auto& v_table = gen_vtable<result_type, Visitor&&, Variants&&...>::vtable;
- auto func_ptr = v_table.access(variants.index()...);
- return (*func_ptr)(std::forward<Visitor>(visitor), std::forward<Variants>(variants)...);
- }
- auto comparator = [](auto&& action) constexpr {
- return ([action](auto&& a, auto&& b) constexpr -> bool {
- if constexpr(std::is_same_v<decltype(a), decltype(b)>){
- return action(a, b);
- } else {
- return 0;
- }
- });
- };
- //template<typename T, size_t... dimensions>
- //struct multi_array {
- // const T& access() const {
- // return data;
- // }
- // T data;
- //};
- //template<typename T, size_t first, size_t... rest>
- //struct multi_array<T, first, rest...> {
- // template<typename... Args>
- // const T& access(size_t first_index, Args... rest_indices) const {
- // return arr[first_index].access(rest_indices...);
- // }
- // multi_array<T, rest...> arr[first];
- //};
- //template<typename array_type, typename variant_tuple, typename index_seq>
- //struct gen_vtable_impl;
- //template<typename result_type, typename visitor, size_t... dimensions, typename... variants, size_t... indices>
- //struct gen_vtable_impl<
- // multi_array<result_type (*)(visitor, variants...), dimensions...>,
- // std::tuple<variants...>,
- // std::index_sequence<indices...> > {
- // using next = std::remove_reference_t<typename nth_type<size_t(sizeof...(indices)),variants...>::type>;
- // using array_type = multi_array<result_type (*)(visitor, variants...), dimensions...>;
- // static array_type apply() {
- // array_type vtable{};
- // apply_all(vtable, std::make_index_sequence<variant_size_v<next>>());
- // return vtable;
- // }
- // template<size_t... var_indices>
- // static void apply_all(array_type& vtable, std::index_sequence<var_indices...>) {
- // (apply_single<var_indices>(vtable.arr[var_indices]), ...);
- // }
- // template<size_t index, typename T>
- // static void apply_single(T& element) {
- // element = gen_vtable_impl<
- // std::remove_reference_t<decltype(element)>,
- // std::tuple<variants...>,
- // std::index_sequence<indices..., index>>::apply();
- // }
- //};
- //template<typename result_type, typename visitor, typename... variants, size_t... indices>
- //struct gen_vtable_impl<
- // multi_array<result_type (*)(visitor, variants...)>,
- // std::tuple<variants...>,
- // std::index_sequence<indices...> > {
- // using array_type = multi_array<result_type (*)(visitor&&, variants...)>;
- // decltype(auto) static visit_invoke(visitor&& vis, variants... vars) {
- // return std::invoke(std::forward<visitor>(vis), get<indices>(std::forward<variants>(vars))...);
- // }
- // static auto apply() {
- // return array_type(&visit_invoke);
- // }
- //};
- //template<typename result_type, typename visitor, typename... variants>
- //struct gen_vtable {
- // using func_ptr = result_type (*)(visitor&&, variants...);
- // using array_type = multi_array<func_ptr, variant_size_v<std::remove_reference_t<variants>>...>;
- // static array_type apply() {
- // return gen_vtable_impl<array_type, std::tuple<variants...>, std::index_sequence<>>::apply();
- // }
- // static const auto vtable = apply();
- //};
- //template<typename Var, typename ... Vars>
- //bool check_valueless(Var one, Vars ... other) {
- // return one.valueless_by_exception() || check_valueless(other.valueless_by_exception() ...);
- //}
- //bool check_valueless() {
- // return false;
- //}
- //template<typename V, typename ... Vars>
- //decltype(auto) visit(V&& visitor, Vars&& ... vars) {
- // if (check_valueless(vars ...)) {
- // throw bad_variant_access();
- // }
- // using result_type = decltype(std::forward<V>(visitor)(get<0>(std::forward<Vars>(vars))...));
- // auto& v_table = gen_vtable<result_type, V&&, Vars&&...>::vtable;
- // auto func_ptr = v_table.access(vars.index()...);
- // return (*func_ptr)(std::forward<V>(visitor), std::forward<Vars>(vars)...);
- //}
- #endif // VARIANT_H
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement