mirror of
https://github.com/boostorg/pfr.git
synced 2026-01-19 04:22:13 +00:00
Improve field count typical case performance (#120)
The tightest upper bound one can specify on the number of fields in a struct is `sizeof(type) * CHAR_BIT`. So this was previously used when performing a binary search for the field count. This upper bound is extremely loose when considering a typical large struct, which is more likely to contain a relatively small number of relatively large fields rather than the other way around. The binary search range being multiple orders of magnitude larger than necessary wouldn't have been a significant issue if each test was cheap, but they're not. Testing a field count of N costs O(N) memory and time. As a result, the initial few steps of the binary search may be prohibitively expensive. The primary optimization introduced by these changes is to use unbounded binary search, a.k.a. exponential search, instead of the typically loosely bounded binary search. This produces a tight upper bound (within 2x) on the field count to then perform the binary search with. As an upside of this change, the compiler-specific limit placed on the upper bound on the field count to stay within compiler limits could be removed.
This commit is contained in:
@@ -70,6 +70,10 @@ test-suite pfr_tests
|
||||
[ run ../../example/sample_printing.cpp : : : : auto_engine_sample_printing ]
|
||||
[ run ../../example/get.cpp : : : : auto_engine_get ]
|
||||
[ run ../../example/quick_examples.cpp : : : : auto_engine_quick ]
|
||||
|
||||
[ compile-fail fields_count_on_incomplete_type.cpp : <define>BOOST_PFR_RUN_TEST_ON=void : fields_count_on_incomplete_type_void ]
|
||||
[ compile-fail fields_count_on_incomplete_type.cpp : <define>BOOST_PFR_RUN_TEST_ON="void()" : fields_count_on_incomplete_type_function ]
|
||||
[ compile-fail fields_count_on_incomplete_type.cpp : <define>BOOST_PFR_RUN_TEST_ON="struct Foo" : fields_count_on_incomplete_type_struct ]
|
||||
;
|
||||
|
||||
local BLACKLIST_TESTS_FOR_LOOPHOLE =
|
||||
|
||||
15
test/core/compile-fail/constructible_0_or_more_args.cpp
Normal file
15
test/core/compile-fail/constructible_0_or_more_args.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2023-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)
|
||||
|
||||
#include <boost/pfr/tuple_size.hpp>
|
||||
|
||||
struct A {
|
||||
template <typename... Args>
|
||||
explicit A(Args&&...) {}
|
||||
};
|
||||
|
||||
int main() {
|
||||
(void)boost::pfr::tuple_size<A>::value; // Must be a compile time error
|
||||
}
|
||||
15
test/core/compile-fail/constructible_1_or_more_args.cpp
Normal file
15
test/core/compile-fail/constructible_1_or_more_args.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2023-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)
|
||||
|
||||
#include <boost/pfr/tuple_size.hpp>
|
||||
|
||||
struct A {
|
||||
template <typename Arg0, typename... Args>
|
||||
explicit A(Arg0&&, Args&&...) {}
|
||||
};
|
||||
|
||||
int main() {
|
||||
(void)boost::pfr::tuple_size<A>::value; // Must be a compile time error
|
||||
}
|
||||
10
test/core/fields_count_on_incomplete_type.cpp
Normal file
10
test/core/fields_count_on_incomplete_type.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) 2023-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)
|
||||
|
||||
#include <boost/pfr/detail/fields_count.hpp>
|
||||
|
||||
int main() {
|
||||
return static_cast<int>(boost::pfr::detail::fields_count<BOOST_PFR_RUN_TEST_ON>());
|
||||
}
|
||||
@@ -5,17 +5,82 @@
|
||||
|
||||
#include <boost/pfr/tuple_size.hpp>
|
||||
|
||||
struct bf {
|
||||
unsigned int i1: 1;
|
||||
unsigned int i2: 1;
|
||||
unsigned int i3: 1;
|
||||
unsigned int i4: 1;
|
||||
unsigned int i5: 1;
|
||||
unsigned int i6: 1;
|
||||
#include <cstdint>
|
||||
|
||||
struct bf7 {
|
||||
uint8_t b0 : 1;
|
||||
uint8_t b1 : 1;
|
||||
uint8_t b2 : 1;
|
||||
uint8_t b3 : 1;
|
||||
uint8_t b4 : 1;
|
||||
uint8_t b5 : 1;
|
||||
uint8_t b6 : 1;
|
||||
};
|
||||
static_assert(sizeof(bf7) == 1, "");
|
||||
|
||||
struct bf8 {
|
||||
uint8_t b0 : 1;
|
||||
uint8_t b1 : 1;
|
||||
uint8_t b2 : 1;
|
||||
uint8_t b3 : 1;
|
||||
uint8_t b4 : 1;
|
||||
uint8_t b5 : 1;
|
||||
uint8_t b6 : 1;
|
||||
uint8_t b7 : 1;
|
||||
};
|
||||
static_assert(sizeof(bf8) == 1, "");
|
||||
|
||||
struct bf16 {
|
||||
uint8_t b0 : 1;
|
||||
uint8_t b1 : 1;
|
||||
uint8_t b2 : 1;
|
||||
uint8_t b3 : 1;
|
||||
uint8_t b4 : 1;
|
||||
uint8_t b5 : 1;
|
||||
uint8_t b6 : 1;
|
||||
uint8_t b7 : 1;
|
||||
uint8_t b8 : 1;
|
||||
uint8_t b9 : 1;
|
||||
uint8_t b10 : 1;
|
||||
uint8_t b11 : 1;
|
||||
uint8_t b12 : 1;
|
||||
uint8_t b13 : 1;
|
||||
uint8_t b14 : 1;
|
||||
uint8_t b15 : 1;
|
||||
};
|
||||
static_assert(sizeof(bf16) == 2, "");
|
||||
|
||||
struct bf24 {
|
||||
uint8_t b0 : 1;
|
||||
uint8_t b1 : 1;
|
||||
uint8_t b2 : 1;
|
||||
uint8_t b3 : 1;
|
||||
uint8_t b4 : 1;
|
||||
uint8_t b5 : 1;
|
||||
uint8_t b6 : 1;
|
||||
uint8_t b7 : 1;
|
||||
uint8_t b8 : 1;
|
||||
uint8_t b9 : 1;
|
||||
uint8_t b10 : 1;
|
||||
uint8_t b11 : 1;
|
||||
uint8_t b12 : 1;
|
||||
uint8_t b13 : 1;
|
||||
uint8_t b14 : 1;
|
||||
uint8_t b15 : 1;
|
||||
uint8_t b16 : 1;
|
||||
uint8_t b17 : 1;
|
||||
uint8_t b18 : 1;
|
||||
uint8_t b19 : 1;
|
||||
uint8_t b20 : 1;
|
||||
uint8_t b21 : 1;
|
||||
uint8_t b22 : 1;
|
||||
uint8_t b23 : 1;
|
||||
};
|
||||
static_assert(sizeof(bf24) == 3, "");
|
||||
|
||||
int main() {
|
||||
static_assert(boost::pfr::tuple_size<bf>::value == 6, "");
|
||||
static_assert(boost::pfr::tuple_size_v<bf7> == 7, "");
|
||||
static_assert(boost::pfr::tuple_size_v<bf8> == 8, "");
|
||||
static_assert(boost::pfr::tuple_size_v<bf16> == 16, "");
|
||||
static_assert(boost::pfr::tuple_size_v<bf24> == 24, "");
|
||||
}
|
||||
|
||||
|
||||
|
||||
63
test/core/run/huge_count.cpp
Normal file
63
test/core/run/huge_count.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
// Copyright (c) 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)
|
||||
|
||||
#include <boost/pfr/tuple_size.hpp>
|
||||
|
||||
#include <climits>
|
||||
#include <cstdint>
|
||||
|
||||
#if defined(__clang__)
|
||||
# if SIZE_MAX > (1ULL << 32) - 1
|
||||
# define ARRAY_MAX (SIZE_MAX >> 3)
|
||||
# else
|
||||
# define ARRAY_MAX SIZE_MAX
|
||||
# endif
|
||||
# define OBJECT_MAX SIZE_MAX
|
||||
#elif defined(__GNUC__)
|
||||
# define ARRAY_MAX INT_MAX
|
||||
# define OBJECT_MAX (SIZE_MAX >> 1)
|
||||
#elif defined(_MSC_VER)
|
||||
# define ARRAY_MAX INT_MAX
|
||||
# define OBJECT_MAX UINT_MAX
|
||||
#else // Let's play it safe
|
||||
# define ARRAY_MAX INT_MAX
|
||||
# define OBJECT_MAX INT_MAX
|
||||
#endif
|
||||
|
||||
#pragma pack(1)
|
||||
struct A {
|
||||
char x[ARRAY_MAX <= (OBJECT_MAX >> 3) ? ARRAY_MAX : OBJECT_MAX >> 3];
|
||||
};
|
||||
|
||||
struct B {
|
||||
A a;
|
||||
A b;
|
||||
A c;
|
||||
A d;
|
||||
A e;
|
||||
A f;
|
||||
A g;
|
||||
A h;
|
||||
};
|
||||
|
||||
struct C {
|
||||
A& a;
|
||||
A b;
|
||||
A c;
|
||||
A d;
|
||||
A e;
|
||||
A f;
|
||||
A g;
|
||||
A h;
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
int main() {
|
||||
#ifndef _MSC_VER
|
||||
static_assert(boost::pfr::tuple_size_v<char[ARRAY_MAX]> == ARRAY_MAX, "");
|
||||
#endif
|
||||
static_assert(boost::pfr::tuple_size_v<B> == 8, "");
|
||||
static_assert(boost::pfr::tuple_size_v<C> == 8, "");
|
||||
}
|
||||
1019
test/core/run/many_fields_count.cpp
Normal file
1019
test/core/run/many_fields_count.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -45,7 +45,7 @@ int main() {
|
||||
"Precise reflection with template constructors sanity check fails"
|
||||
);
|
||||
|
||||
boost::pfr::detail::enable_if_constructible_helper_t<aggregate_unconstrained, 2> foo;
|
||||
boost::pfr::detail::enable_if_initializable_helper_t<aggregate_unconstrained, 2> foo;
|
||||
(void)foo;
|
||||
|
||||
static_assert(
|
||||
|
||||
@@ -45,7 +45,7 @@ int main() {
|
||||
"Precise reflection with template constructors sanity check fails"
|
||||
);
|
||||
|
||||
boost::pfr::detail::enable_if_constructible_helper_t<aggregate_unconstrained, 2> foo;
|
||||
boost::pfr::detail::enable_if_initializable_helper_t<aggregate_unconstrained, 2> foo;
|
||||
(void)foo;
|
||||
|
||||
static_assert(
|
||||
|
||||
Reference in New Issue
Block a user