Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:45:56

0001 /* Copyright 2024-2025 Joaquin M Lopez Munoz.
0002  * Distributed under the Boost Software License, Version 1.0.
0003  * (See accompanying file LICENSE_1_0.txt or copy at
0004  * http://www.boost.org/LICENSE_1_0.txt)
0005  *
0006  * See http://www.boost.org/libs/poly_collection for library home page.
0007  */
0008 
0009 #ifndef BOOST_POLY_COLLECTION_DETAIL_FIXED_VARIANT_HPP
0010 #define BOOST_POLY_COLLECTION_DETAIL_FIXED_VARIANT_HPP
0011 
0012 #if defined(_MSC_VER)
0013 #pragma once
0014 #endif
0015 
0016 #include <boost/config.hpp>
0017 #include <boost/core/addressof.hpp>
0018 #include <boost/detail/workaround.hpp>
0019 #include <boost/mp11/algorithm.hpp>
0020 #include <boost/mp11/function.hpp>
0021 #include <boost/mp11/list.hpp>
0022 #include <boost/mp11/set.hpp>
0023 #include <boost/mp11/tuple.hpp>
0024 #include <boost/mp11/utility.hpp>
0025 #include <boost/poly_collection/detail/is_equality_comparable.hpp>
0026 #include <boost/poly_collection/detail/is_nothrow_eq_comparable.hpp>
0027 #include <boost/type_traits/is_constructible.hpp>
0028 #include <cstddef>
0029 #include <limits>
0030 #include <memory>
0031 #include <stdexcept>
0032 #include <type_traits>
0033 #include <utility>
0034 
0035 namespace boost{
0036 
0037 namespace poly_collection{
0038 
0039 namespace fixed_variant_impl{
0040 
0041 /* fixed_variant behaves as a variant without the possibility to change the
0042  * initial alternative. The referenced value does not belong in fixed_variant
0043  * but assumed to be right before it, which layout is implemented by
0044  * fixed_variant_closure<T,fixed_variant<...>>. This approach allows us to pack
0045  * same-alternative fixed_variants optimally, without reserving space for
0046  * the largest alternative type.
0047  */
0048 
0049 template<typename... Ts>
0050 class fixed_variant
0051 {
0052   static_assert(
0053     !mp11::mp_empty<fixed_variant>::value,
0054     "the variant can't be specified with zero types");
0055   static_assert(
0056     mp11::mp_is_set<fixed_variant>::value,
0057     "all types in the variant must be distinct");
0058 
0059   static constexpr std::size_t N=sizeof...(Ts);
0060   using index_type=mp11::mp_cond<
0061     mp11::mp_bool<
0062       (N<=(std::numeric_limits<unsigned char>::max)())>,unsigned char,
0063     mp11::mp_bool<
0064       (N<=(std::numeric_limits<unsigned short>::max)())>,unsigned short,
0065     mp11::mp_true, std::size_t
0066   >;
0067 
0068 public:
0069   template<
0070     typename T,
0071     std::size_t I=mp11::mp_find<fixed_variant,T>::value,
0072     typename std::enable_if<
0073       (I<mp11::mp_size<fixed_variant>::value)>::type* =nullptr
0074   >
0075   explicit fixed_variant(const T&):index_{static_cast<index_type>(I)}{}
0076 
0077   std::size_t index()const noexcept{return index_;}
0078   bool        valueless_by_exception()const noexcept{return false;}
0079 
0080 #if BOOST_WORKAROUND(BOOST_MSVC,<1920)
0081   /* spurious C2248 when perfect forwarding fixed_variant */
0082 #else
0083 protected:
0084   fixed_variant(const fixed_variant&)=default;
0085   fixed_variant& operator=(const fixed_variant&)=default;
0086 #endif
0087 
0088 private:
0089   index_type index_;
0090 };
0091 
0092 template<typename T>
0093 struct fixed_variant_store
0094 {
0095   template<typename... Args>
0096   fixed_variant_store(Args&&... args):value{std::forward<Args>(args)...}{}
0097 
0098   T value;
0099 };
0100 
0101 template<typename T,typename Base>
0102 class fixed_variant_closure:public fixed_variant_store<T>,public Base
0103 {
0104 public:
0105   template<
0106     typename... Args,
0107     typename std::enable_if<
0108       std::is_constructible<T,Args&&...>::value
0109     >::type* =nullptr
0110   >
0111   fixed_variant_closure(Args&&... args)
0112     noexcept(std::is_nothrow_constructible<T,Args&&...>::value):
0113     fixed_variant_store<T>{std::forward<Args>(args)...},
0114     Base{this->value}
0115     {}
0116 
0117   fixed_variant_closure(const fixed_variant_closure&)=default;
0118   fixed_variant_closure(fixed_variant_closure&&)=default;
0119   fixed_variant_closure& operator=(fixed_variant_closure&&)=default;
0120 
0121   template<
0122     typename Q=T,
0123     typename std::enable_if<
0124       detail::is_equality_comparable<Q>::value,bool>::type* =nullptr
0125   >
0126   bool operator==(const fixed_variant_closure& x)const
0127     noexcept(detail::is_nothrow_equality_comparable<T>::value)
0128   {
0129     return this->value==x.value;
0130   }
0131 };
0132 
0133 struct bad_variant_access:std::exception
0134 {
0135   bad_variant_access()noexcept{}
0136   const char* what()const noexcept{return "bad variant access";}
0137 };
0138 
0139 template<typename T> struct variant_size;
0140 template<typename... Ts>
0141 struct variant_size<fixed_variant<Ts...>>:
0142   std::integral_constant<std::size_t, sizeof...(Ts)>{};
0143 template<typename T> struct variant_size<const T>:variant_size<T>{};
0144 
0145 #ifndef BOOST_NO_CXX14_VARIABLE_TEMPLATES
0146 template<typename T>
0147 constexpr std::size_t variant_size_v=variant_size<T>::value;
0148 #endif
0149 
0150 template<std::size_t I,typename T,typename=void> struct variant_alternative;
0151 
0152 template<typename T> struct is_fixed_variant:std::false_type{};
0153 template<typename... Ts>
0154 struct is_fixed_variant<fixed_variant<Ts...>>:std::true_type{};
0155 
0156 template<typename T,typename Q> 
0157 struct transfer_cref{using type=Q;};
0158 template<typename T,typename Q>
0159 struct transfer_cref<const T,Q>{using type=const Q;};
0160 template<typename T,typename Q>
0161 struct transfer_cref<T&,Q>
0162 {using type=typename transfer_cref<T,Q>::type&;};
0163 template<typename T,typename Q>
0164 struct transfer_cref<T&&,Q>
0165 {using type=typename transfer_cref<T,Q>::type&&;};
0166 
0167 template<std::size_t I,typename V>
0168 struct variant_alternative<
0169   I,V,
0170   typename std::enable_if<
0171     is_fixed_variant<typename std::decay<V>::type>::value
0172   >::type
0173 >
0174 {
0175   using type=typename transfer_cref<
0176     V,mp11::mp_at_c<typename std::decay<V>::type,I>>::type;
0177 };
0178 
0179 template<std::size_t I,typename V>
0180 using variant_alternative_t=typename variant_alternative<I,V>::type;
0181 
0182 template<typename T,typename... Ts>
0183 bool holds_alternative(const fixed_variant<Ts...>& x)noexcept
0184 {
0185   static_assert(
0186     mp11::mp_contains<fixed_variant<Ts...>,T>::value,
0187     "type must be one of the variant alternatives");
0188   return x.index()==mp11::mp_find<fixed_variant<Ts...>,T>::value;
0189 }
0190 
0191 template<typename T,typename... Ts>
0192 const T& unsafe_get(const fixed_variant<Ts...>& x)
0193 {
0194   return static_cast<const fixed_variant_closure<T,fixed_variant<Ts...>>&>
0195     (x).value;
0196 }
0197 
0198 template<typename T,typename... Ts>
0199 T& unsafe_get(fixed_variant<Ts...>& x)
0200 {
0201   return const_cast<T&>(
0202     unsafe_get<T>(const_cast<const fixed_variant<Ts...>&>(x)));
0203 }
0204 
0205 template<typename T,typename... Ts>
0206 const T&& unsafe_get(const fixed_variant<Ts...>&& x)
0207 {
0208   return std::move(unsafe_get<T>(x));
0209 }
0210 
0211 template<typename T,typename... Ts>
0212 T&& unsafe_get(fixed_variant<Ts...>&& x)
0213 {
0214   return std::move(unsafe_get<T>(x));
0215 }
0216 
0217 template<std::size_t I,typename V>
0218 variant_alternative_t<I,V&&> unsafe_get(V&& x)
0219 {
0220   using raw_variant=typename std::decay<V>::type;
0221 
0222   return unsafe_get<mp11::mp_at_c<raw_variant,I>>(std::forward<V>(x));
0223 }
0224 
0225 template<std::size_t I,typename V>
0226 variant_alternative_t<I,V&&> get(V&& x)
0227 {
0228   using raw_variant=typename std::decay<V>::type;
0229   static_assert(
0230     I<mp11::mp_size<raw_variant>::value,
0231     "index must be less than the number of alternatives");
0232 
0233   if(x.index()!=I)throw bad_variant_access{};
0234   else return unsafe_get<I>(std::forward<V>(x));
0235 }
0236 
0237 template<typename T,typename V>
0238 auto get(V&& x)->decltype(unsafe_get<T>(std::forward<V>(x)))
0239 {
0240   using raw_variant=typename std::decay<V>::type;
0241   static_assert(
0242     mp11::mp_contains<raw_variant,T>::value,
0243     "type must be one of the variant alternatives");
0244 
0245   if(!holds_alternative<T>(x))throw bad_variant_access{};
0246   else return unsafe_get<T>(std::forward<V>(x));
0247 }
0248 
0249 template<std::size_t I,typename... Ts>
0250 variant_alternative_t<I,fixed_variant<Ts...>>*
0251 get_if(fixed_variant<Ts...>* px)noexcept
0252 {
0253   if(!px||px->index()!=I)return nullptr;
0254   else return std::addressof(unsafe_get<I>(*px));
0255 }
0256 
0257 template<std::size_t I,typename... Ts>
0258 const variant_alternative_t<I,fixed_variant<Ts...>>*
0259 get_if(const fixed_variant<Ts...>* px)noexcept
0260 {
0261   return get_if<I>(const_cast<fixed_variant<Ts...>*>(px));
0262 }
0263 
0264 template<typename T,typename... Ts>
0265 T* get_if(fixed_variant<Ts...>* px)noexcept
0266 {
0267   if(!px||!holds_alternative<T>(*px))return nullptr;
0268   else return std::addressof(unsafe_get<T>(*px));
0269 }
0270 
0271 template<typename T,typename... Ts>
0272 const T* get_if(const fixed_variant<Ts...>* px)noexcept
0273 {
0274   return get_if<T>(const_cast<fixed_variant<Ts...>*>(px));
0275 }
0276 
0277 struct deduced;
0278 
0279 template<typename R,typename F,typename... Vs>
0280 struct return_type_impl
0281 {
0282   using type=R;
0283 };
0284 
0285 template<typename F,typename... Vs>
0286 struct return_type_impl<deduced,F,Vs...>
0287 {
0288   using type=decltype(std::declval<F>()(get<0>(std::declval<Vs>())...));
0289 };
0290 
0291 template<typename R,typename F,typename... Vs>
0292 using return_type=typename return_type_impl<R,F,Vs...>::type;
0293 
0294 template<typename R,typename F,typename... Vs>
0295 struct visit_helper;
0296 
0297 template<typename R,typename F>
0298 struct visit_helper<R,F>
0299 {
0300   F&& f;
0301 
0302   R operator()(){return std::forward<F>(f)();}
0303 };
0304 
0305 template<typename F>
0306 struct visit_helper<void,F>
0307 {
0308   F&& f;
0309 
0310   void operator()(){(void)std::forward<F>(f)();}
0311 };
0312 
0313 template<
0314   typename R=deduced,typename F,
0315   typename ReturnType=return_type<R,F&&>
0316 >
0317 ReturnType visit(F&& f)
0318 {
0319   return visit_helper<ReturnType,F>{std::forward<F>(f)}();
0320 }
0321 
0322 template<typename R,typename F,typename V>
0323 struct visit_helper<R,F,V>
0324 {
0325   F&& f;
0326   V&& x;
0327 
0328   template<typename I>
0329   R operator()(I)
0330   {
0331     return std::forward<F>(f)(unsafe_get<I::value>(std::forward<V>(x)));
0332   }
0333 };
0334 
0335 template<typename F,typename V>
0336 struct visit_helper<void,F,V>
0337 {
0338   F&& f;
0339   V&& x;
0340 
0341   template<typename I>
0342   void operator()(I)
0343   {
0344     (void)std::forward<F>(f)(unsafe_get<I::value>(std::forward<V>(x)));
0345   }
0346 };
0347 
0348 template<
0349   typename R=deduced,typename F,typename V,
0350   typename ReturnType=return_type<R,F&&,V&&>
0351 >
0352 ReturnType visit(F&& f,V&& x)
0353 {
0354   using raw_variant=typename std::decay<V>::type;
0355 
0356   return mp11::mp_with_index<mp11::mp_size<raw_variant>::value>(
0357     x.index(),
0358     visit_helper<ReturnType,F,V>{std::forward<F>(f),std::forward<V>(x)});
0359 }
0360 
0361 template<typename R,typename F,typename V,typename I>
0362 struct bound_f
0363 {
0364   F&& f;
0365   V&& x;
0366 
0367   template<typename... Args>
0368   R operator()(Args&&... xs)
0369   {
0370     return std::forward<F>(f)(
0371       unsafe_get<I::value>(std::forward<V>(x)),std::forward<Args>(xs)...);
0372   }
0373 };
0374 
0375 template<typename F,typename V,typename I>
0376 struct bound_f<void,F,V,I>
0377 {
0378   F&& f;
0379   V&& x;
0380 
0381   template<typename... Args>
0382   void operator()(Args&&... xs)
0383   {
0384     (void)std::forward<F>(f)(
0385       unsafe_get<I::value>(std::forward<V>(x)),std::forward<Args>(xs)...);
0386   }
0387 };
0388 
0389 template<typename R,typename F>
0390 struct bound_visit;
0391 
0392 template<typename R,typename F,typename V,typename... Vs>
0393 struct visit_helper<R,F,V,Vs...>
0394 {
0395   F&&                 f;
0396   V&&                 x;
0397   std::tuple<Vs&&...> xs;
0398 
0399   template<typename I>
0400   R operator()(I)
0401   {
0402     return mp11::tuple_apply(
0403       bound_visit<R,bound_f<R,F,V,I>>{{std::forward<F>(f),std::forward<V>(x)}},
0404       std::move(xs));
0405   }
0406 };
0407 
0408 template<
0409   typename R=deduced,typename F,typename V1,typename V2,typename... Vs,
0410   typename ReturnType=return_type<R,F&&,V1&&,V2&&,Vs&&...>
0411 >
0412 ReturnType visit(F&& f,V1&& x1,V2&& x2,Vs&&... xs)
0413 {
0414   using raw_variant=typename std::decay<V1>::type;
0415 
0416   return mp11::mp_with_index<mp11::mp_size<raw_variant>::value>(
0417     x1.index(),
0418     visit_helper<ReturnType,F,V1,V2,Vs...>{
0419       std::forward<F>(f),std::forward<V1>(x1),
0420       std::forward_as_tuple(std::forward<V2>(x2),std::forward<Vs>(xs)...)});
0421 }
0422 
0423 template<typename R,typename F>
0424 struct bound_visit
0425 {
0426   F&& f;
0427 
0428   template<typename... Vs>
0429   R operator()(Vs&&... xs)
0430   {
0431     return visit<R>(std::forward<F>(f),std::forward<Vs>(xs)...);
0432   }
0433 };
0434 
0435 template<typename R,typename V,typename... Fs>
0436 struct return_type_by_index_impl
0437 {
0438   using type=R;
0439 };
0440 
0441 template<typename V,typename F,typename... Fs>
0442 struct return_type_by_index_impl<deduced,V,F,Fs...>
0443 {
0444   using type=decltype(std::declval<F>()(get<0>(std::declval<V>())));
0445 };
0446 
0447 template<typename R,typename V,typename... Fs>
0448 using return_type_by_index=typename return_type_by_index_impl<R,V,Fs...>::type;
0449 
0450 template<typename R,typename V,typename... Fs>
0451 struct visit_by_index_helper
0452 {
0453   V&&                 x;
0454   std::tuple<Fs&&...> fs;
0455 
0456   template<typename I>
0457   R operator()(I)
0458   {
0459     return std::get<I::value>(std::move(fs))(
0460       unsafe_get<I::value>(std::forward<V>(x)));
0461   }
0462 };
0463 
0464 template<typename V,typename... Fs>
0465 struct visit_by_index_helper<void,V,Fs...>
0466 {
0467   V&&                 x;
0468   std::tuple<Fs&&...> fs;
0469 
0470   template<typename I>
0471   void operator()(I)
0472   {
0473     (void)std::get<I::value>(std::move(fs))(
0474       unsafe_get<I::value>(std::forward<V>(x)));
0475   }
0476 };
0477 
0478 template<
0479   typename R=deduced,typename V,typename... Fs,
0480   typename ReturnType=return_type_by_index<R,V&&,Fs&&...>
0481 >
0482 ReturnType visit_by_index(V&& x,Fs&&... fs)
0483 {
0484   using raw_variant=typename std::decay<V>::type;
0485   static_assert(
0486     mp11::mp_size<raw_variant>::value==sizeof...(Fs),
0487     "the number of function objects must be the same as that of the "
0488     "alternative types in the variant");
0489 
0490   return mp11::mp_with_index<mp11::mp_size<raw_variant>::value>(
0491     x.index(),
0492     visit_by_index_helper<ReturnType,V,Fs...>{
0493       std::forward<V>(x),
0494       std::forward_as_tuple(std::forward<Fs>(fs)...)});
0495 }
0496 
0497 template<typename RelOp,typename ... Ts>
0498 struct relop_helper
0499 {
0500   const fixed_variant<Ts...> &x,&y;
0501 
0502   template<typename I> bool operator()(I)const
0503   {
0504     return RelOp{}(unsafe_get<I::value>(x),unsafe_get<I::value>(y));
0505   }
0506 };
0507 
0508 struct eq_
0509 {
0510   template<typename T>
0511   bool operator()(const T& x,const T& y)const{return x==y;}
0512 };
0513 
0514 template<typename... Ts>
0515 bool operator==(
0516   const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y)
0517 {
0518   return
0519     x.index()==y.index()&&
0520     mp11::mp_with_index<sizeof...(Ts)>(x.index(),relop_helper<eq_,Ts...>{x,y});
0521 }
0522 
0523 struct neq_
0524 {
0525   template<typename T>
0526   bool operator()(const T& x,const T& y)const{return x!=y;}
0527 };
0528 
0529 template<typename... Ts>
0530 bool operator!=(
0531   const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y)
0532 {
0533   return
0534     x.index()!=y.index()||
0535     mp11::mp_with_index<sizeof...(Ts)>(
0536       x.index(),relop_helper<neq_,Ts...>{x,y});
0537 }
0538 
0539 struct lt_
0540 {
0541   template<typename T>
0542   bool operator()(const T& x,const T& y)const{return x<y;}
0543 };
0544 
0545 template<typename... Ts>
0546 bool operator<(
0547   const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y)
0548 {
0549   return
0550     x.index()<y.index()||
0551     (x.index()==y.index()&&mp11::mp_with_index<sizeof...(Ts)>(
0552       x.index(),relop_helper<lt_,Ts...>{x,y}));
0553 }
0554 
0555 struct lte_
0556 {
0557   template<typename T>
0558   bool operator()(const T& x,const T& y)const{return x<=y;}
0559 };
0560 
0561 template<typename... Ts>
0562 bool operator<=(
0563   const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y)
0564 {
0565   return
0566     x.index()<y.index()||
0567     (x.index()==y.index()&&mp11::mp_with_index<sizeof...(Ts)>(
0568       x.index(),relop_helper<lte_,Ts...>{x,y}));
0569 }
0570 
0571 struct gt_
0572 {
0573   template<typename T>
0574   bool operator()(const T& x,const T& y)const{return x>y;}
0575 };
0576 
0577 template<typename... Ts>
0578 bool operator>(
0579   const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y)
0580 {
0581   return
0582     x.index()>y.index()||
0583     (x.index()==y.index()&&mp11::mp_with_index<sizeof...(Ts)>(
0584       x.index(),relop_helper<gt_,Ts...>{x,y}));
0585 }
0586 
0587 struct gte_
0588 {
0589   template<typename T>
0590   bool operator()(const T& x,const T& y)const{return x>=y;}
0591 };
0592 
0593 template<typename... Ts>
0594 bool operator>=(
0595   const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y)
0596 {
0597   return
0598     x.index()>y.index()||
0599     (x.index()==y.index()&&mp11::mp_with_index<sizeof...(Ts)>(
0600       x.index(),relop_helper<gte_,Ts...>{x,y}));
0601 }
0602 
0603 } /* namespace poly_collection::fixed_variant_impl */
0604 
0605 using boost::poly_collection::fixed_variant_impl::variant_size;
0606 
0607 #ifndef BOOST_NO_CXX14_VARIABLE_TEMPLATES
0608 using boost::poly_collection::fixed_variant_impl::variant_size_v;
0609 #endif
0610 
0611 using boost::poly_collection::fixed_variant_impl::bad_variant_access;
0612 using boost::poly_collection::fixed_variant_impl::variant_alternative;
0613 using boost::poly_collection::fixed_variant_impl::variant_alternative_t;
0614 using boost::poly_collection::fixed_variant_impl::visit;
0615 using boost::poly_collection::fixed_variant_impl::visit_by_index;
0616 using boost::poly_collection::fixed_variant_impl::holds_alternative;
0617 using boost::poly_collection::fixed_variant_impl::get;
0618 using boost::poly_collection::fixed_variant_impl::unsafe_get;
0619 using boost::poly_collection::fixed_variant_impl::get_if;
0620 
0621 } /* namespace poly_collection */
0622 
0623 } /* namespace boost */
0624 
0625 #endif