File indexing completed on 2025-09-17 08:45:56
0001
0002
0003
0004
0005
0006
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
0042
0043
0044
0045
0046
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
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 }
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 }
0622
0623 }
0624
0625 #endif