Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-13 08:43:01

0001 // Copyright (c) 2016-2025 Antony Polukhin
0002 //
0003 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0004 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
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 ///////////////////// General utility stuff
0039 
0040 template <class T> struct identity {
0041     typedef T type;
0042 };
0043 
0044 template <class T>
0045 constexpr T construct_helper() noexcept { // adding const here allows to deal with copyable only types
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 ///////////////////// All the stuff for representing Type as integer and converting integer back to type
0053 namespace typeid_conversions {
0054 
0055 ///////////////////// Helper constants and typedefs
0056 
0057 #ifdef _MSC_VER
0058 #   pragma warning( push )
0059     // '<<': check operator precedence for possible error; use parentheses to clarify precedence
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 ///////////////////// Helper functions
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 ///////////////////// Forward declarations
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 ///////////////////// Definitions of type_to_id and id_to_type for fundamental types
0138 /// @cond
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 /// @endcond
0148 
0149 
0150 // Register all base types here
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 ///////////////////// Definitions of type_to_id and id_to_type for types with extensions and nested types
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 } // namespace typeid_conversions
0304 
0305 ///////////////////// Structure that remembers types as integers on a `constexpr operator Type()` call
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 ///////////////////// Structure that remembers size of the type on a `constexpr operator Type()` call
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 ///////////////////// Returns array of (offsets without accounting alignments). Required for keeping places for nested type ids
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 ///////////////////// Returns array of typeids and zeros if constructor of a type accepts sizeof...(I) parameters
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; // If type is empty offsets are not used
0367     return nullptr;
0368 }
0369 
0370 ///////////////////// Returns array of typeids and zeros
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 ///////////////////// Returns array of typeids without zeros
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 ///////////////////// Convert array of typeids into sequence_tuple::tuple
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] ]          >{},    // id of type
0476             size_t_< First + type_indexes.data[INew]                    >{},    // index of current id in `a`
0477             size_t_< subtuples_length.data[ type_indexes.data[INew] ]   >{}     // if id of type is tuple, then length of that tuple
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 ///////////////////// Flattening
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; ///< all empty structs always flat refelectable
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 ///////////////////// Structure that can be converted to copy of anything
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 /*is_flat_refelectable*/) {
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 /*is_flat_refelectable*/) {
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 }}} // namespace boost::pfr::detail
0709 
0710 #endif // BOOST_PFR_DETAIL_CORE14_CLASSIC_HPP