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