File indexing completed on 2025-01-18 09:43:37
0001
0002
0003
0004
0005
0006 #ifndef BOOST_PFR_DETAIL_FIELDS_COUNT_HPP
0007 #define BOOST_PFR_DETAIL_FIELDS_COUNT_HPP
0008 #pragma once
0009
0010 #include <boost/pfr/detail/config.hpp>
0011 #include <boost/pfr/detail/make_integer_sequence.hpp>
0012 #include <boost/pfr/detail/size_t_.hpp>
0013 #include <boost/pfr/detail/unsafe_declval.hpp>
0014
0015 #include <climits> // CHAR_BIT
0016 #include <type_traits>
0017 #include <utility> // metaprogramming stuff
0018
0019 #ifdef __clang__
0020 # pragma clang diagnostic push
0021 # pragma clang diagnostic ignored "-Wmissing-braces"
0022 # pragma clang diagnostic ignored "-Wundefined-inline"
0023 # pragma clang diagnostic ignored "-Wundefined-internal"
0024 # pragma clang diagnostic ignored "-Wmissing-field-initializers"
0025 #endif
0026
0027 namespace boost { namespace pfr { namespace detail {
0028
0029
0030 struct ubiq_lref_constructor {
0031 std::size_t ignore;
0032 template <class Type> constexpr operator Type&() const && noexcept {
0033 return detail::unsafe_declval<Type&>();
0034 }
0035
0036 template <class Type> constexpr operator Type&() const & noexcept {
0037 return detail::unsafe_declval<Type&>();
0038 }
0039 };
0040
0041
0042 struct ubiq_rref_constructor {
0043 std::size_t ignore;
0044 template <class Type> operator Type() const && noexcept {
0045 return detail::unsafe_declval<Type>();
0046 }
0047 };
0048
0049
0050 #ifndef __cpp_lib_is_aggregate
0051
0052
0053
0054 template <class T, bool IsCopyConstructible>
0055 struct ubiq_constructor_except {
0056 std::size_t ignore;
0057 template <class Type> constexpr operator std::enable_if_t<!std::is_same<T, Type>::value, Type&> () const noexcept;
0058 };
0059
0060 template <class T>
0061 struct ubiq_constructor_except<T, false> {
0062 std::size_t ignore;
0063 template <class Type> constexpr operator std::enable_if_t<!std::is_same<T, Type>::value, Type&&> () const noexcept;
0064 };
0065
0066
0067
0068 template <std::size_t N, class T> struct is_single_field_and_aggregate_initializable: std::false_type {};
0069 template <class T> struct is_single_field_and_aggregate_initializable<1, T>: std::integral_constant<
0070 bool, !std::is_constructible<T, ubiq_constructor_except<T, std::is_copy_constructible<T>::value>>::value
0071 > {};
0072
0073
0074
0075
0076
0077 template <class T, std::size_t N>
0078 struct is_aggregate_initializable_n {
0079 template <std::size_t ...I>
0080 static constexpr bool is_not_constructible_n(std::index_sequence<I...>) noexcept {
0081 return (!std::is_constructible<T, decltype(ubiq_lref_constructor{I})...>::value && !std::is_constructible<T, decltype(ubiq_rref_constructor{I})...>::value)
0082 || is_single_field_and_aggregate_initializable<N, T>::value
0083 ;
0084 }
0085
0086 static constexpr bool value =
0087 std::is_empty<T>::value
0088 || std::is_array<T>::value
0089 || std::is_fundamental<T>::value
0090 || is_not_constructible_n(detail::make_index_sequence<N>{})
0091 ;
0092 };
0093
0094 #endif
0095
0096
0097 template <class Derived, class U>
0098 constexpr bool static_assert_non_inherited() noexcept {
0099 static_assert(
0100 !std::is_base_of<U, Derived>::value,
0101 "====================> Boost.PFR: Boost.PFR: Inherited types are not supported."
0102 );
0103 return true;
0104 }
0105
0106 template <class Derived>
0107 struct ubiq_lref_base_asserting {
0108 template <class Type> constexpr operator Type&() const &&
0109 noexcept(detail::static_assert_non_inherited<Derived, Type>())
0110 {
0111 return detail::unsafe_declval<Type&>();
0112 }
0113
0114 template <class Type> constexpr operator Type&() const &
0115 noexcept(detail::static_assert_non_inherited<Derived, Type>())
0116 {
0117 return detail::unsafe_declval<Type&>();
0118 }
0119 };
0120
0121 template <class Derived>
0122 struct ubiq_rref_base_asserting {
0123 template <class Type> operator Type() const &&
0124 noexcept(detail::static_assert_non_inherited<Derived, Type>())
0125 {
0126 return detail::unsafe_declval<Type>();
0127 }
0128 };
0129
0130 template <class T, std::size_t I0, std::size_t... I, class = typename std::enable_if<std::is_copy_constructible<T>::value>::type>
0131 constexpr auto assert_first_not_base(std::index_sequence<I0, I...>) noexcept
0132 -> typename std::add_pointer<decltype(T{ ubiq_lref_base_asserting<T>{}, ubiq_lref_constructor{I}... })>::type
0133 {
0134 return nullptr;
0135 }
0136
0137 template <class T, std::size_t I0, std::size_t... I, class = typename std::enable_if<!std::is_copy_constructible<T>::value>::type>
0138 constexpr auto assert_first_not_base(std::index_sequence<I0, I...>) noexcept
0139 -> typename std::add_pointer<decltype(T{ ubiq_rref_base_asserting<T>{}, ubiq_rref_constructor{I}... })>::type
0140 {
0141 return nullptr;
0142 }
0143
0144 template <class T>
0145 constexpr void* assert_first_not_base(std::index_sequence<>) noexcept
0146 {
0147 return nullptr;
0148 }
0149
0150
0151 template <class T, std::size_t... I, class = typename std::enable_if<std::is_copy_constructible<T>::value>::type>
0152 constexpr auto enable_if_constructible_helper(std::index_sequence<I...>) noexcept
0153 -> typename std::add_pointer<decltype(T{ ubiq_lref_constructor{I}... })>::type;
0154
0155 template <class T, std::size_t... I, class = typename std::enable_if<!std::is_copy_constructible<T>::value>::type>
0156 constexpr auto enable_if_constructible_helper(std::index_sequence<I...>) noexcept
0157 -> typename std::add_pointer<decltype(T{ ubiq_rref_constructor{I}... })>::type;
0158
0159 template <class T, std::size_t N, class = decltype( enable_if_constructible_helper<T>(detail::make_index_sequence<N>()) ) >
0160 using enable_if_constructible_helper_t = std::size_t;
0161
0162
0163 template <std::size_t Begin, std::size_t Last>
0164 using is_one_element_range = std::integral_constant<bool, Begin == Last>;
0165
0166 using multi_element_range = std::false_type;
0167 using one_element_range = std::true_type;
0168
0169
0170 template <class T, std::size_t Begin, std::size_t Middle>
0171 constexpr std::size_t detect_fields_count(detail::one_element_range, long) noexcept {
0172 static_assert(
0173 Begin == Middle,
0174 "====================> Boost.PFR: Internal logic error."
0175 );
0176 return Begin;
0177 }
0178
0179 template <class T, std::size_t Begin, std::size_t Middle>
0180 constexpr std::size_t detect_fields_count(detail::multi_element_range, int) noexcept;
0181
0182 template <class T, std::size_t Begin, std::size_t Middle>
0183 constexpr auto detect_fields_count(detail::multi_element_range, long) noexcept
0184 -> detail::enable_if_constructible_helper_t<T, Middle>
0185 {
0186 constexpr std::size_t next_v = Middle + (Middle - Begin + 1) / 2;
0187 return detail::detect_fields_count<T, Middle, next_v>(detail::is_one_element_range<Middle, next_v>{}, 1L);
0188 }
0189
0190 template <class T, std::size_t Begin, std::size_t Middle>
0191 constexpr std::size_t detect_fields_count(detail::multi_element_range, int) noexcept {
0192 constexpr std::size_t next_v = Begin + (Middle - Begin) / 2;
0193 return detail::detect_fields_count<T, Begin, next_v>(detail::is_one_element_range<Begin, next_v>{}, 1L);
0194 }
0195
0196
0197 template <class T, std::size_t N>
0198 constexpr auto detect_fields_count_greedy_remember(long) noexcept
0199 -> detail::enable_if_constructible_helper_t<T, N>
0200 {
0201 return N;
0202 }
0203
0204 template <class T, std::size_t N>
0205 constexpr std::size_t detect_fields_count_greedy_remember(int) noexcept {
0206 return 0;
0207 }
0208
0209 template <class T, std::size_t Begin, std::size_t Last>
0210 constexpr std::size_t detect_fields_count_greedy(detail::one_element_range) noexcept {
0211 static_assert(
0212 Begin == Last,
0213 "====================> Boost.PFR: Internal logic error."
0214 );
0215 return detail::detect_fields_count_greedy_remember<T, Begin>(1L);
0216 }
0217
0218 template <class T, std::size_t Begin, std::size_t Last>
0219 constexpr std::size_t detect_fields_count_greedy(detail::multi_element_range) noexcept {
0220 constexpr std::size_t middle = Begin + (Last - Begin) / 2;
0221 constexpr std::size_t fields_count_big_range = detail::detect_fields_count_greedy<T, middle + 1, Last>(
0222 detail::is_one_element_range<middle + 1, Last>{}
0223 );
0224
0225 constexpr std::size_t small_range_begin = (fields_count_big_range ? 0 : Begin);
0226 constexpr std::size_t small_range_last = (fields_count_big_range ? 0 : middle);
0227 constexpr std::size_t fields_count_small_range = detail::detect_fields_count_greedy<T, small_range_begin, small_range_last>(
0228 detail::is_one_element_range<small_range_begin, small_range_last>{}
0229 );
0230 return fields_count_big_range ? fields_count_big_range : fields_count_small_range;
0231 }
0232
0233
0234 template <class T, std::size_t N>
0235 constexpr auto detect_fields_count_dispatch(size_t_<N>, long, long) noexcept
0236 -> typename std::enable_if<std::is_array<T>::value, std::size_t>::type
0237 {
0238 return sizeof(T) / sizeof(typename std::remove_all_extents<T>::type);
0239 }
0240
0241 template <class T, std::size_t N>
0242 constexpr auto detect_fields_count_dispatch(size_t_<N>, long, int) noexcept
0243 -> decltype(sizeof(T{}))
0244 {
0245 constexpr std::size_t middle = N / 2 + 1;
0246 return detail::detect_fields_count<T, 0, middle>(detail::multi_element_range{}, 1L);
0247 }
0248
0249 template <class T, std::size_t N>
0250 constexpr std::size_t detect_fields_count_dispatch(size_t_<N>, int, int) noexcept {
0251
0252
0253
0254 return detail::detect_fields_count_greedy<T, 0, N>(detail::multi_element_range{});
0255 }
0256
0257
0258 template <class T>
0259 constexpr std::size_t fields_count() noexcept {
0260 using type = std::remove_cv_t<T>;
0261
0262 static_assert(
0263 !std::is_reference<type>::value,
0264 "====================> Boost.PFR: Attempt to get fields count on a reference. This is not allowed because that could hide an issue and different library users expect different behavior in that case."
0265 );
0266
0267 #if !BOOST_PFR_HAS_GUARANTEED_COPY_ELISION
0268 static_assert(
0269 std::is_copy_constructible<std::remove_all_extents_t<type>>::value || (
0270 std::is_move_constructible<std::remove_all_extents_t<type>>::value
0271 && std::is_move_assignable<std::remove_all_extents_t<type>>::value
0272 ),
0273 "====================> Boost.PFR: Type and each field in the type must be copy constructible (or move constructible and move assignable)."
0274 );
0275 #endif
0276
0277 static_assert(
0278 !std::is_polymorphic<type>::value,
0279 "====================> Boost.PFR: Type must have no virtual function, because otherwise it is not aggregate initializable."
0280 );
0281
0282 #ifdef __cpp_lib_is_aggregate
0283 static_assert(
0284 std::is_aggregate<type>::value
0285 || std::is_scalar<type>::value,
0286 "====================> Boost.PFR: Type must be aggregate initializable."
0287 );
0288 #endif
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298 #if defined(_MSC_VER) && (_MSC_VER <= 1920)
0299
0300 constexpr std::size_t max_fields_count = (sizeof(type) * CHAR_BIT >= 1024 ? 1024 : sizeof(type) * CHAR_BIT);
0301 #else
0302 constexpr std::size_t max_fields_count = (sizeof(type) * CHAR_BIT);
0303 #endif
0304
0305 constexpr std::size_t result = detail::detect_fields_count_dispatch<type>(size_t_<max_fields_count>{}, 1L, 1L);
0306
0307 detail::assert_first_not_base<type>(detail::make_index_sequence<result>{});
0308
0309 #ifndef __cpp_lib_is_aggregate
0310 static_assert(
0311 is_aggregate_initializable_n<type, result>::value,
0312 "====================> Boost.PFR: Types with user specified constructors (non-aggregate initializable types) are not supported."
0313 );
0314 #endif
0315
0316 static_assert(
0317 result != 0 || std::is_empty<type>::value || std::is_fundamental<type>::value || std::is_reference<type>::value,
0318 "====================> Boost.PFR: If there's no other failed static asserts then something went wrong. Please report this issue to the github along with the structure you're reflecting."
0319 );
0320
0321 return result;
0322 }
0323
0324 }}}
0325
0326 #ifdef __clang__
0327 # pragma clang diagnostic pop
0328 #endif
0329
0330 #endif