| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626 |
- /* Copyright 2024-2025 Joaquin M Lopez Munoz.
- * Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE_1_0.txt or copy at
- * http://www.boost.org/LICENSE_1_0.txt)
- *
- * See http://www.boost.org/libs/poly_collection for library home page.
- */
- #ifndef BOOST_POLY_COLLECTION_DETAIL_FIXED_VARIANT_HPP
- #define BOOST_POLY_COLLECTION_DETAIL_FIXED_VARIANT_HPP
- #if defined(_MSC_VER)
- #pragma once
- #endif
- #include <boost/config.hpp>
- #include <boost/core/addressof.hpp>
- #include <boost/detail/workaround.hpp>
- #include <boost/mp11/algorithm.hpp>
- #include <boost/mp11/function.hpp>
- #include <boost/mp11/list.hpp>
- #include <boost/mp11/set.hpp>
- #include <boost/mp11/tuple.hpp>
- #include <boost/mp11/utility.hpp>
- #include <boost/poly_collection/detail/is_equality_comparable.hpp>
- #include <boost/poly_collection/detail/is_nothrow_eq_comparable.hpp>
- #include <boost/type_traits/is_constructible.hpp>
- #include <cstddef>
- #include <limits>
- #include <memory>
- #include <stdexcept>
- #include <type_traits>
- #include <utility>
- namespace boost{
- namespace poly_collection{
- namespace fixed_variant_impl{
- /* fixed_variant behaves as a variant without the possibility to change the
- * initial alternative. The referenced value does not belong in fixed_variant
- * but assumed to be right before it, which layout is implemented by
- * fixed_variant_closure<T,fixed_variant<...>>. This approach allows us to pack
- * same-alternative fixed_variants optimally, without reserving space for
- * the largest alternative type.
- */
- template<typename... Ts>
- class fixed_variant
- {
- static_assert(
- !mp11::mp_empty<fixed_variant>::value,
- "the variant can't be specified with zero types");
- static_assert(
- mp11::mp_is_set<fixed_variant>::value,
- "all types in the variant must be distinct");
- static constexpr std::size_t N=sizeof...(Ts);
- using index_type=mp11::mp_cond<
- mp11::mp_bool<
- (N<=(std::numeric_limits<unsigned char>::max)())>,unsigned char,
- mp11::mp_bool<
- (N<=(std::numeric_limits<unsigned short>::max)())>,unsigned short,
- mp11::mp_true, std::size_t
- >;
- public:
- template<
- typename T,
- std::size_t I=mp11::mp_find<fixed_variant,T>::value,
- typename std::enable_if<
- (I<mp11::mp_size<fixed_variant>::value)>::type* =nullptr
- >
- explicit fixed_variant(const T&):index_{static_cast<index_type>(I)}{}
- std::size_t index()const noexcept{return index_;}
- bool valueless_by_exception()const noexcept{return false;}
- #if BOOST_WORKAROUND(BOOST_MSVC,<1920)
- /* spurious C2248 when perfect forwarding fixed_variant */
- #else
- protected:
- fixed_variant(const fixed_variant&)=default;
- fixed_variant& operator=(const fixed_variant&)=default;
- #endif
- private:
- index_type index_;
- };
- template<typename T>
- struct fixed_variant_store
- {
- template<typename... Args>
- fixed_variant_store(Args&&... args):value{std::forward<Args>(args)...}{}
- T value;
- };
- template<typename T,typename Base>
- class fixed_variant_closure:public fixed_variant_store<T>,public Base
- {
- public:
- template<
- typename... Args,
- typename std::enable_if<
- std::is_constructible<T,Args&&...>::value
- >::type* =nullptr
- >
- fixed_variant_closure(Args&&... args)
- noexcept(std::is_nothrow_constructible<T,Args&&...>::value):
- fixed_variant_store<T>{std::forward<Args>(args)...},
- Base{this->value}
- {}
- fixed_variant_closure(const fixed_variant_closure&)=default;
- fixed_variant_closure(fixed_variant_closure&&)=default;
- fixed_variant_closure& operator=(fixed_variant_closure&&)=default;
- template<
- typename Q=T,
- typename std::enable_if<
- detail::is_equality_comparable<Q>::value,bool>::type* =nullptr
- >
- bool operator==(const fixed_variant_closure& x)const
- noexcept(detail::is_nothrow_equality_comparable<T>::value)
- {
- return this->value==x.value;
- }
- };
- struct bad_variant_access:std::exception
- {
- bad_variant_access()noexcept{}
- const char* what()const noexcept{return "bad variant access";}
- };
- template<typename T> struct variant_size;
- template<typename... Ts>
- struct variant_size<fixed_variant<Ts...>>:
- std::integral_constant<std::size_t, sizeof...(Ts)>{};
- template<typename T> struct variant_size<const T>:variant_size<T>{};
- #ifndef BOOST_NO_CXX14_VARIABLE_TEMPLATES
- template<typename T>
- constexpr std::size_t variant_size_v=variant_size<T>::value;
- #endif
- template<std::size_t I,typename T,typename=void> struct variant_alternative;
- template<typename T> struct is_fixed_variant:std::false_type{};
- template<typename... Ts>
- struct is_fixed_variant<fixed_variant<Ts...>>:std::true_type{};
- template<typename T,typename Q>
- struct transfer_cref{using type=Q;};
- template<typename T,typename Q>
- struct transfer_cref<const T,Q>{using type=const Q;};
- template<typename T,typename Q>
- struct transfer_cref<T&,Q>
- {using type=typename transfer_cref<T,Q>::type&;};
- template<typename T,typename Q>
- struct transfer_cref<T&&,Q>
- {using type=typename transfer_cref<T,Q>::type&&;};
- template<std::size_t I,typename V>
- struct variant_alternative<
- I,V,
- typename std::enable_if<
- is_fixed_variant<typename std::decay<V>::type>::value
- >::type
- >
- {
- using type=typename transfer_cref<
- V,mp11::mp_at_c<typename std::decay<V>::type,I>>::type;
- };
- template<std::size_t I,typename V>
- using variant_alternative_t=typename variant_alternative<I,V>::type;
- template<typename T,typename... Ts>
- bool holds_alternative(const fixed_variant<Ts...>& x)noexcept
- {
- static_assert(
- mp11::mp_contains<fixed_variant<Ts...>,T>::value,
- "type must be one of the variant alternatives");
- return x.index()==mp11::mp_find<fixed_variant<Ts...>,T>::value;
- }
- template<typename T,typename... Ts>
- const T& unsafe_get(const fixed_variant<Ts...>& x)
- {
- return static_cast<const fixed_variant_closure<T,fixed_variant<Ts...>>&>
- (x).value;
- }
- template<typename T,typename... Ts>
- T& unsafe_get(fixed_variant<Ts...>& x)
- {
- return const_cast<T&>(
- unsafe_get<T>(const_cast<const fixed_variant<Ts...>&>(x)));
- }
- template<typename T,typename... Ts>
- const T&& unsafe_get(const fixed_variant<Ts...>&& x)
- {
- return std::move(unsafe_get<T>(x));
- }
- template<typename T,typename... Ts>
- T&& unsafe_get(fixed_variant<Ts...>&& x)
- {
- return std::move(unsafe_get<T>(x));
- }
- template<std::size_t I,typename V>
- variant_alternative_t<I,V&&> unsafe_get(V&& x)
- {
- using raw_variant=typename std::decay<V>::type;
- return unsafe_get<mp11::mp_at_c<raw_variant,I>>(std::forward<V>(x));
- }
- template<std::size_t I,typename V>
- variant_alternative_t<I,V&&> get(V&& x)
- {
- using raw_variant=typename std::decay<V>::type;
- static_assert(
- I<mp11::mp_size<raw_variant>::value,
- "index must be less than the number of alternatives");
- if(x.index()!=I)throw bad_variant_access{};
- else return unsafe_get<I>(std::forward<V>(x));
- }
- template<typename T,typename V>
- auto get(V&& x)->decltype(unsafe_get<T>(std::forward<V>(x)))
- {
- using raw_variant=typename std::decay<V>::type;
- static_assert(
- mp11::mp_contains<raw_variant,T>::value,
- "type must be one of the variant alternatives");
- if(!holds_alternative<T>(x))throw bad_variant_access{};
- else return unsafe_get<T>(std::forward<V>(x));
- }
- template<std::size_t I,typename... Ts>
- variant_alternative_t<I,fixed_variant<Ts...>>*
- get_if(fixed_variant<Ts...>* px)noexcept
- {
- if(!px||px->index()!=I)return nullptr;
- else return std::addressof(unsafe_get<I>(*px));
- }
- template<std::size_t I,typename... Ts>
- const variant_alternative_t<I,fixed_variant<Ts...>>*
- get_if(const fixed_variant<Ts...>* px)noexcept
- {
- return get_if<I>(const_cast<fixed_variant<Ts...>*>(px));
- }
- template<typename T,typename... Ts>
- T* get_if(fixed_variant<Ts...>* px)noexcept
- {
- if(!px||!holds_alternative<T>(*px))return nullptr;
- else return std::addressof(unsafe_get<T>(*px));
- }
- template<typename T,typename... Ts>
- const T* get_if(const fixed_variant<Ts...>* px)noexcept
- {
- return get_if<T>(const_cast<fixed_variant<Ts...>*>(px));
- }
- struct deduced;
- template<typename R,typename F,typename... Vs>
- struct return_type_impl
- {
- using type=R;
- };
- template<typename F,typename... Vs>
- struct return_type_impl<deduced,F,Vs...>
- {
- using type=decltype(std::declval<F>()(get<0>(std::declval<Vs>())...));
- };
- template<typename R,typename F,typename... Vs>
- using return_type=typename return_type_impl<R,F,Vs...>::type;
- template<typename R,typename F,typename... Vs>
- struct visit_helper;
- template<typename R,typename F>
- struct visit_helper<R,F>
- {
- F&& f;
- R operator()(){return std::forward<F>(f)();}
- };
- template<typename F>
- struct visit_helper<void,F>
- {
- F&& f;
- void operator()(){(void)std::forward<F>(f)();}
- };
- template<
- typename R=deduced,typename F,
- typename ReturnType=return_type<R,F&&>
- >
- ReturnType visit(F&& f)
- {
- return visit_helper<ReturnType,F>{std::forward<F>(f)}();
- }
- template<typename R,typename F,typename V>
- struct visit_helper<R,F,V>
- {
- F&& f;
- V&& x;
- template<typename I>
- R operator()(I)
- {
- return std::forward<F>(f)(unsafe_get<I::value>(std::forward<V>(x)));
- }
- };
- template<typename F,typename V>
- struct visit_helper<void,F,V>
- {
- F&& f;
- V&& x;
- template<typename I>
- void operator()(I)
- {
- (void)std::forward<F>(f)(unsafe_get<I::value>(std::forward<V>(x)));
- }
- };
- template<
- typename R=deduced,typename F,typename V,
- typename ReturnType=return_type<R,F&&,V&&>
- >
- ReturnType visit(F&& f,V&& x)
- {
- using raw_variant=typename std::decay<V>::type;
- return mp11::mp_with_index<mp11::mp_size<raw_variant>::value>(
- x.index(),
- visit_helper<ReturnType,F,V>{std::forward<F>(f),std::forward<V>(x)});
- }
- template<typename R,typename F,typename V,typename I>
- struct bound_f
- {
- F&& f;
- V&& x;
- template<typename... Args>
- R operator()(Args&&... xs)
- {
- return std::forward<F>(f)(
- unsafe_get<I::value>(std::forward<V>(x)),std::forward<Args>(xs)...);
- }
- };
- template<typename F,typename V,typename I>
- struct bound_f<void,F,V,I>
- {
- F&& f;
- V&& x;
- template<typename... Args>
- void operator()(Args&&... xs)
- {
- (void)std::forward<F>(f)(
- unsafe_get<I::value>(std::forward<V>(x)),std::forward<Args>(xs)...);
- }
- };
- template<typename R,typename F>
- struct bound_visit;
- template<typename R,typename F,typename V,typename... Vs>
- struct visit_helper<R,F,V,Vs...>
- {
- F&& f;
- V&& x;
- std::tuple<Vs&&...> xs;
- template<typename I>
- R operator()(I)
- {
- return mp11::tuple_apply(
- bound_visit<R,bound_f<R,F,V,I>>{{std::forward<F>(f),std::forward<V>(x)}},
- std::move(xs));
- }
- };
- template<
- typename R=deduced,typename F,typename V1,typename V2,typename... Vs,
- typename ReturnType=return_type<R,F&&,V1&&,V2&&,Vs&&...>
- >
- ReturnType visit(F&& f,V1&& x1,V2&& x2,Vs&&... xs)
- {
- using raw_variant=typename std::decay<V1>::type;
- return mp11::mp_with_index<mp11::mp_size<raw_variant>::value>(
- x1.index(),
- visit_helper<ReturnType,F,V1,V2,Vs...>{
- std::forward<F>(f),std::forward<V1>(x1),
- std::forward_as_tuple(std::forward<V2>(x2),std::forward<Vs>(xs)...)});
- }
- template<typename R,typename F>
- struct bound_visit
- {
- F&& f;
- template<typename... Vs>
- R operator()(Vs&&... xs)
- {
- return visit<R>(std::forward<F>(f),std::forward<Vs>(xs)...);
- }
- };
- template<typename R,typename V,typename... Fs>
- struct return_type_by_index_impl
- {
- using type=R;
- };
- template<typename V,typename F,typename... Fs>
- struct return_type_by_index_impl<deduced,V,F,Fs...>
- {
- using type=decltype(std::declval<F>()(get<0>(std::declval<V>())));
- };
- template<typename R,typename V,typename... Fs>
- using return_type_by_index=typename return_type_by_index_impl<R,V,Fs...>::type;
- template<typename R,typename V,typename... Fs>
- struct visit_by_index_helper
- {
- V&& x;
- std::tuple<Fs&&...> fs;
- template<typename I>
- R operator()(I)
- {
- return std::get<I::value>(std::move(fs))(
- unsafe_get<I::value>(std::forward<V>(x)));
- }
- };
- template<typename V,typename... Fs>
- struct visit_by_index_helper<void,V,Fs...>
- {
- V&& x;
- std::tuple<Fs&&...> fs;
- template<typename I>
- void operator()(I)
- {
- (void)std::get<I::value>(std::move(fs))(
- unsafe_get<I::value>(std::forward<V>(x)));
- }
- };
- template<
- typename R=deduced,typename V,typename... Fs,
- typename ReturnType=return_type_by_index<R,V&&,Fs&&...>
- >
- ReturnType visit_by_index(V&& x,Fs&&... fs)
- {
- using raw_variant=typename std::decay<V>::type;
- static_assert(
- mp11::mp_size<raw_variant>::value==sizeof...(Fs),
- "the number of function objects must be the same as that of the "
- "alternative types in the variant");
- return mp11::mp_with_index<mp11::mp_size<raw_variant>::value>(
- x.index(),
- visit_by_index_helper<ReturnType,V,Fs...>{
- std::forward<V>(x),
- std::forward_as_tuple(std::forward<Fs>(fs)...)});
- }
- template<typename RelOp,typename ... Ts>
- struct relop_helper
- {
- const fixed_variant<Ts...> &x,&y;
- template<typename I> bool operator()(I)const
- {
- return RelOp{}(unsafe_get<I::value>(x),unsafe_get<I::value>(y));
- }
- };
- struct eq_
- {
- template<typename T>
- bool operator()(const T& x,const T& y)const{return x==y;}
- };
- template<typename... Ts>
- bool operator==(
- const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y)
- {
- return
- x.index()==y.index()&&
- mp11::mp_with_index<sizeof...(Ts)>(x.index(),relop_helper<eq_,Ts...>{x,y});
- }
- struct neq_
- {
- template<typename T>
- bool operator()(const T& x,const T& y)const{return x!=y;}
- };
- template<typename... Ts>
- bool operator!=(
- const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y)
- {
- return
- x.index()!=y.index()||
- mp11::mp_with_index<sizeof...(Ts)>(
- x.index(),relop_helper<neq_,Ts...>{x,y});
- }
- struct lt_
- {
- template<typename T>
- bool operator()(const T& x,const T& y)const{return x<y;}
- };
- template<typename... Ts>
- bool operator<(
- const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y)
- {
- return
- x.index()<y.index()||
- (x.index()==y.index()&&mp11::mp_with_index<sizeof...(Ts)>(
- x.index(),relop_helper<lt_,Ts...>{x,y}));
- }
- struct lte_
- {
- template<typename T>
- bool operator()(const T& x,const T& y)const{return x<=y;}
- };
- template<typename... Ts>
- bool operator<=(
- const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y)
- {
- return
- x.index()<y.index()||
- (x.index()==y.index()&&mp11::mp_with_index<sizeof...(Ts)>(
- x.index(),relop_helper<lte_,Ts...>{x,y}));
- }
- struct gt_
- {
- template<typename T>
- bool operator()(const T& x,const T& y)const{return x>y;}
- };
- template<typename... Ts>
- bool operator>(
- const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y)
- {
- return
- x.index()>y.index()||
- (x.index()==y.index()&&mp11::mp_with_index<sizeof...(Ts)>(
- x.index(),relop_helper<gt_,Ts...>{x,y}));
- }
- struct gte_
- {
- template<typename T>
- bool operator()(const T& x,const T& y)const{return x>=y;}
- };
- template<typename... Ts>
- bool operator>=(
- const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y)
- {
- return
- x.index()>y.index()||
- (x.index()==y.index()&&mp11::mp_with_index<sizeof...(Ts)>(
- x.index(),relop_helper<gte_,Ts...>{x,y}));
- }
- } /* namespace poly_collection::fixed_variant_impl */
- using boost::poly_collection::fixed_variant_impl::variant_size;
- #ifndef BOOST_NO_CXX14_VARIABLE_TEMPLATES
- using boost::poly_collection::fixed_variant_impl::variant_size_v;
- #endif
- using boost::poly_collection::fixed_variant_impl::bad_variant_access;
- using boost::poly_collection::fixed_variant_impl::variant_alternative;
- using boost::poly_collection::fixed_variant_impl::variant_alternative_t;
- using boost::poly_collection::fixed_variant_impl::visit;
- using boost::poly_collection::fixed_variant_impl::visit_by_index;
- using boost::poly_collection::fixed_variant_impl::holds_alternative;
- using boost::poly_collection::fixed_variant_impl::get;
- using boost::poly_collection::fixed_variant_impl::unsafe_get;
- using boost::poly_collection::fixed_variant_impl::get_if;
- } /* namespace poly_collection */
- } /* namespace boost */
- #endif
|