core14_classic.hpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  1. // Copyright (c) 2016-2024 Antony Polukhin
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_PFR_DETAIL_CORE14_CLASSIC_HPP
  6. #define BOOST_PFR_DETAIL_CORE14_CLASSIC_HPP
  7. #pragma once
  8. #include <boost/pfr/detail/config.hpp>
  9. #include <type_traits>
  10. #include <utility> // metaprogramming stuff
  11. #include <boost/pfr/detail/sequence_tuple.hpp>
  12. #include <boost/pfr/detail/offset_based_getter.hpp>
  13. #include <boost/pfr/detail/fields_count.hpp>
  14. #include <boost/pfr/detail/make_flat_tuple_of_references.hpp>
  15. #include <boost/pfr/detail/make_integer_sequence.hpp>
  16. #include <boost/pfr/detail/size_array.hpp>
  17. #include <boost/pfr/detail/size_t_.hpp>
  18. #include <boost/pfr/detail/rvalue_t.hpp>
  19. #ifdef __clang__
  20. # pragma clang diagnostic push
  21. # pragma clang diagnostic ignored "-Wmissing-braces"
  22. # pragma clang diagnostic ignored "-Wundefined-inline"
  23. # pragma clang diagnostic ignored "-Wundefined-internal"
  24. # pragma clang diagnostic ignored "-Wmissing-field-initializers"
  25. #endif
  26. namespace boost { namespace pfr { namespace detail {
  27. ///////////////////// General utility stuff
  28. template <class T> struct identity {
  29. typedef T type;
  30. };
  31. template <class T>
  32. constexpr T construct_helper() noexcept { // adding const here allows to deal with copyable only types
  33. return {};
  34. }
  35. template <class T> constexpr size_array<sizeof(T) * 3> fields_count_and_type_ids_with_zeros() noexcept;
  36. template <class T> constexpr auto flat_array_of_type_ids() noexcept;
  37. ///////////////////// All the stuff for representing Type as integer and converting integer back to type
  38. namespace typeid_conversions {
  39. ///////////////////// Helper constants and typedefs
  40. #ifdef _MSC_VER
  41. # pragma warning( push )
  42. // '<<': check operator precedence for possible error; use parentheses to clarify precedence
  43. # pragma warning( disable : 4554 )
  44. #endif
  45. constexpr std::size_t native_types_mask = 31;
  46. constexpr std::size_t bits_per_extension = 3;
  47. constexpr std::size_t extension_mask = (
  48. static_cast<std::size_t>((1 << bits_per_extension) - 1)
  49. << static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
  50. );
  51. constexpr std::size_t native_ptr_type = (
  52. static_cast<std::size_t>(1)
  53. << static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
  54. );
  55. constexpr std::size_t native_const_ptr_type = (
  56. static_cast<std::size_t>(2)
  57. << static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
  58. );
  59. constexpr std::size_t native_const_volatile_ptr_type = (
  60. static_cast<std::size_t>(3)
  61. << static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
  62. );
  63. constexpr std::size_t native_volatile_ptr_type = (
  64. static_cast<std::size_t>(4)
  65. << static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
  66. );
  67. constexpr std::size_t native_ref_type = (
  68. static_cast<std::size_t>(5)
  69. << static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
  70. );
  71. template <std::size_t Index, std::size_t Extension>
  72. using if_extension = std::enable_if_t< (Index & extension_mask) == Extension >*;
  73. ///////////////////// Helper functions
  74. template <std::size_t Unptr>
  75. constexpr std::size_t type_to_id_extension_apply(std::size_t ext) noexcept {
  76. constexpr std::size_t native_id = (Unptr & native_types_mask);
  77. constexpr std::size_t extensions = (Unptr & ~native_types_mask);
  78. static_assert(
  79. !((extensions >> bits_per_extension) & native_types_mask),
  80. "====================> Boost.PFR: Too many extensions for a single field (something close to `int************************** p;` is in the POD type)."
  81. );
  82. return (extensions >> bits_per_extension) | native_id | ext;
  83. }
  84. template <std::size_t Index>
  85. using remove_1_ext = size_t_<
  86. ((Index & ~native_types_mask) << bits_per_extension) | (Index & native_types_mask)
  87. >;
  88. #ifdef _MSC_VER
  89. # pragma warning( pop )
  90. #endif
  91. ///////////////////// Forward declarations
  92. template <class Type> constexpr std::size_t type_to_id(identity<Type*>) noexcept;
  93. template <class Type> constexpr std::size_t type_to_id(identity<const Type*>) noexcept;
  94. template <class Type> constexpr std::size_t type_to_id(identity<const volatile Type*>) noexcept;
  95. template <class Type> constexpr std::size_t type_to_id(identity<volatile Type*>) noexcept;
  96. template <class Type> constexpr std::size_t type_to_id(identity<Type&>) noexcept;
  97. template <class Type> constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_enum<Type>::value>* = nullptr) noexcept;
  98. template <class Type> constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_empty<Type>::value>* = nullptr) noexcept;
  99. template <class Type> constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_union<Type>::value>* = nullptr) noexcept;
  100. 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;
  101. template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_const_ptr_type> = nullptr) noexcept;
  102. template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_ptr_type> = nullptr) noexcept;
  103. template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_const_volatile_ptr_type> = nullptr) noexcept;
  104. template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_volatile_ptr_type> = nullptr) noexcept;
  105. template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_ref_type> = nullptr) noexcept;
  106. ///////////////////// Definitions of type_to_id and id_to_type for fundamental types
  107. /// @cond
  108. #define BOOST_MAGIC_GET_REGISTER_TYPE(Type, Index) \
  109. constexpr std::size_t type_to_id(identity<Type>) noexcept { \
  110. return Index; \
  111. } \
  112. constexpr Type id_to_type( size_t_<Index > ) noexcept { \
  113. return detail::construct_helper<Type>(); \
  114. } \
  115. /**/
  116. /// @endcond
  117. // Register all base types here
  118. BOOST_MAGIC_GET_REGISTER_TYPE(unsigned char , 1)
  119. BOOST_MAGIC_GET_REGISTER_TYPE(unsigned short , 2)
  120. BOOST_MAGIC_GET_REGISTER_TYPE(unsigned int , 3)
  121. BOOST_MAGIC_GET_REGISTER_TYPE(unsigned long , 4)
  122. BOOST_MAGIC_GET_REGISTER_TYPE(unsigned long long , 5)
  123. BOOST_MAGIC_GET_REGISTER_TYPE(signed char , 6)
  124. BOOST_MAGIC_GET_REGISTER_TYPE(short , 7)
  125. BOOST_MAGIC_GET_REGISTER_TYPE(int , 8)
  126. BOOST_MAGIC_GET_REGISTER_TYPE(long , 9)
  127. BOOST_MAGIC_GET_REGISTER_TYPE(long long , 10)
  128. BOOST_MAGIC_GET_REGISTER_TYPE(char , 11)
  129. BOOST_MAGIC_GET_REGISTER_TYPE(wchar_t , 12)
  130. BOOST_MAGIC_GET_REGISTER_TYPE(char16_t , 13)
  131. BOOST_MAGIC_GET_REGISTER_TYPE(char32_t , 14)
  132. BOOST_MAGIC_GET_REGISTER_TYPE(float , 15)
  133. BOOST_MAGIC_GET_REGISTER_TYPE(double , 16)
  134. BOOST_MAGIC_GET_REGISTER_TYPE(long double , 17)
  135. BOOST_MAGIC_GET_REGISTER_TYPE(bool , 18)
  136. BOOST_MAGIC_GET_REGISTER_TYPE(void* , 19)
  137. BOOST_MAGIC_GET_REGISTER_TYPE(const void* , 20)
  138. BOOST_MAGIC_GET_REGISTER_TYPE(volatile void* , 21)
  139. BOOST_MAGIC_GET_REGISTER_TYPE(const volatile void* , 22)
  140. BOOST_MAGIC_GET_REGISTER_TYPE(std::nullptr_t , 23)
  141. constexpr std::size_t tuple_begin_tag = 24;
  142. constexpr std::size_t tuple_end_tag = 25;
  143. #undef BOOST_MAGIC_GET_REGISTER_TYPE
  144. ///////////////////// Definitions of type_to_id and id_to_type for types with extensions and nested types
  145. template <class Type>
  146. constexpr std::size_t type_to_id(identity<Type*>) noexcept {
  147. constexpr auto unptr = typeid_conversions::type_to_id(identity<Type>{});
  148. static_assert(
  149. std::is_same<const std::size_t, decltype(unptr)>::value,
  150. "====================> Boost.PFR: Pointers to user defined types are not supported."
  151. );
  152. return typeid_conversions::type_to_id_extension_apply<unptr>(native_ptr_type);
  153. }
  154. template <class Type>
  155. constexpr std::size_t type_to_id(identity<const Type*>) noexcept {
  156. constexpr auto unptr = typeid_conversions::type_to_id(identity<Type>{});
  157. static_assert(
  158. std::is_same<const std::size_t, decltype(unptr)>::value,
  159. "====================> Boost.PFR: Const pointers to user defined types are not supported."
  160. );
  161. return typeid_conversions::type_to_id_extension_apply<unptr>(native_const_ptr_type);
  162. }
  163. template <class Type>
  164. constexpr std::size_t type_to_id(identity<const volatile Type*>) noexcept {
  165. constexpr auto unptr = typeid_conversions::type_to_id(identity<Type>{});
  166. static_assert(
  167. std::is_same<const std::size_t, decltype(unptr)>::value,
  168. "====================> Boost.PFR: Const volatile pointers to user defined types are not supported."
  169. );
  170. return typeid_conversions::type_to_id_extension_apply<unptr>(native_const_volatile_ptr_type);
  171. }
  172. template <class Type>
  173. constexpr std::size_t type_to_id(identity<volatile Type*>) noexcept {
  174. constexpr auto unptr = typeid_conversions::type_to_id(identity<Type>{});
  175. static_assert(
  176. std::is_same<const std::size_t, decltype(unptr)>::value,
  177. "====================> Boost.PFR: Volatile pointers to user defined types are not supported."
  178. );
  179. return typeid_conversions::type_to_id_extension_apply<unptr>(native_volatile_ptr_type);
  180. }
  181. template <class Type>
  182. constexpr std::size_t type_to_id(identity<Type&>) noexcept {
  183. constexpr auto unptr = typeid_conversions::type_to_id(identity<Type>{});
  184. static_assert(
  185. std::is_same<const std::size_t, decltype(unptr)>::value,
  186. "====================> Boost.PFR: References to user defined types are not supported."
  187. );
  188. return typeid_conversions::type_to_id_extension_apply<unptr>(native_ref_type);
  189. }
  190. template <class Type>
  191. constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_enum<Type>::value>*) noexcept {
  192. return typeid_conversions::type_to_id(identity<typename std::underlying_type<Type>::type >{});
  193. }
  194. template <class Type>
  195. constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_empty<Type>::value>*) noexcept {
  196. static_assert(!std::is_empty<Type>::value, "====================> Boost.PFR: Empty classes/structures as members are not supported.");
  197. return 0;
  198. }
  199. template <class Type>
  200. constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_union<Type>::value>*) noexcept {
  201. static_assert(
  202. !std::is_union<Type>::value,
  203. "====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
  204. );
  205. return 0;
  206. }
  207. template <class Type>
  208. 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 {
  209. constexpr auto t = detail::flat_array_of_type_ids<Type>();
  210. size_array<sizeof(Type) * 3> result {{tuple_begin_tag}};
  211. constexpr bool requires_tuplening = (
  212. (t.count_nonzeros() != 1) || (t.count_nonzeros() == t.count_from_opening_till_matching_parenthis_seq(0, tuple_begin_tag, tuple_end_tag))
  213. );
  214. if (requires_tuplening) {
  215. for (std::size_t i = 0; i < t.size(); ++i)
  216. result.data[i + 1] = t.data[i];
  217. result.data[result.size() - 1] = tuple_end_tag;
  218. } else {
  219. for (std::size_t i = 0; i < t.size(); ++i)
  220. result.data[i] = t.data[i];
  221. }
  222. return result;
  223. }
  224. template <std::size_t Index>
  225. constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_ptr_type>) noexcept {
  226. typedef decltype( typeid_conversions::id_to_type(remove_1_ext<Index>()) )* res_t;
  227. return detail::construct_helper<res_t>();
  228. }
  229. template <std::size_t Index>
  230. constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_const_ptr_type>) noexcept {
  231. typedef const decltype( typeid_conversions::id_to_type(remove_1_ext<Index>()) )* res_t;
  232. return detail::construct_helper<res_t>();
  233. }
  234. template <std::size_t Index>
  235. constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_const_volatile_ptr_type>) noexcept {
  236. typedef const volatile decltype( typeid_conversions::id_to_type(remove_1_ext<Index>()) )* res_t;
  237. return detail::construct_helper<res_t>();
  238. }
  239. template <std::size_t Index>
  240. constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_volatile_ptr_type>) noexcept {
  241. typedef volatile decltype( typeid_conversions::id_to_type(remove_1_ext<Index>()) )* res_t;
  242. return detail::construct_helper<res_t>();
  243. }
  244. template <std::size_t Index>
  245. constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_ref_type>) noexcept {
  246. static_assert(!Index, "====================> Boost.PFR: References are not supported");
  247. return nullptr;
  248. }
  249. } // namespace typeid_conversions
  250. ///////////////////// Structure that remembers types as integers on a `constexpr operator Type()` call
  251. struct ubiq_val {
  252. std::size_t* ref_;
  253. template <class T>
  254. constexpr void assign(const T& typeids) const noexcept {
  255. for (std::size_t i = 0; i < T::size(); ++i)
  256. ref_[i] = typeids.data[i];
  257. }
  258. constexpr void assign(std::size_t val) const noexcept {
  259. ref_[0] = val;
  260. }
  261. template <class Type>
  262. constexpr operator Type() const noexcept {
  263. constexpr auto typeids = typeid_conversions::type_to_id(identity<Type>{});
  264. assign(typeids);
  265. return detail::construct_helper<Type>();
  266. }
  267. };
  268. ///////////////////// Structure that remembers size of the type on a `constexpr operator Type()` call
  269. struct ubiq_sizes {
  270. std::size_t& ref_;
  271. template <class Type>
  272. constexpr operator Type() const noexcept {
  273. ref_ = sizeof(Type);
  274. return detail::construct_helper<Type>();
  275. }
  276. };
  277. ///////////////////// Returns array of (offsets without accounting alignments). Required for keeping places for nested type ids
  278. template <class T, std::size_t N, std::size_t... I>
  279. constexpr size_array<N> get_type_offsets() noexcept {
  280. typedef size_array<N> array_t;
  281. array_t sizes{};
  282. T tmp{ ubiq_sizes{sizes.data[I]}... };
  283. (void)tmp;
  284. array_t offsets{{0}};
  285. for (std::size_t i = 1; i < N; ++i)
  286. offsets.data[i] = offsets.data[i - 1] + sizes.data[i - 1];
  287. return offsets;
  288. }
  289. ///////////////////// Returns array of typeids and zeros if constructor of a type accepts sizeof...(I) parameters
  290. template <class T, std::size_t N, std::size_t... I>
  291. constexpr void* flat_type_to_array_of_type_ids(std::size_t* types, std::index_sequence<I...>) noexcept
  292. {
  293. static_assert(
  294. N <= sizeof(T),
  295. "====================> Boost.PFR: Bit fields are not supported."
  296. );
  297. constexpr auto offsets = detail::get_type_offsets<T, N, I...>();
  298. T tmp{ ubiq_val{types + get<I>(offsets) * 3}... };
  299. (void)types;
  300. (void)tmp;
  301. (void)offsets; // If type is empty offsets are not used
  302. return nullptr;
  303. }
  304. ///////////////////// Returns array of typeids and zeros
  305. template <class T>
  306. constexpr size_array<sizeof(T) * 3> fields_count_and_type_ids_with_zeros() noexcept {
  307. size_array<sizeof(T) * 3> types{};
  308. constexpr std::size_t N = detail::fields_count<T>();
  309. detail::flat_type_to_array_of_type_ids<T, N>(types.data, detail::make_index_sequence<N>());
  310. return types;
  311. }
  312. ///////////////////// Returns array of typeids without zeros
  313. template <class T>
  314. constexpr auto flat_array_of_type_ids() noexcept {
  315. constexpr auto types = detail::fields_count_and_type_ids_with_zeros<T>();
  316. constexpr std::size_t count = types.count_nonzeros();
  317. size_array<count> res{};
  318. std::size_t j = 0;
  319. for (std::size_t i = 0; i < decltype(types)::size(); ++i) {
  320. if (types.data[i]) {
  321. res.data[j] = types.data[i];
  322. ++ j;
  323. }
  324. }
  325. return res;
  326. }
  327. ///////////////////// Convert array of typeids into sequence_tuple::tuple
  328. template <class T, std::size_t First, std::size_t... I>
  329. constexpr auto as_flat_tuple_impl(std::index_sequence<First, I...>) noexcept;
  330. template <class T>
  331. constexpr sequence_tuple::tuple<> as_flat_tuple_impl(std::index_sequence<>) noexcept {
  332. return sequence_tuple::tuple<>{};
  333. }
  334. template <std::size_t Increment, std::size_t... I>
  335. constexpr auto increment_index_sequence(std::index_sequence<I...>) noexcept {
  336. return std::index_sequence<I + Increment...>{};
  337. }
  338. template <class T, std::size_t V, std::size_t I, std::size_t SubtupleLength>
  339. constexpr auto prepare_subtuples(size_t_<V>, size_t_<I>, size_t_<SubtupleLength>) noexcept {
  340. static_assert(SubtupleLength == 0, "====================> Boost.PFR: Internal error while representing nested field as tuple");
  341. return typeid_conversions::id_to_type(size_t_<V>{});
  342. }
  343. template <class T, std::size_t I, std::size_t SubtupleLength>
  344. constexpr auto prepare_subtuples(size_t_<typeid_conversions::tuple_end_tag>, size_t_<I>, size_t_<SubtupleLength>) noexcept {
  345. static_assert(sizeof(T) == 0, "====================> Boost.PFR: Internal error while representing nested field as tuple");
  346. return int{};
  347. }
  348. template <class T, std::size_t I, std::size_t SubtupleLength>
  349. constexpr auto prepare_subtuples(size_t_<typeid_conversions::tuple_begin_tag>, size_t_<I>, size_t_<SubtupleLength>) noexcept {
  350. static_assert(SubtupleLength > 2, "====================> Boost.PFR: Internal error while representing nested field as tuple");
  351. constexpr auto seq = detail::make_index_sequence<SubtupleLength - 2>{};
  352. return detail::as_flat_tuple_impl<T>( detail::increment_index_sequence<I + 1>(seq) );
  353. }
  354. template <class Array>
  355. constexpr Array remove_subtuples(Array indexes_plus_1, const Array& subtuple_lengths) noexcept {
  356. for (std::size_t i = 0; i < subtuple_lengths.size(); ++i) {
  357. if (subtuple_lengths.data[i]) {
  358. const std::size_t skips_count = subtuple_lengths.data[i];
  359. for (std::size_t j = i + 1; j < skips_count + i; ++j) {
  360. indexes_plus_1.data[j] = 0;
  361. }
  362. i += skips_count - 1;
  363. }
  364. }
  365. return indexes_plus_1;
  366. }
  367. template <std::size_t N, class Array>
  368. constexpr size_array<N> resize_dropping_zeros_and_decrementing(size_t_<N>, const Array& a) noexcept {
  369. size_array<N> result{};
  370. std::size_t result_indx = 0;
  371. for (std::size_t i = 0; i < a.size(); ++i) {
  372. if (a.data[i]) {
  373. result.data[result_indx] = static_cast<std::size_t>(a.data[i] - 1);
  374. ++ result_indx;
  375. }
  376. }
  377. return result;
  378. }
  379. template <class T, std::size_t First, std::size_t... I, std::size_t... INew>
  380. constexpr auto as_flat_tuple_impl_drop_helpers(std::index_sequence<First, I...>, std::index_sequence<INew...>) noexcept {
  381. constexpr auto a = detail::flat_array_of_type_ids<T>();
  382. constexpr size_array<sizeof...(I) + 1> subtuples_length {{
  383. a.count_from_opening_till_matching_parenthis_seq(First, typeid_conversions::tuple_begin_tag, typeid_conversions::tuple_end_tag),
  384. a.count_from_opening_till_matching_parenthis_seq(I, typeid_conversions::tuple_begin_tag, typeid_conversions::tuple_end_tag)...
  385. }};
  386. constexpr size_array<sizeof...(I) + 1> type_indexes_with_subtuple_internals {{ 1, 1 + I - First...}};
  387. constexpr auto type_indexes_plus_1_and_zeros_as_skips = detail::remove_subtuples(type_indexes_with_subtuple_internals, subtuples_length);
  388. constexpr auto new_size = size_t_<type_indexes_plus_1_and_zeros_as_skips.count_nonzeros()>{};
  389. constexpr auto type_indexes = detail::resize_dropping_zeros_and_decrementing(new_size, type_indexes_plus_1_and_zeros_as_skips);
  390. typedef sequence_tuple::tuple<
  391. decltype(detail::prepare_subtuples<T>(
  392. size_t_< a.data[ First + type_indexes.data[INew] ] >{}, // id of type
  393. size_t_< First + type_indexes.data[INew] >{}, // index of current id in `a`
  394. size_t_< subtuples_length.data[ type_indexes.data[INew] ] >{} // if id of type is tuple, then length of that tuple
  395. ))...
  396. > subtuples_uncleanuped_t;
  397. return subtuples_uncleanuped_t{};
  398. }
  399. template <class Array>
  400. constexpr std::size_t count_skips_in_array(std::size_t begin_index, std::size_t end_index, const Array& a) noexcept {
  401. std::size_t skips = 0;
  402. for (std::size_t i = begin_index; i < end_index; ++i) {
  403. if (a.data[i] == typeid_conversions::tuple_begin_tag) {
  404. 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;
  405. skips += this_tuple_size;
  406. i += this_tuple_size - 1;
  407. }
  408. }
  409. return skips;
  410. }
  411. template <class T, std::size_t First, std::size_t... I>
  412. constexpr auto as_flat_tuple_impl(std::index_sequence<First, I...>) noexcept {
  413. constexpr auto a = detail::flat_array_of_type_ids<T>();
  414. constexpr std::size_t count_of_I = sizeof...(I);
  415. return detail::as_flat_tuple_impl_drop_helpers<T>(
  416. std::index_sequence<First, I...>{},
  417. detail::make_index_sequence< 1 + count_of_I - count_skips_in_array(First, First + count_of_I, a) >{}
  418. );
  419. }
  420. template <class T>
  421. constexpr auto internal_tuple_with_same_alignment() noexcept {
  422. typedef typename std::remove_cv<T>::type type;
  423. static_assert(
  424. std::is_trivial<type>::value && std::is_standard_layout<type>::value,
  425. "====================> Boost.PFR: Type can not be reflected without Loophole or C++17, because it's not POD"
  426. );
  427. static_assert(!std::is_reference<type>::value, "====================> Boost.PFR: Not applyable");
  428. constexpr auto res = detail::as_flat_tuple_impl<type>(
  429. detail::make_index_sequence< decltype(detail::flat_array_of_type_ids<type>())::size() >()
  430. );
  431. return res;
  432. }
  433. template <class T>
  434. using internal_tuple_with_same_alignment_t = decltype( detail::internal_tuple_with_same_alignment<T>() );
  435. ///////////////////// Flattening
  436. struct ubiq_is_flat_refelectable {
  437. bool& is_flat_refelectable;
  438. template <class Type>
  439. constexpr operator Type() const noexcept {
  440. is_flat_refelectable = std::is_fundamental<std::remove_pointer_t<Type>>::value;
  441. return {};
  442. }
  443. };
  444. template <class T, std::size_t... I>
  445. constexpr bool is_flat_refelectable(std::index_sequence<I...>) noexcept {
  446. constexpr std::size_t fields = sizeof...(I);
  447. bool result[fields] = {static_cast<bool>(I)...};
  448. const T v{ ubiq_is_flat_refelectable{result[I]}... };
  449. (void)v;
  450. for (std::size_t i = 0; i < fields; ++i) {
  451. if (!result[i]) {
  452. return false;
  453. }
  454. }
  455. return true;
  456. }
  457. template<class T>
  458. constexpr bool is_flat_refelectable(std::index_sequence<>) noexcept {
  459. return true; ///< all empty structs always flat refelectable
  460. }
  461. template <class T>
  462. auto tie_as_flat_tuple(T& lvalue) noexcept {
  463. static_assert(
  464. !std::is_union<T>::value,
  465. "====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
  466. );
  467. using type = std::remove_cv_t<T>;
  468. using tuple_type = internal_tuple_with_same_alignment_t<type>;
  469. offset_based_getter<type, tuple_type> getter;
  470. return boost::pfr::detail::make_flat_tuple_of_references(lvalue, getter, size_t_<0>{}, size_t_<tuple_type::size_v>{});
  471. }
  472. template <class T>
  473. auto tie_as_tuple(T& val) noexcept {
  474. static_assert(
  475. !std::is_union<T>::value,
  476. "====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
  477. );
  478. static_assert(
  479. boost::pfr::detail::is_flat_refelectable<T>( detail::make_index_sequence<boost::pfr::detail::fields_count<T>()>{} ),
  480. "====================> Boost.PFR: Not possible in C++14 to represent that type without loosing information. Change type definition or enable C++17"
  481. );
  482. return boost::pfr::detail::tie_as_flat_tuple(val);
  483. }
  484. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  485. ///////////////////// Structure that can be converted to copy of anything
  486. struct ubiq_constructor_constexpr_copy {
  487. std::size_t ignore;
  488. template <class Type>
  489. constexpr operator Type() const noexcept {
  490. static_assert(
  491. std::is_trivially_destructible<Type>::value,
  492. "====================> Boost.PFR: One of the fields in the type passed to `for_each_field` has non trivial destructor."
  493. );
  494. return {};
  495. }
  496. };
  497. /////////////////////
  498. template <class T, std::size_t... I>
  499. struct is_constexpr_aggregate_initializable {
  500. template<class T2, std::size_t... I2>
  501. static constexpr void* constexpr_aggregate_initializer() noexcept {
  502. T2 tmp{ ubiq_constructor_constexpr_copy{I2}... };
  503. (void)tmp;
  504. return nullptr;
  505. }
  506. template <void* = constexpr_aggregate_initializer<T, I...>() >
  507. static std::true_type test(long) noexcept;
  508. static std::false_type test(...) noexcept;
  509. static constexpr bool value = decltype(test(0)){};
  510. };
  511. template <class T, class F, std::size_t I0, std::size_t... I, class... Fields>
  512. void for_each_field_in_depth(T& t, F&& f, std::index_sequence<I0, I...>, identity<Fields>...);
  513. template <class T, class F, class... Fields>
  514. void for_each_field_in_depth(T& t, F&& f, std::index_sequence<>, identity<Fields>...);
  515. template <class T, class F, class IndexSeq, class... Fields>
  516. struct next_step {
  517. T& t;
  518. F& f;
  519. template <class Field>
  520. operator Field() const {
  521. boost::pfr::detail::for_each_field_in_depth(
  522. t,
  523. std::forward<F>(f),
  524. IndexSeq{},
  525. identity<Fields>{}...,
  526. identity<Field>{}
  527. );
  528. return {};
  529. }
  530. };
  531. template <class T, class F, std::size_t I0, std::size_t... I, class... Fields>
  532. void for_each_field_in_depth(T& t, F&& f, std::index_sequence<I0, I...>, identity<Fields>...) {
  533. (void)std::add_const_t<std::remove_reference_t<T>>{
  534. Fields{}...,
  535. next_step<T, F, std::index_sequence<I...>, Fields...>{t, f},
  536. ubiq_constructor_constexpr_copy{I}...
  537. };
  538. }
  539. template <class T, class F, class... Fields>
  540. void for_each_field_in_depth(T& lvalue, F&& f, std::index_sequence<>, identity<Fields>...) {
  541. using tuple_type = sequence_tuple::tuple<Fields...>;
  542. offset_based_getter<std::remove_cv_t<std::remove_reference_t<T>>, tuple_type> getter;
  543. std::forward<F>(f)(
  544. boost::pfr::detail::make_flat_tuple_of_references(lvalue, getter, size_t_<0>{}, size_t_<sizeof...(Fields)>{})
  545. );
  546. }
  547. template <class T, class F, std::size_t... I>
  548. void for_each_field_dispatcher_1(T& t, F&& f, std::index_sequence<I...>, std::true_type /*is_flat_refelectable*/) {
  549. std::forward<F>(f)(
  550. boost::pfr::detail::tie_as_flat_tuple(t)
  551. );
  552. }
  553. template <class T, class F, std::size_t... I>
  554. void for_each_field_dispatcher_1(T& t, F&& f, std::index_sequence<I...>, std::false_type /*is_flat_refelectable*/) {
  555. boost::pfr::detail::for_each_field_in_depth(
  556. t,
  557. std::forward<F>(f),
  558. std::index_sequence<I...>{}
  559. );
  560. }
  561. template <class T, class F, std::size_t... I>
  562. void for_each_field_dispatcher(T& t, F&& f, std::index_sequence<I...>) {
  563. static_assert(
  564. !std::is_union<T>::value,
  565. "====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
  566. );
  567. static_assert(is_constexpr_aggregate_initializable<T, I...>::value, "====================> Boost.PFR: T must be a constexpr initializable type");
  568. constexpr bool is_flat_refelectable_val = detail::is_flat_refelectable<T>( std::index_sequence<I...>{} );
  569. detail::for_each_field_dispatcher_1(
  570. t,
  571. std::forward<F>(f),
  572. std::index_sequence<I...>{},
  573. std::integral_constant<bool, is_flat_refelectable_val>{}
  574. );
  575. }
  576. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  577. #ifdef __clang__
  578. # pragma clang diagnostic pop
  579. #endif
  580. }}} // namespace boost::pfr::detail
  581. #endif // BOOST_PFR_DETAIL_CORE14_CLASSIC_HPP