Skip to content

Commit aad922e

Browse files
committed
Speedup PFR fields detection
1 parent ff415a2 commit aad922e

File tree

2 files changed

+18
-19
lines changed

2 files changed

+18
-19
lines changed

Diff for: include/boost/pfr/detail/fields_count.hpp

+17-19
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,7 @@ import std;
3232
namespace boost { namespace pfr { namespace detail {
3333

3434
///////////////////// min without including <algorithm>
35-
template <class T>
36-
constexpr const T& (min)(const T& a, const T& b) {
35+
constexpr std::size_t min_of_size_t(std::size_t a, std::size_t b) noexcept {
3736
return b < a ? b : a;
3837
}
3938

@@ -275,17 +274,10 @@ constexpr auto fields_count_upper_bound(long, int) noexcept
275274
-> detail::enable_if_initializable_helper_t<T, N>
276275
{
277276
constexpr std::size_t next_optimal = Begin + (N - Begin) * 2;
278-
constexpr std::size_t next = (detail::min)(next_optimal, detail::fields_count_compiler_limitation_next(N));
277+
constexpr std::size_t next = detail::min_of_size_t(next_optimal, detail::fields_count_compiler_limitation_next(N));
279278
return detail::fields_count_upper_bound<T, Begin, next>(1L, 1L);
280279
}
281280

282-
template <class T, std::size_t Begin = 0>
283-
constexpr std::size_t fields_count_binary_search_unbounded() noexcept {
284-
constexpr std::size_t last = detail::fields_count_upper_bound<T, Begin, Begin + 1>(1L, 1L);
285-
constexpr std::size_t middle = (Begin + last + 1) / 2;
286-
return detail::fields_count_binary_search<T, Begin, middle>(detail::is_one_element_range<Begin, middle>{}, 1L);
287-
}
288-
289281
///////////////////// Fields count lower bound linear search.
290282
// Template instantiation: depth is O(log(result)), count is O(result), cost is O(result^2).
291283
template <class T, std::size_t Begin, std::size_t Last, class RangeSize, std::size_t Result>
@@ -315,13 +307,13 @@ constexpr std::size_t fields_count_lower_bound(detail::multi_element_range, size
315307
);
316308
}
317309

318-
template <class T, std::size_t Begin = 1, std::size_t Result>
310+
template <class T, std::size_t Begin, std::size_t Result>
319311
constexpr std::size_t fields_count_lower_bound_unbounded(int, size_t_<Result>) noexcept {
320312
return Result;
321313
}
322314

323-
template <class T, std::size_t Begin = 1>
324-
constexpr auto fields_count_lower_bound_unbounded(long, size_t_<0> = {}) noexcept
315+
template <class T, std::size_t Begin, std::size_t Result>
316+
constexpr auto fields_count_lower_bound_unbounded(long, size_t_<Result>) noexcept
325317
-> std::enable_if_t<(Begin >= detail::fields_count_upper_bound_loose<T>()), std::size_t>
326318
{
327319
static_assert(
@@ -330,9 +322,9 @@ constexpr auto fields_count_lower_bound_unbounded(long, size_t_<0> = {}) noexcep
330322
return detail::fields_count_upper_bound_loose<T>();
331323
}
332324

333-
template <class T, std::size_t Begin = 1>
334-
constexpr std::size_t fields_count_lower_bound_unbounded(int, size_t_<0> = {}) noexcept {
335-
constexpr std::size_t last = (detail::min)(Begin * 2, detail::fields_count_upper_bound_loose<T>()) - 1;
325+
template <class T, std::size_t Begin>
326+
constexpr std::size_t fields_count_lower_bound_unbounded(int, size_t_<0>) noexcept {
327+
constexpr std::size_t last = detail::min_of_size_t(Begin * 2, detail::fields_count_upper_bound_loose<T>()) - 1;
336328
constexpr std::size_t result_maybe = detail::fields_count_lower_bound<T, Begin, last>(
337329
detail::is_one_element_range<Begin, last>{}
338330
);
@@ -351,15 +343,21 @@ template <class T>
351343
constexpr auto fields_count_dispatch(long, int) noexcept
352344
-> decltype(sizeof(T{}))
353345
{
354-
return detail::fields_count_binary_search_unbounded<T>();
346+
constexpr std::size_t typical_fields_count = 4;
347+
constexpr std::size_t last = detail::fields_count_upper_bound<T, typical_fields_count, typical_fields_count * 2>(1L, 1L);
348+
constexpr std::size_t middle = (last + 1) / 2;
349+
return detail::fields_count_binary_search<T, 0, middle>(detail::is_one_element_range<0, middle>{}, 1L);
355350
}
356351

357352
template <class T>
358353
constexpr std::size_t fields_count_dispatch(int, int) noexcept {
359354
// T is not default aggregate initializable. This means that at least one of the members is not default-constructible.
360355
// Use linear search to find the smallest valid initializer, after which we unbounded binary search for the largest.
361-
constexpr std::size_t begin = detail::fields_count_lower_bound_unbounded<T>(1L);
362-
return detail::fields_count_binary_search_unbounded<T, begin>();
356+
constexpr std::size_t begin = detail::fields_count_lower_bound_unbounded<T, 1>(1L, size_t_<0>{});
357+
358+
constexpr std::size_t last = detail::fields_count_upper_bound<T, begin, begin + 1>(1L, 1L);
359+
constexpr std::size_t middle = (begin + last + 1) / 2;
360+
return detail::fields_count_binary_search<T, begin, middle>(detail::is_one_element_range<begin, middle>{}, 1L);
363361
}
364362

365363
///////////////////// Returns fields count

Diff for: test/core/compile-fail/constructible_1_or_more_args.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <boost/pfr/tuple_size.hpp>
77

8+
89
struct A {
910
template <typename Arg0, typename... Args>
1011
explicit A(Arg0&&, Args&&...) {}

0 commit comments

Comments
 (0)