File indexing completed on 2025-09-13 08:43:01
0001
0002
0003
0004
0005
0006 #ifndef BOOST_PFR_DETAIL_CORE14_CLASSIC_HPP
0007 #define BOOST_PFR_DETAIL_CORE14_CLASSIC_HPP
0008 #pragma once
0009
0010 #include <boost/pfr/detail/config.hpp>
0011
0012 #ifdef BOOST_PFR_HAS_STD_MODULE
0013 import std;
0014 #else
0015 #include <type_traits>
0016 #include <utility> // metaprogramming stuff
0017 #endif
0018
0019 #include <boost/pfr/detail/sequence_tuple.hpp>
0020 #include <boost/pfr/detail/offset_based_getter.hpp>
0021 #include <boost/pfr/detail/fields_count.hpp>
0022 #include <boost/pfr/detail/make_flat_tuple_of_references.hpp>
0023 #include <boost/pfr/detail/make_integer_sequence.hpp>
0024 #include <boost/pfr/detail/size_array.hpp>
0025 #include <boost/pfr/detail/size_t_.hpp>
0026 #include <boost/pfr/detail/rvalue_t.hpp>
0027
0028 #ifdef __clang__
0029 # pragma clang diagnostic push
0030 # pragma clang diagnostic ignored "-Wmissing-braces"
0031 # pragma clang diagnostic ignored "-Wundefined-inline"
0032 # pragma clang diagnostic ignored "-Wundefined-internal"
0033 # pragma clang diagnostic ignored "-Wmissing-field-initializers"
0034 #endif
0035
0036 namespace boost { namespace pfr { namespace detail {
0037
0038
0039
0040 template <class T> struct identity {
0041 typedef T type;
0042 };
0043
0044 template <class T>
0045 constexpr T construct_helper() noexcept {
0046 return {};
0047 }
0048
0049 template <class T> constexpr size_array<sizeof(T) * 3> fields_count_and_type_ids_with_zeros() noexcept;
0050 template <class T> constexpr auto flat_array_of_type_ids() noexcept;
0051
0052
0053 namespace typeid_conversions {
0054
0055
0056
0057 #ifdef _MSC_VER
0058 # pragma warning( push )
0059
0060 # pragma warning( disable : 4554 )
0061 #endif
0062
0063 constexpr std::size_t native_types_mask = 31;
0064 constexpr std::size_t bits_per_extension = 3;
0065 constexpr std::size_t extension_mask = (
0066 static_cast<std::size_t>((1 << bits_per_extension) - 1)
0067 << static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
0068 );
0069 constexpr std::size_t native_ptr_type = (
0070 static_cast<std::size_t>(1)
0071 << static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
0072 );
0073 constexpr std::size_t native_const_ptr_type = (
0074 static_cast<std::size_t>(2)
0075 << static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
0076 );
0077
0078 constexpr std::size_t native_const_volatile_ptr_type = (
0079 static_cast<std::size_t>(3)
0080 << static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
0081 );
0082
0083 constexpr std::size_t native_volatile_ptr_type = (
0084 static_cast<std::size_t>(4)
0085 << static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
0086 );
0087
0088 constexpr std::size_t native_ref_type = (
0089 static_cast<std::size_t>(5)
0090 << static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
0091 );
0092
0093 template <std::size_t Index, std::size_t Extension>
0094 using if_extension = std::enable_if_t< (Index & extension_mask) == Extension >*;
0095
0096
0097 template <std::size_t Unptr>
0098 constexpr std::size_t type_to_id_extension_apply(std::size_t ext) noexcept {
0099 constexpr std::size_t native_id = (Unptr & native_types_mask);
0100 constexpr std::size_t extensions = (Unptr & ~native_types_mask);
0101 static_assert(
0102 !((extensions >> bits_per_extension) & native_types_mask),
0103 "====================> Boost.PFR: Too many extensions for a single field (something close to `int************************** p;` is in the POD type)."
0104 );
0105
0106 return (extensions >> bits_per_extension) | native_id | ext;
0107 }
0108
0109 template <std::size_t Index>
0110 using remove_1_ext = size_t_<
0111 ((Index & ~native_types_mask) << bits_per_extension) | (Index & native_types_mask)
0112 >;
0113
0114 #ifdef _MSC_VER
0115 # pragma warning( pop )
0116 #endif
0117
0118
0119
0120 template <class Type> constexpr std::size_t type_to_id(identity<Type*>) noexcept;
0121 template <class Type> constexpr std::size_t type_to_id(identity<const Type*>) noexcept;
0122 template <class Type> constexpr std::size_t type_to_id(identity<const volatile Type*>) noexcept;
0123 template <class Type> constexpr std::size_t type_to_id(identity<volatile Type*>) noexcept;
0124 template <class Type> constexpr std::size_t type_to_id(identity<Type&>) noexcept;
0125 template <class Type> constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_enum<Type>::value>* = nullptr) noexcept;
0126 template <class Type> constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_empty<Type>::value>* = nullptr) noexcept;
0127 template <class Type> constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_union<Type>::value>* = nullptr) noexcept;
0128 template <class Type> constexpr size_array<sizeof(Type) * 3> type_to_id(identity<Type>, std::enable_if_t<!std::is_enum<Type>::value && !std::is_empty<Type>::value && !std::is_union<Type>::value>* = 0) noexcept;
0129
0130 template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_const_ptr_type> = nullptr) noexcept;
0131 template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_ptr_type> = nullptr) noexcept;
0132 template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_const_volatile_ptr_type> = nullptr) noexcept;
0133 template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_volatile_ptr_type> = nullptr) noexcept;
0134 template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_ref_type> = nullptr) noexcept;
0135
0136
0137
0138
0139 #define BOOST_MAGIC_GET_REGISTER_TYPE(Type, Index) \
0140 constexpr std::size_t type_to_id(identity<Type>) noexcept { \
0141 return Index; \
0142 } \
0143 constexpr Type id_to_type( size_t_<Index > ) noexcept { \
0144 return detail::construct_helper<Type>(); \
0145 } \
0146
0147
0148
0149
0150
0151 BOOST_MAGIC_GET_REGISTER_TYPE(unsigned char , 1)
0152 BOOST_MAGIC_GET_REGISTER_TYPE(unsigned short , 2)
0153 BOOST_MAGIC_GET_REGISTER_TYPE(unsigned int , 3)
0154 BOOST_MAGIC_GET_REGISTER_TYPE(unsigned long , 4)
0155 BOOST_MAGIC_GET_REGISTER_TYPE(unsigned long long , 5)
0156 BOOST_MAGIC_GET_REGISTER_TYPE(signed char , 6)
0157 BOOST_MAGIC_GET_REGISTER_TYPE(short , 7)
0158 BOOST_MAGIC_GET_REGISTER_TYPE(int , 8)
0159 BOOST_MAGIC_GET_REGISTER_TYPE(long , 9)
0160 BOOST_MAGIC_GET_REGISTER_TYPE(long long , 10)
0161 BOOST_MAGIC_GET_REGISTER_TYPE(char , 11)
0162 BOOST_MAGIC_GET_REGISTER_TYPE(wchar_t , 12)
0163 BOOST_MAGIC_GET_REGISTER_TYPE(char16_t , 13)
0164 BOOST_MAGIC_GET_REGISTER_TYPE(char32_t , 14)
0165 BOOST_MAGIC_GET_REGISTER_TYPE(float , 15)
0166 BOOST_MAGIC_GET_REGISTER_TYPE(double , 16)
0167 BOOST_MAGIC_GET_REGISTER_TYPE(long double , 17)
0168 BOOST_MAGIC_GET_REGISTER_TYPE(bool , 18)
0169 BOOST_MAGIC_GET_REGISTER_TYPE(void* , 19)
0170 BOOST_MAGIC_GET_REGISTER_TYPE(const void* , 20)
0171 BOOST_MAGIC_GET_REGISTER_TYPE(volatile void* , 21)
0172 BOOST_MAGIC_GET_REGISTER_TYPE(const volatile void* , 22)
0173 BOOST_MAGIC_GET_REGISTER_TYPE(std::nullptr_t , 23)
0174 constexpr std::size_t tuple_begin_tag = 24;
0175 constexpr std::size_t tuple_end_tag = 25;
0176
0177 #undef BOOST_MAGIC_GET_REGISTER_TYPE
0178
0179
0180 template <class Type>
0181 constexpr std::size_t type_to_id(identity<Type*>) noexcept {
0182 constexpr auto unptr = typeid_conversions::type_to_id(identity<Type>{});
0183 static_assert(
0184 std::is_same<const std::size_t, decltype(unptr)>::value,
0185 "====================> Boost.PFR: Pointers to user defined types are not supported."
0186 );
0187 return typeid_conversions::type_to_id_extension_apply<unptr>(native_ptr_type);
0188 }
0189
0190 template <class Type>
0191 constexpr std::size_t type_to_id(identity<const Type*>) noexcept {
0192 constexpr auto unptr = typeid_conversions::type_to_id(identity<Type>{});
0193 static_assert(
0194 std::is_same<const std::size_t, decltype(unptr)>::value,
0195 "====================> Boost.PFR: Const pointers to user defined types are not supported."
0196 );
0197 return typeid_conversions::type_to_id_extension_apply<unptr>(native_const_ptr_type);
0198 }
0199
0200 template <class Type>
0201 constexpr std::size_t type_to_id(identity<const volatile Type*>) noexcept {
0202 constexpr auto unptr = typeid_conversions::type_to_id(identity<Type>{});
0203 static_assert(
0204 std::is_same<const std::size_t, decltype(unptr)>::value,
0205 "====================> Boost.PFR: Const volatile pointers to user defined types are not supported."
0206 );
0207 return typeid_conversions::type_to_id_extension_apply<unptr>(native_const_volatile_ptr_type);
0208 }
0209
0210 template <class Type>
0211 constexpr std::size_t type_to_id(identity<volatile Type*>) noexcept {
0212 constexpr auto unptr = typeid_conversions::type_to_id(identity<Type>{});
0213 static_assert(
0214 std::is_same<const std::size_t, decltype(unptr)>::value,
0215 "====================> Boost.PFR: Volatile pointers to user defined types are not supported."
0216 );
0217 return typeid_conversions::type_to_id_extension_apply<unptr>(native_volatile_ptr_type);
0218 }
0219
0220 template <class Type>
0221 constexpr std::size_t type_to_id(identity<Type&>) noexcept {
0222 constexpr auto unptr = typeid_conversions::type_to_id(identity<Type>{});
0223 static_assert(
0224 std::is_same<const std::size_t, decltype(unptr)>::value,
0225 "====================> Boost.PFR: References to user defined types are not supported."
0226 );
0227 return typeid_conversions::type_to_id_extension_apply<unptr>(native_ref_type);
0228 }
0229
0230 template <class Type>
0231 constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_enum<Type>::value>*) noexcept {
0232 return typeid_conversions::type_to_id(identity<typename std::underlying_type<Type>::type >{});
0233 }
0234
0235 template <class Type>
0236 constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_empty<Type>::value>*) noexcept {
0237 static_assert(!std::is_empty<Type>::value, "====================> Boost.PFR: Empty classes/structures as members are not supported.");
0238 return 0;
0239 }
0240
0241 template <class Type>
0242 constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_union<Type>::value>*) noexcept {
0243 static_assert(
0244 !std::is_union<Type>::value,
0245 "====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
0246 );
0247 return 0;
0248 }
0249
0250 template <class Type>
0251 constexpr size_array<sizeof(Type) * 3> type_to_id(identity<Type>, std::enable_if_t<!std::is_enum<Type>::value && !std::is_empty<Type>::value && !std::is_union<Type>::value>*) noexcept {
0252 constexpr auto t = detail::flat_array_of_type_ids<Type>();
0253 size_array<sizeof(Type) * 3> result {{tuple_begin_tag}};
0254 constexpr bool requires_tuplening = (
0255 (t.count_nonzeros() != 1) || (t.count_nonzeros() == t.count_from_opening_till_matching_parenthis_seq(0, tuple_begin_tag, tuple_end_tag))
0256 );
0257
0258 if (requires_tuplening) {
0259 for (std::size_t i = 0; i < t.size(); ++i)
0260 result.data[i + 1] = t.data[i];
0261 result.data[result.size() - 1] = tuple_end_tag;
0262 } else {
0263 for (std::size_t i = 0; i < t.size(); ++i)
0264 result.data[i] = t.data[i];
0265 }
0266 return result;
0267 }
0268
0269
0270
0271 template <std::size_t Index>
0272 constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_ptr_type>) noexcept {
0273 typedef decltype( typeid_conversions::id_to_type(remove_1_ext<Index>()) )* res_t;
0274 return detail::construct_helper<res_t>();
0275 }
0276
0277 template <std::size_t Index>
0278 constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_const_ptr_type>) noexcept {
0279 typedef const decltype( typeid_conversions::id_to_type(remove_1_ext<Index>()) )* res_t;
0280 return detail::construct_helper<res_t>();
0281 }
0282
0283 template <std::size_t Index>
0284 constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_const_volatile_ptr_type>) noexcept {
0285 typedef const volatile decltype( typeid_conversions::id_to_type(remove_1_ext<Index>()) )* res_t;
0286 return detail::construct_helper<res_t>();
0287 }
0288
0289
0290 template <std::size_t Index>
0291 constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_volatile_ptr_type>) noexcept {
0292 typedef volatile decltype( typeid_conversions::id_to_type(remove_1_ext<Index>()) )* res_t;
0293 return detail::construct_helper<res_t>();
0294 }
0295
0296
0297 template <std::size_t Index>
0298 constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_ref_type>) noexcept {
0299 static_assert(!Index, "====================> Boost.PFR: References are not supported");
0300 return nullptr;
0301 }
0302
0303 }
0304
0305
0306 struct ubiq_val {
0307 std::size_t* ref_;
0308
0309 template <class T>
0310 constexpr void assign(const T& typeids) const noexcept {
0311 for (std::size_t i = 0; i < T::size(); ++i)
0312 ref_[i] = typeids.data[i];
0313 }
0314
0315 constexpr void assign(std::size_t val) const noexcept {
0316 ref_[0] = val;
0317 }
0318
0319 template <class Type>
0320 constexpr operator Type() const noexcept {
0321 constexpr auto typeids = typeid_conversions::type_to_id(identity<Type>{});
0322 assign(typeids);
0323 return detail::construct_helper<Type>();
0324 }
0325 };
0326
0327
0328 struct ubiq_sizes {
0329 std::size_t& ref_;
0330
0331 template <class Type>
0332 constexpr operator Type() const noexcept {
0333 ref_ = sizeof(Type);
0334 return detail::construct_helper<Type>();
0335 }
0336 };
0337
0338
0339 template <class T, std::size_t N, std::size_t... I>
0340 constexpr size_array<N> get_type_offsets() noexcept {
0341 typedef size_array<N> array_t;
0342 array_t sizes{};
0343 T tmp{ ubiq_sizes{sizes.data[I]}... };
0344 (void)tmp;
0345
0346 array_t offsets{{0}};
0347 for (std::size_t i = 1; i < N; ++i)
0348 offsets.data[i] = offsets.data[i - 1] + sizes.data[i - 1];
0349
0350 return offsets;
0351 }
0352
0353
0354 template <class T, std::size_t N, std::size_t... I>
0355 constexpr void* flat_type_to_array_of_type_ids(std::size_t* types, std::index_sequence<I...>) noexcept
0356 {
0357 static_assert(
0358 N <= sizeof(T),
0359 "====================> Boost.PFR: Bit fields are not supported."
0360 );
0361
0362 constexpr auto offsets = detail::get_type_offsets<T, N, I...>();
0363 T tmp{ ubiq_val{types + get<I>(offsets) * 3}... };
0364 (void)types;
0365 (void)tmp;
0366 (void)offsets;
0367 return nullptr;
0368 }
0369
0370
0371 template <class T>
0372 constexpr size_array<sizeof(T) * 3> fields_count_and_type_ids_with_zeros() noexcept {
0373 size_array<sizeof(T) * 3> types{};
0374 constexpr std::size_t N = detail::fields_count<T>();
0375 detail::flat_type_to_array_of_type_ids<T, N>(types.data, detail::make_index_sequence<N>());
0376 return types;
0377 }
0378
0379
0380 template <class T>
0381 constexpr auto flat_array_of_type_ids() noexcept {
0382 constexpr auto types = detail::fields_count_and_type_ids_with_zeros<T>();
0383 constexpr std::size_t count = types.count_nonzeros();
0384 size_array<count> res{};
0385 std::size_t j = 0;
0386 for (std::size_t i = 0; i < decltype(types)::size(); ++i) {
0387 if (types.data[i]) {
0388 res.data[j] = types.data[i];
0389 ++ j;
0390 }
0391 }
0392
0393 return res;
0394 }
0395
0396
0397
0398 template <class T, std::size_t First, std::size_t... I>
0399 constexpr auto as_flat_tuple_impl(std::index_sequence<First, I...>) noexcept;
0400
0401 template <class T>
0402 constexpr sequence_tuple::tuple<> as_flat_tuple_impl(std::index_sequence<>) noexcept {
0403 return sequence_tuple::tuple<>{};
0404 }
0405
0406 template <std::size_t Increment, std::size_t... I>
0407 constexpr auto increment_index_sequence(std::index_sequence<I...>) noexcept {
0408 return std::index_sequence<I + Increment...>{};
0409 }
0410
0411 template <class T, std::size_t V, std::size_t I, std::size_t SubtupleLength>
0412 constexpr auto prepare_subtuples(size_t_<V>, size_t_<I>, size_t_<SubtupleLength>) noexcept {
0413 static_assert(SubtupleLength == 0, "====================> Boost.PFR: Internal error while representing nested field as tuple");
0414 return typeid_conversions::id_to_type(size_t_<V>{});
0415 }
0416
0417 template <class T, std::size_t I, std::size_t SubtupleLength>
0418 constexpr auto prepare_subtuples(size_t_<typeid_conversions::tuple_end_tag>, size_t_<I>, size_t_<SubtupleLength>) noexcept {
0419 static_assert(sizeof(T) == 0, "====================> Boost.PFR: Internal error while representing nested field as tuple");
0420 return int{};
0421 }
0422
0423 template <class T, std::size_t I, std::size_t SubtupleLength>
0424 constexpr auto prepare_subtuples(size_t_<typeid_conversions::tuple_begin_tag>, size_t_<I>, size_t_<SubtupleLength>) noexcept {
0425 static_assert(SubtupleLength > 2, "====================> Boost.PFR: Internal error while representing nested field as tuple");
0426 constexpr auto seq = detail::make_index_sequence<SubtupleLength - 2>{};
0427 return detail::as_flat_tuple_impl<T>( detail::increment_index_sequence<I + 1>(seq) );
0428 }
0429
0430
0431 template <class Array>
0432 constexpr Array remove_subtuples(Array indexes_plus_1, const Array& subtuple_lengths) noexcept {
0433 for (std::size_t i = 0; i < subtuple_lengths.size(); ++i) {
0434 if (subtuple_lengths.data[i]) {
0435 const std::size_t skips_count = subtuple_lengths.data[i];
0436 for (std::size_t j = i + 1; j < skips_count + i; ++j) {
0437 indexes_plus_1.data[j] = 0;
0438 }
0439 i += skips_count - 1;
0440 }
0441 }
0442 return indexes_plus_1;
0443 }
0444
0445 template <std::size_t N, class Array>
0446 constexpr size_array<N> resize_dropping_zeros_and_decrementing(size_t_<N>, const Array& a) noexcept {
0447 size_array<N> result{};
0448 std::size_t result_indx = 0;
0449 for (std::size_t i = 0; i < a.size(); ++i) {
0450 if (a.data[i]) {
0451 result.data[result_indx] = static_cast<std::size_t>(a.data[i] - 1);
0452 ++ result_indx;
0453 }
0454 }
0455
0456 return result;
0457 }
0458
0459 template <class T, std::size_t First, std::size_t... I, std::size_t... INew>
0460 constexpr auto as_flat_tuple_impl_drop_helpers(std::index_sequence<First, I...>, std::index_sequence<INew...>) noexcept {
0461 constexpr auto a = detail::flat_array_of_type_ids<T>();
0462
0463 constexpr size_array<sizeof...(I) + 1> subtuples_length {{
0464 a.count_from_opening_till_matching_parenthis_seq(First, typeid_conversions::tuple_begin_tag, typeid_conversions::tuple_end_tag),
0465 a.count_from_opening_till_matching_parenthis_seq(I, typeid_conversions::tuple_begin_tag, typeid_conversions::tuple_end_tag)...
0466 }};
0467
0468 constexpr size_array<sizeof...(I) + 1> type_indexes_with_subtuple_internals {{ 1, 1 + I - First...}};
0469 constexpr auto type_indexes_plus_1_and_zeros_as_skips = detail::remove_subtuples(type_indexes_with_subtuple_internals, subtuples_length);
0470 constexpr auto new_size = size_t_<type_indexes_plus_1_and_zeros_as_skips.count_nonzeros()>{};
0471 constexpr auto type_indexes = detail::resize_dropping_zeros_and_decrementing(new_size, type_indexes_plus_1_and_zeros_as_skips);
0472
0473 typedef sequence_tuple::tuple<
0474 decltype(detail::prepare_subtuples<T>(
0475 size_t_< a.data[ First + type_indexes.data[INew] ] >{},
0476 size_t_< First + type_indexes.data[INew] >{},
0477 size_t_< subtuples_length.data[ type_indexes.data[INew] ] >{}
0478 ))...
0479 > subtuples_uncleanuped_t;
0480
0481 return subtuples_uncleanuped_t{};
0482 }
0483
0484 template <class Array>
0485 constexpr std::size_t count_skips_in_array(std::size_t begin_index, std::size_t end_index, const Array& a) noexcept {
0486 std::size_t skips = 0;
0487 for (std::size_t i = begin_index; i < end_index; ++i) {
0488 if (a.data[i] == typeid_conversions::tuple_begin_tag) {
0489 const std::size_t this_tuple_size = a.count_from_opening_till_matching_parenthis_seq(i, typeid_conversions::tuple_begin_tag, typeid_conversions::tuple_end_tag) - 1;
0490 skips += this_tuple_size;
0491 i += this_tuple_size - 1;
0492 }
0493 }
0494
0495 return skips;
0496 }
0497
0498 template <class T, std::size_t First, std::size_t... I>
0499 constexpr auto as_flat_tuple_impl(std::index_sequence<First, I...>) noexcept {
0500 constexpr auto a = detail::flat_array_of_type_ids<T>();
0501 constexpr std::size_t count_of_I = sizeof...(I);
0502
0503 return detail::as_flat_tuple_impl_drop_helpers<T>(
0504 std::index_sequence<First, I...>{},
0505 detail::make_index_sequence< 1 + count_of_I - count_skips_in_array(First, First + count_of_I, a) >{}
0506 );
0507 }
0508
0509 template <class T>
0510 constexpr auto internal_tuple_with_same_alignment() noexcept {
0511 typedef typename std::remove_cv<T>::type type;
0512
0513 static_assert(
0514 std::is_trivial<type>::value && std::is_standard_layout<type>::value,
0515 "====================> Boost.PFR: Type can not be reflected without Loophole or C++17, because it's not POD"
0516 );
0517 static_assert(!std::is_reference<type>::value, "====================> Boost.PFR: Not applyable");
0518 constexpr auto res = detail::as_flat_tuple_impl<type>(
0519 detail::make_index_sequence< decltype(detail::flat_array_of_type_ids<type>())::size() >()
0520 );
0521
0522 return res;
0523 }
0524
0525 template <class T>
0526 using internal_tuple_with_same_alignment_t = decltype( detail::internal_tuple_with_same_alignment<T>() );
0527
0528
0529
0530 struct ubiq_is_flat_refelectable {
0531 bool& is_flat_refelectable;
0532
0533 template <class Type>
0534 constexpr operator Type() const noexcept {
0535 is_flat_refelectable = std::is_fundamental<std::remove_pointer_t<Type>>::value;
0536 return {};
0537 }
0538 };
0539
0540 template <class T, std::size_t... I>
0541 constexpr bool is_flat_refelectable(std::index_sequence<I...>) noexcept {
0542 constexpr std::size_t fields = sizeof...(I);
0543 bool result[fields] = {static_cast<bool>(I)...};
0544 const T v{ ubiq_is_flat_refelectable{result[I]}... };
0545 (void)v;
0546
0547 for (std::size_t i = 0; i < fields; ++i) {
0548 if (!result[i]) {
0549 return false;
0550 }
0551 }
0552
0553 return true;
0554 }
0555
0556 template<class T>
0557 constexpr bool is_flat_refelectable(std::index_sequence<>) noexcept {
0558 return true;
0559 }
0560
0561 template <class T>
0562 auto tie_as_flat_tuple(T& lvalue) noexcept {
0563 static_assert(
0564 !std::is_union<T>::value,
0565 "====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
0566 );
0567 using type = std::remove_cv_t<T>;
0568 using tuple_type = internal_tuple_with_same_alignment_t<type>;
0569
0570 offset_based_getter<type, tuple_type> getter;
0571 return boost::pfr::detail::make_flat_tuple_of_references(lvalue, getter, size_t_<0>{}, size_t_<tuple_type::size_v>{});
0572 }
0573
0574 template <class T>
0575 auto tie_as_tuple(T& val) noexcept {
0576 static_assert(
0577 !std::is_union<T>::value,
0578 "====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
0579 );
0580 static_assert(
0581 boost::pfr::detail::is_flat_refelectable<T>( detail::make_index_sequence<boost::pfr::detail::fields_count<T>()>{} ),
0582 "====================> Boost.PFR: Not possible in C++14 to represent that type without loosing information. Change type definition or enable C++17"
0583 );
0584 return boost::pfr::detail::tie_as_flat_tuple(val);
0585 }
0586
0587
0588
0589
0590 struct ubiq_constructor_constexpr_copy {
0591 std::size_t ignore;
0592
0593 template <class Type>
0594 constexpr operator Type() const noexcept {
0595 static_assert(
0596 std::is_trivially_destructible<Type>::value,
0597 "====================> Boost.PFR: One of the fields in the type passed to `for_each_field` has non trivial destructor."
0598 );
0599 return {};
0600 }
0601 };
0602
0603
0604
0605 template <class T, std::size_t... I>
0606 struct is_constexpr_aggregate_initializable {
0607 template<class T2, std::size_t... I2>
0608 static constexpr void* constexpr_aggregate_initializer() noexcept {
0609 T2 tmp{ ubiq_constructor_constexpr_copy{I2}... };
0610 (void)tmp;
0611 return nullptr;
0612 }
0613
0614 template <void* = constexpr_aggregate_initializer<T, I...>() >
0615 static std::true_type test(long) noexcept;
0616
0617 static std::false_type test(...) noexcept;
0618
0619 static constexpr bool value = decltype(test(0)){};
0620 };
0621
0622
0623 template <class T, class F, std::size_t I0, std::size_t... I, class... Fields>
0624 void for_each_field_in_depth(T& t, F&& f, std::index_sequence<I0, I...>, identity<Fields>...);
0625
0626 template <class T, class F, class... Fields>
0627 void for_each_field_in_depth(T& t, F&& f, std::index_sequence<>, identity<Fields>...);
0628
0629 template <class T, class F, class IndexSeq, class... Fields>
0630 struct next_step {
0631 T& t;
0632 F& f;
0633
0634 template <class Field>
0635 operator Field() const {
0636 boost::pfr::detail::for_each_field_in_depth(
0637 t,
0638 std::forward<F>(f),
0639 IndexSeq{},
0640 identity<Fields>{}...,
0641 identity<Field>{}
0642 );
0643
0644 return {};
0645 }
0646 };
0647
0648 template <class T, class F, std::size_t I0, std::size_t... I, class... Fields>
0649 void for_each_field_in_depth(T& t, F&& f, std::index_sequence<I0, I...>, identity<Fields>...) {
0650 (void)std::add_const_t<std::remove_reference_t<T>>{
0651 Fields{}...,
0652 next_step<T, F, std::index_sequence<I...>, Fields...>{t, f},
0653 ubiq_constructor_constexpr_copy{I}...
0654 };
0655 }
0656
0657 template <class T, class F, class... Fields>
0658 void for_each_field_in_depth(T& lvalue, F&& f, std::index_sequence<>, identity<Fields>...) {
0659 using tuple_type = sequence_tuple::tuple<Fields...>;
0660
0661 offset_based_getter<std::remove_cv_t<std::remove_reference_t<T>>, tuple_type> getter;
0662 std::forward<F>(f)(
0663 boost::pfr::detail::make_flat_tuple_of_references(lvalue, getter, size_t_<0>{}, size_t_<sizeof...(Fields)>{})
0664 );
0665 }
0666
0667 template <class T, class F, std::size_t... I>
0668 void for_each_field_dispatcher_1(T& t, F&& f, std::index_sequence<I...>, std::true_type ) {
0669 std::forward<F>(f)(
0670 boost::pfr::detail::tie_as_flat_tuple(t)
0671 );
0672 }
0673
0674
0675 template <class T, class F, std::size_t... I>
0676 void for_each_field_dispatcher_1(T& t, F&& f, std::index_sequence<I...>, std::false_type ) {
0677 boost::pfr::detail::for_each_field_in_depth(
0678 t,
0679 std::forward<F>(f),
0680 std::index_sequence<I...>{}
0681 );
0682 }
0683
0684 template <class T, class F, std::size_t... I>
0685 void for_each_field_dispatcher(T& t, F&& f, std::index_sequence<I...>) {
0686 static_assert(
0687 !std::is_union<T>::value,
0688 "====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
0689 );
0690 static_assert(is_constexpr_aggregate_initializable<T, I...>::value, "====================> Boost.PFR: T must be a constexpr initializable type");
0691
0692 constexpr bool is_flat_refelectable_val = detail::is_flat_refelectable<T>( std::index_sequence<I...>{} );
0693 detail::for_each_field_dispatcher_1(
0694 t,
0695 std::forward<F>(f),
0696 std::index_sequence<I...>{},
0697 std::integral_constant<bool, is_flat_refelectable_val>{}
0698 );
0699 }
0700
0701
0702
0703
0704 #ifdef __clang__
0705 # pragma clang diagnostic pop
0706 #endif
0707
0708 }}}
0709
0710 #endif