123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706 |
- // Copyright (c) 2016-2024 Antony Polukhin
- //
- // Distributed under the Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- #ifndef BOOST_PFR_DETAIL_CORE14_CLASSIC_HPP
- #define BOOST_PFR_DETAIL_CORE14_CLASSIC_HPP
- #pragma once
- #include <boost/pfr/detail/config.hpp>
- #include <type_traits>
- #include <utility> // metaprogramming stuff
- #include <boost/pfr/detail/sequence_tuple.hpp>
- #include <boost/pfr/detail/offset_based_getter.hpp>
- #include <boost/pfr/detail/fields_count.hpp>
- #include <boost/pfr/detail/make_flat_tuple_of_references.hpp>
- #include <boost/pfr/detail/make_integer_sequence.hpp>
- #include <boost/pfr/detail/size_array.hpp>
- #include <boost/pfr/detail/size_t_.hpp>
- #include <boost/pfr/detail/rvalue_t.hpp>
- #ifdef __clang__
- # pragma clang diagnostic push
- # pragma clang diagnostic ignored "-Wmissing-braces"
- # pragma clang diagnostic ignored "-Wundefined-inline"
- # pragma clang diagnostic ignored "-Wundefined-internal"
- # pragma clang diagnostic ignored "-Wmissing-field-initializers"
- #endif
- namespace boost { namespace pfr { namespace detail {
- ///////////////////// General utility stuff
- template <class T> struct identity {
- typedef T type;
- };
- template <class T>
- constexpr T construct_helper() noexcept { // adding const here allows to deal with copyable only types
- return {};
- }
- template <class T> constexpr size_array<sizeof(T) * 3> fields_count_and_type_ids_with_zeros() noexcept;
- template <class T> constexpr auto flat_array_of_type_ids() noexcept;
- ///////////////////// All the stuff for representing Type as integer and converting integer back to type
- namespace typeid_conversions {
- ///////////////////// Helper constants and typedefs
- #ifdef _MSC_VER
- # pragma warning( push )
- // '<<': check operator precedence for possible error; use parentheses to clarify precedence
- # pragma warning( disable : 4554 )
- #endif
- constexpr std::size_t native_types_mask = 31;
- constexpr std::size_t bits_per_extension = 3;
- constexpr std::size_t extension_mask = (
- static_cast<std::size_t>((1 << bits_per_extension) - 1)
- << static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
- );
- constexpr std::size_t native_ptr_type = (
- static_cast<std::size_t>(1)
- << static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
- );
- constexpr std::size_t native_const_ptr_type = (
- static_cast<std::size_t>(2)
- << static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
- );
- constexpr std::size_t native_const_volatile_ptr_type = (
- static_cast<std::size_t>(3)
- << static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
- );
- constexpr std::size_t native_volatile_ptr_type = (
- static_cast<std::size_t>(4)
- << static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
- );
- constexpr std::size_t native_ref_type = (
- static_cast<std::size_t>(5)
- << static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
- );
- template <std::size_t Index, std::size_t Extension>
- using if_extension = std::enable_if_t< (Index & extension_mask) == Extension >*;
- ///////////////////// Helper functions
- template <std::size_t Unptr>
- constexpr std::size_t type_to_id_extension_apply(std::size_t ext) noexcept {
- constexpr std::size_t native_id = (Unptr & native_types_mask);
- constexpr std::size_t extensions = (Unptr & ~native_types_mask);
- static_assert(
- !((extensions >> bits_per_extension) & native_types_mask),
- "====================> Boost.PFR: Too many extensions for a single field (something close to `int************************** p;` is in the POD type)."
- );
- return (extensions >> bits_per_extension) | native_id | ext;
- }
- template <std::size_t Index>
- using remove_1_ext = size_t_<
- ((Index & ~native_types_mask) << bits_per_extension) | (Index & native_types_mask)
- >;
- #ifdef _MSC_VER
- # pragma warning( pop )
- #endif
- ///////////////////// Forward declarations
- template <class Type> constexpr std::size_t type_to_id(identity<Type*>) noexcept;
- template <class Type> constexpr std::size_t type_to_id(identity<const Type*>) noexcept;
- template <class Type> constexpr std::size_t type_to_id(identity<const volatile Type*>) noexcept;
- template <class Type> constexpr std::size_t type_to_id(identity<volatile Type*>) noexcept;
- template <class Type> constexpr std::size_t type_to_id(identity<Type&>) noexcept;
- template <class Type> constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_enum<Type>::value>* = nullptr) noexcept;
- template <class Type> constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_empty<Type>::value>* = nullptr) noexcept;
- template <class Type> constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_union<Type>::value>* = nullptr) noexcept;
- 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;
- template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_const_ptr_type> = nullptr) noexcept;
- template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_ptr_type> = nullptr) noexcept;
- template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_const_volatile_ptr_type> = nullptr) noexcept;
- template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_volatile_ptr_type> = nullptr) noexcept;
- template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_ref_type> = nullptr) noexcept;
- ///////////////////// Definitions of type_to_id and id_to_type for fundamental types
- /// @cond
- #define BOOST_MAGIC_GET_REGISTER_TYPE(Type, Index) \
- constexpr std::size_t type_to_id(identity<Type>) noexcept { \
- return Index; \
- } \
- constexpr Type id_to_type( size_t_<Index > ) noexcept { \
- return detail::construct_helper<Type>(); \
- } \
- /**/
- /// @endcond
- // Register all base types here
- BOOST_MAGIC_GET_REGISTER_TYPE(unsigned char , 1)
- BOOST_MAGIC_GET_REGISTER_TYPE(unsigned short , 2)
- BOOST_MAGIC_GET_REGISTER_TYPE(unsigned int , 3)
- BOOST_MAGIC_GET_REGISTER_TYPE(unsigned long , 4)
- BOOST_MAGIC_GET_REGISTER_TYPE(unsigned long long , 5)
- BOOST_MAGIC_GET_REGISTER_TYPE(signed char , 6)
- BOOST_MAGIC_GET_REGISTER_TYPE(short , 7)
- BOOST_MAGIC_GET_REGISTER_TYPE(int , 8)
- BOOST_MAGIC_GET_REGISTER_TYPE(long , 9)
- BOOST_MAGIC_GET_REGISTER_TYPE(long long , 10)
- BOOST_MAGIC_GET_REGISTER_TYPE(char , 11)
- BOOST_MAGIC_GET_REGISTER_TYPE(wchar_t , 12)
- BOOST_MAGIC_GET_REGISTER_TYPE(char16_t , 13)
- BOOST_MAGIC_GET_REGISTER_TYPE(char32_t , 14)
- BOOST_MAGIC_GET_REGISTER_TYPE(float , 15)
- BOOST_MAGIC_GET_REGISTER_TYPE(double , 16)
- BOOST_MAGIC_GET_REGISTER_TYPE(long double , 17)
- BOOST_MAGIC_GET_REGISTER_TYPE(bool , 18)
- BOOST_MAGIC_GET_REGISTER_TYPE(void* , 19)
- BOOST_MAGIC_GET_REGISTER_TYPE(const void* , 20)
- BOOST_MAGIC_GET_REGISTER_TYPE(volatile void* , 21)
- BOOST_MAGIC_GET_REGISTER_TYPE(const volatile void* , 22)
- BOOST_MAGIC_GET_REGISTER_TYPE(std::nullptr_t , 23)
- constexpr std::size_t tuple_begin_tag = 24;
- constexpr std::size_t tuple_end_tag = 25;
- #undef BOOST_MAGIC_GET_REGISTER_TYPE
- ///////////////////// Definitions of type_to_id and id_to_type for types with extensions and nested types
- template <class Type>
- constexpr std::size_t type_to_id(identity<Type*>) noexcept {
- constexpr auto unptr = typeid_conversions::type_to_id(identity<Type>{});
- static_assert(
- std::is_same<const std::size_t, decltype(unptr)>::value,
- "====================> Boost.PFR: Pointers to user defined types are not supported."
- );
- return typeid_conversions::type_to_id_extension_apply<unptr>(native_ptr_type);
- }
- template <class Type>
- constexpr std::size_t type_to_id(identity<const Type*>) noexcept {
- constexpr auto unptr = typeid_conversions::type_to_id(identity<Type>{});
- static_assert(
- std::is_same<const std::size_t, decltype(unptr)>::value,
- "====================> Boost.PFR: Const pointers to user defined types are not supported."
- );
- return typeid_conversions::type_to_id_extension_apply<unptr>(native_const_ptr_type);
- }
- template <class Type>
- constexpr std::size_t type_to_id(identity<const volatile Type*>) noexcept {
- constexpr auto unptr = typeid_conversions::type_to_id(identity<Type>{});
- static_assert(
- std::is_same<const std::size_t, decltype(unptr)>::value,
- "====================> Boost.PFR: Const volatile pointers to user defined types are not supported."
- );
- return typeid_conversions::type_to_id_extension_apply<unptr>(native_const_volatile_ptr_type);
- }
- template <class Type>
- constexpr std::size_t type_to_id(identity<volatile Type*>) noexcept {
- constexpr auto unptr = typeid_conversions::type_to_id(identity<Type>{});
- static_assert(
- std::is_same<const std::size_t, decltype(unptr)>::value,
- "====================> Boost.PFR: Volatile pointers to user defined types are not supported."
- );
- return typeid_conversions::type_to_id_extension_apply<unptr>(native_volatile_ptr_type);
- }
- template <class Type>
- constexpr std::size_t type_to_id(identity<Type&>) noexcept {
- constexpr auto unptr = typeid_conversions::type_to_id(identity<Type>{});
- static_assert(
- std::is_same<const std::size_t, decltype(unptr)>::value,
- "====================> Boost.PFR: References to user defined types are not supported."
- );
- return typeid_conversions::type_to_id_extension_apply<unptr>(native_ref_type);
- }
- template <class Type>
- constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_enum<Type>::value>*) noexcept {
- return typeid_conversions::type_to_id(identity<typename std::underlying_type<Type>::type >{});
- }
- template <class Type>
- constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_empty<Type>::value>*) noexcept {
- static_assert(!std::is_empty<Type>::value, "====================> Boost.PFR: Empty classes/structures as members are not supported.");
- return 0;
- }
- template <class Type>
- constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_union<Type>::value>*) noexcept {
- static_assert(
- !std::is_union<Type>::value,
- "====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
- );
- return 0;
- }
- 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>*) noexcept {
- constexpr auto t = detail::flat_array_of_type_ids<Type>();
- size_array<sizeof(Type) * 3> result {{tuple_begin_tag}};
- constexpr bool requires_tuplening = (
- (t.count_nonzeros() != 1) || (t.count_nonzeros() == t.count_from_opening_till_matching_parenthis_seq(0, tuple_begin_tag, tuple_end_tag))
- );
- if (requires_tuplening) {
- for (std::size_t i = 0; i < t.size(); ++i)
- result.data[i + 1] = t.data[i];
- result.data[result.size() - 1] = tuple_end_tag;
- } else {
- for (std::size_t i = 0; i < t.size(); ++i)
- result.data[i] = t.data[i];
- }
- return result;
- }
- template <std::size_t Index>
- constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_ptr_type>) noexcept {
- typedef decltype( typeid_conversions::id_to_type(remove_1_ext<Index>()) )* res_t;
- return detail::construct_helper<res_t>();
- }
- template <std::size_t Index>
- constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_const_ptr_type>) noexcept {
- typedef const decltype( typeid_conversions::id_to_type(remove_1_ext<Index>()) )* res_t;
- return detail::construct_helper<res_t>();
- }
- template <std::size_t Index>
- constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_const_volatile_ptr_type>) noexcept {
- typedef const volatile decltype( typeid_conversions::id_to_type(remove_1_ext<Index>()) )* res_t;
- return detail::construct_helper<res_t>();
- }
- template <std::size_t Index>
- constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_volatile_ptr_type>) noexcept {
- typedef volatile decltype( typeid_conversions::id_to_type(remove_1_ext<Index>()) )* res_t;
- return detail::construct_helper<res_t>();
- }
- template <std::size_t Index>
- constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_ref_type>) noexcept {
- static_assert(!Index, "====================> Boost.PFR: References are not supported");
- return nullptr;
- }
- } // namespace typeid_conversions
- ///////////////////// Structure that remembers types as integers on a `constexpr operator Type()` call
- struct ubiq_val {
- std::size_t* ref_;
- template <class T>
- constexpr void assign(const T& typeids) const noexcept {
- for (std::size_t i = 0; i < T::size(); ++i)
- ref_[i] = typeids.data[i];
- }
- constexpr void assign(std::size_t val) const noexcept {
- ref_[0] = val;
- }
- template <class Type>
- constexpr operator Type() const noexcept {
- constexpr auto typeids = typeid_conversions::type_to_id(identity<Type>{});
- assign(typeids);
- return detail::construct_helper<Type>();
- }
- };
- ///////////////////// Structure that remembers size of the type on a `constexpr operator Type()` call
- struct ubiq_sizes {
- std::size_t& ref_;
- template <class Type>
- constexpr operator Type() const noexcept {
- ref_ = sizeof(Type);
- return detail::construct_helper<Type>();
- }
- };
- ///////////////////// Returns array of (offsets without accounting alignments). Required for keeping places for nested type ids
- template <class T, std::size_t N, std::size_t... I>
- constexpr size_array<N> get_type_offsets() noexcept {
- typedef size_array<N> array_t;
- array_t sizes{};
- T tmp{ ubiq_sizes{sizes.data[I]}... };
- (void)tmp;
- array_t offsets{{0}};
- for (std::size_t i = 1; i < N; ++i)
- offsets.data[i] = offsets.data[i - 1] + sizes.data[i - 1];
- return offsets;
- }
- ///////////////////// Returns array of typeids and zeros if constructor of a type accepts sizeof...(I) parameters
- template <class T, std::size_t N, std::size_t... I>
- constexpr void* flat_type_to_array_of_type_ids(std::size_t* types, std::index_sequence<I...>) noexcept
- {
- static_assert(
- N <= sizeof(T),
- "====================> Boost.PFR: Bit fields are not supported."
- );
- constexpr auto offsets = detail::get_type_offsets<T, N, I...>();
- T tmp{ ubiq_val{types + get<I>(offsets) * 3}... };
- (void)types;
- (void)tmp;
- (void)offsets; // If type is empty offsets are not used
- return nullptr;
- }
- ///////////////////// Returns array of typeids and zeros
- template <class T>
- constexpr size_array<sizeof(T) * 3> fields_count_and_type_ids_with_zeros() noexcept {
- size_array<sizeof(T) * 3> types{};
- constexpr std::size_t N = detail::fields_count<T>();
- detail::flat_type_to_array_of_type_ids<T, N>(types.data, detail::make_index_sequence<N>());
- return types;
- }
- ///////////////////// Returns array of typeids without zeros
- template <class T>
- constexpr auto flat_array_of_type_ids() noexcept {
- constexpr auto types = detail::fields_count_and_type_ids_with_zeros<T>();
- constexpr std::size_t count = types.count_nonzeros();
- size_array<count> res{};
- std::size_t j = 0;
- for (std::size_t i = 0; i < decltype(types)::size(); ++i) {
- if (types.data[i]) {
- res.data[j] = types.data[i];
- ++ j;
- }
- }
- return res;
- }
- ///////////////////// Convert array of typeids into sequence_tuple::tuple
- template <class T, std::size_t First, std::size_t... I>
- constexpr auto as_flat_tuple_impl(std::index_sequence<First, I...>) noexcept;
- template <class T>
- constexpr sequence_tuple::tuple<> as_flat_tuple_impl(std::index_sequence<>) noexcept {
- return sequence_tuple::tuple<>{};
- }
- template <std::size_t Increment, std::size_t... I>
- constexpr auto increment_index_sequence(std::index_sequence<I...>) noexcept {
- return std::index_sequence<I + Increment...>{};
- }
- template <class T, std::size_t V, std::size_t I, std::size_t SubtupleLength>
- constexpr auto prepare_subtuples(size_t_<V>, size_t_<I>, size_t_<SubtupleLength>) noexcept {
- static_assert(SubtupleLength == 0, "====================> Boost.PFR: Internal error while representing nested field as tuple");
- return typeid_conversions::id_to_type(size_t_<V>{});
- }
- template <class T, std::size_t I, std::size_t SubtupleLength>
- constexpr auto prepare_subtuples(size_t_<typeid_conversions::tuple_end_tag>, size_t_<I>, size_t_<SubtupleLength>) noexcept {
- static_assert(sizeof(T) == 0, "====================> Boost.PFR: Internal error while representing nested field as tuple");
- return int{};
- }
- template <class T, std::size_t I, std::size_t SubtupleLength>
- constexpr auto prepare_subtuples(size_t_<typeid_conversions::tuple_begin_tag>, size_t_<I>, size_t_<SubtupleLength>) noexcept {
- static_assert(SubtupleLength > 2, "====================> Boost.PFR: Internal error while representing nested field as tuple");
- constexpr auto seq = detail::make_index_sequence<SubtupleLength - 2>{};
- return detail::as_flat_tuple_impl<T>( detail::increment_index_sequence<I + 1>(seq) );
- }
- template <class Array>
- constexpr Array remove_subtuples(Array indexes_plus_1, const Array& subtuple_lengths) noexcept {
- for (std::size_t i = 0; i < subtuple_lengths.size(); ++i) {
- if (subtuple_lengths.data[i]) {
- const std::size_t skips_count = subtuple_lengths.data[i];
- for (std::size_t j = i + 1; j < skips_count + i; ++j) {
- indexes_plus_1.data[j] = 0;
- }
- i += skips_count - 1;
- }
- }
- return indexes_plus_1;
- }
- template <std::size_t N, class Array>
- constexpr size_array<N> resize_dropping_zeros_and_decrementing(size_t_<N>, const Array& a) noexcept {
- size_array<N> result{};
- std::size_t result_indx = 0;
- for (std::size_t i = 0; i < a.size(); ++i) {
- if (a.data[i]) {
- result.data[result_indx] = static_cast<std::size_t>(a.data[i] - 1);
- ++ result_indx;
- }
- }
- return result;
- }
- template <class T, std::size_t First, std::size_t... I, std::size_t... INew>
- constexpr auto as_flat_tuple_impl_drop_helpers(std::index_sequence<First, I...>, std::index_sequence<INew...>) noexcept {
- constexpr auto a = detail::flat_array_of_type_ids<T>();
- constexpr size_array<sizeof...(I) + 1> subtuples_length {{
- a.count_from_opening_till_matching_parenthis_seq(First, typeid_conversions::tuple_begin_tag, typeid_conversions::tuple_end_tag),
- a.count_from_opening_till_matching_parenthis_seq(I, typeid_conversions::tuple_begin_tag, typeid_conversions::tuple_end_tag)...
- }};
- constexpr size_array<sizeof...(I) + 1> type_indexes_with_subtuple_internals {{ 1, 1 + I - First...}};
- constexpr auto type_indexes_plus_1_and_zeros_as_skips = detail::remove_subtuples(type_indexes_with_subtuple_internals, subtuples_length);
- constexpr auto new_size = size_t_<type_indexes_plus_1_and_zeros_as_skips.count_nonzeros()>{};
- constexpr auto type_indexes = detail::resize_dropping_zeros_and_decrementing(new_size, type_indexes_plus_1_and_zeros_as_skips);
- typedef sequence_tuple::tuple<
- decltype(detail::prepare_subtuples<T>(
- size_t_< a.data[ First + type_indexes.data[INew] ] >{}, // id of type
- size_t_< First + type_indexes.data[INew] >{}, // index of current id in `a`
- size_t_< subtuples_length.data[ type_indexes.data[INew] ] >{} // if id of type is tuple, then length of that tuple
- ))...
- > subtuples_uncleanuped_t;
- return subtuples_uncleanuped_t{};
- }
- template <class Array>
- constexpr std::size_t count_skips_in_array(std::size_t begin_index, std::size_t end_index, const Array& a) noexcept {
- std::size_t skips = 0;
- for (std::size_t i = begin_index; i < end_index; ++i) {
- if (a.data[i] == typeid_conversions::tuple_begin_tag) {
- 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;
- skips += this_tuple_size;
- i += this_tuple_size - 1;
- }
- }
- return skips;
- }
- template <class T, std::size_t First, std::size_t... I>
- constexpr auto as_flat_tuple_impl(std::index_sequence<First, I...>) noexcept {
- constexpr auto a = detail::flat_array_of_type_ids<T>();
- constexpr std::size_t count_of_I = sizeof...(I);
- return detail::as_flat_tuple_impl_drop_helpers<T>(
- std::index_sequence<First, I...>{},
- detail::make_index_sequence< 1 + count_of_I - count_skips_in_array(First, First + count_of_I, a) >{}
- );
- }
- template <class T>
- constexpr auto internal_tuple_with_same_alignment() noexcept {
- typedef typename std::remove_cv<T>::type type;
- static_assert(
- std::is_trivial<type>::value && std::is_standard_layout<type>::value,
- "====================> Boost.PFR: Type can not be reflected without Loophole or C++17, because it's not POD"
- );
- static_assert(!std::is_reference<type>::value, "====================> Boost.PFR: Not applyable");
- constexpr auto res = detail::as_flat_tuple_impl<type>(
- detail::make_index_sequence< decltype(detail::flat_array_of_type_ids<type>())::size() >()
- );
- return res;
- }
- template <class T>
- using internal_tuple_with_same_alignment_t = decltype( detail::internal_tuple_with_same_alignment<T>() );
- ///////////////////// Flattening
- struct ubiq_is_flat_refelectable {
- bool& is_flat_refelectable;
- template <class Type>
- constexpr operator Type() const noexcept {
- is_flat_refelectable = std::is_fundamental<std::remove_pointer_t<Type>>::value;
- return {};
- }
- };
- template <class T, std::size_t... I>
- constexpr bool is_flat_refelectable(std::index_sequence<I...>) noexcept {
- constexpr std::size_t fields = sizeof...(I);
- bool result[fields] = {static_cast<bool>(I)...};
- const T v{ ubiq_is_flat_refelectable{result[I]}... };
- (void)v;
- for (std::size_t i = 0; i < fields; ++i) {
- if (!result[i]) {
- return false;
- }
- }
- return true;
- }
- template<class T>
- constexpr bool is_flat_refelectable(std::index_sequence<>) noexcept {
- return true; ///< all empty structs always flat refelectable
- }
- template <class T>
- auto tie_as_flat_tuple(T& lvalue) noexcept {
- static_assert(
- !std::is_union<T>::value,
- "====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
- );
- using type = std::remove_cv_t<T>;
- using tuple_type = internal_tuple_with_same_alignment_t<type>;
- offset_based_getter<type, tuple_type> getter;
- return boost::pfr::detail::make_flat_tuple_of_references(lvalue, getter, size_t_<0>{}, size_t_<tuple_type::size_v>{});
- }
- template <class T>
- auto tie_as_tuple(T& val) noexcept {
- static_assert(
- !std::is_union<T>::value,
- "====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
- );
- static_assert(
- boost::pfr::detail::is_flat_refelectable<T>( detail::make_index_sequence<boost::pfr::detail::fields_count<T>()>{} ),
- "====================> Boost.PFR: Not possible in C++14 to represent that type without loosing information. Change type definition or enable C++17"
- );
- return boost::pfr::detail::tie_as_flat_tuple(val);
- }
- /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////// Structure that can be converted to copy of anything
- struct ubiq_constructor_constexpr_copy {
- std::size_t ignore;
- template <class Type>
- constexpr operator Type() const noexcept {
- static_assert(
- std::is_trivially_destructible<Type>::value,
- "====================> Boost.PFR: One of the fields in the type passed to `for_each_field` has non trivial destructor."
- );
- return {};
- }
- };
- /////////////////////
- template <class T, std::size_t... I>
- struct is_constexpr_aggregate_initializable {
- template<class T2, std::size_t... I2>
- static constexpr void* constexpr_aggregate_initializer() noexcept {
- T2 tmp{ ubiq_constructor_constexpr_copy{I2}... };
- (void)tmp;
- return nullptr;
- }
- template <void* = constexpr_aggregate_initializer<T, I...>() >
- static std::true_type test(long) noexcept;
- static std::false_type test(...) noexcept;
- static constexpr bool value = decltype(test(0)){};
- };
- template <class T, class F, std::size_t I0, std::size_t... I, class... Fields>
- void for_each_field_in_depth(T& t, F&& f, std::index_sequence<I0, I...>, identity<Fields>...);
- template <class T, class F, class... Fields>
- void for_each_field_in_depth(T& t, F&& f, std::index_sequence<>, identity<Fields>...);
- template <class T, class F, class IndexSeq, class... Fields>
- struct next_step {
- T& t;
- F& f;
- template <class Field>
- operator Field() const {
- boost::pfr::detail::for_each_field_in_depth(
- t,
- std::forward<F>(f),
- IndexSeq{},
- identity<Fields>{}...,
- identity<Field>{}
- );
- return {};
- }
- };
- template <class T, class F, std::size_t I0, std::size_t... I, class... Fields>
- void for_each_field_in_depth(T& t, F&& f, std::index_sequence<I0, I...>, identity<Fields>...) {
- (void)std::add_const_t<std::remove_reference_t<T>>{
- Fields{}...,
- next_step<T, F, std::index_sequence<I...>, Fields...>{t, f},
- ubiq_constructor_constexpr_copy{I}...
- };
- }
- template <class T, class F, class... Fields>
- void for_each_field_in_depth(T& lvalue, F&& f, std::index_sequence<>, identity<Fields>...) {
- using tuple_type = sequence_tuple::tuple<Fields...>;
- offset_based_getter<std::remove_cv_t<std::remove_reference_t<T>>, tuple_type> getter;
- std::forward<F>(f)(
- boost::pfr::detail::make_flat_tuple_of_references(lvalue, getter, size_t_<0>{}, size_t_<sizeof...(Fields)>{})
- );
- }
- template <class T, class F, std::size_t... I>
- void for_each_field_dispatcher_1(T& t, F&& f, std::index_sequence<I...>, std::true_type /*is_flat_refelectable*/) {
- std::forward<F>(f)(
- boost::pfr::detail::tie_as_flat_tuple(t)
- );
- }
- template <class T, class F, std::size_t... I>
- void for_each_field_dispatcher_1(T& t, F&& f, std::index_sequence<I...>, std::false_type /*is_flat_refelectable*/) {
- boost::pfr::detail::for_each_field_in_depth(
- t,
- std::forward<F>(f),
- std::index_sequence<I...>{}
- );
- }
- template <class T, class F, std::size_t... I>
- void for_each_field_dispatcher(T& t, F&& f, std::index_sequence<I...>) {
- static_assert(
- !std::is_union<T>::value,
- "====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
- );
- static_assert(is_constexpr_aggregate_initializable<T, I...>::value, "====================> Boost.PFR: T must be a constexpr initializable type");
- constexpr bool is_flat_refelectable_val = detail::is_flat_refelectable<T>( std::index_sequence<I...>{} );
- detail::for_each_field_dispatcher_1(
- t,
- std::forward<F>(f),
- std::index_sequence<I...>{},
- std::integral_constant<bool, is_flat_refelectable_val>{}
- );
- }
- /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- #ifdef __clang__
- # pragma clang diagnostic pop
- #endif
- }}} // namespace boost::pfr::detail
- #endif // BOOST_PFR_DETAIL_CORE14_CLASSIC_HPP
|