Skip to content

Commit d68b505

Browse files
authored
Improve compilation performance and cleanup (#1512)
* Faster compile time contains * Remove old invalid test code * support for meta_keys objects * Faster compilation of glz::detail::schematic * Use normal `for` loop * Remove now unused tuple_ptr code * Use std::array rather than std::vector * Revert "Use std::array rather than std::vector" This reverts commit 43b0aec. * reserve memory * Note on using vector rather than array * Removing more old map handling code * formatting * Remove make_map usage * More removal of make_map * Removing make_map for flags_t
1 parent 7a3e1b0 commit d68b505

File tree

10 files changed

+205
-200
lines changed

10 files changed

+205
-200
lines changed

include/glaze/beve/write.hpp

+12-8
Original file line numberDiff line numberDiff line change
@@ -874,14 +874,18 @@ namespace glz
874874

875875
static constexpr auto key = get<0>(group);
876876
static constexpr auto sub_partial = get<1>(group);
877-
static constexpr auto frozen_map = detail::make_map<T>();
878-
static constexpr auto member_it = frozen_map.find(key);
879-
static_assert(member_it != frozen_map.end(), "Invalid key passed to partial write");
880-
static constexpr auto index = member_it->second.index();
881-
static constexpr decltype(auto) element = get<index>(member_it->second);
882-
883-
detail::write<BEVE>::no_header<Opts>(key, ctx, b, ix);
884-
write_partial<BEVE>::op<sub_partial, Opts>(glz::get_member(value, element), ctx, b, ix);
877+
static constexpr auto index = key_index<T>(key);
878+
static_assert(index < reflect<T>::size, "Invalid key passed to partial write");
879+
880+
if constexpr (glaze_object_t<T>) {
881+
static constexpr auto member = get<index>(reflect<T>::values);
882+
detail::write<BEVE>::no_header<Opts>(key, ctx, b, ix);
883+
write_partial<BEVE>::op<sub_partial, Opts>(get_member(value, member), ctx, b, ix);
884+
}
885+
else {
886+
detail::write<BEVE>::no_header<Opts>(key, ctx, b, ix);
887+
write_partial<BEVE>::op<sub_partial, Opts>(get_member(value, get<index>(to_tuple(value))), ctx, b, ix);
888+
}
885889
});
886890
}
887891
else if constexpr (writable_map_t<T>) {

include/glaze/core/common.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ namespace glz
372372
concept glaze_array_t = glaze_t<T> && is_specialization_v<meta_wrapper_t<T>, Array>;
373373

374374
template <class T>
375-
concept glaze_object_t = glaze_t<T> && is_specialization_v<meta_wrapper_t<T>, Object>;
375+
concept glaze_object_t = glaze_t<T> && (is_specialization_v<meta_wrapper_t<T>, Object> || (not std::is_enum_v<std::decay_t<T>> && meta_keys<T>));
376376

377377
template <class T>
378378
concept glaze_enum_t = glaze_t<T> && is_specialization_v<meta_wrapper_t<T>, Enum>;
@@ -387,7 +387,7 @@ namespace glz
387387
template <class T>
388388
concept reflectable = std::is_aggregate_v<std::remove_cvref_t<T>> && std::is_class_v<std::remove_cvref_t<T>> &&
389389
!(is_no_reflect<T> || glaze_value_t<T> || glaze_object_t<T> || glaze_array_t<T> ||
390-
glaze_flags_t<T> || range<T> || pair_t<T> || null_t<T>);
390+
glaze_flags_t<T> || range<T> || pair_t<T> || null_t<T> || meta_keys<T>);
391391

392392
template <class T>
393393
concept is_memory_object = is_memory_type<T> && (glaze_object_t<memory_type<T>> || reflectable<memory_type<T>>);

include/glaze/core/meta.hpp

+8-1
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,14 @@ namespace glz
140140
}();
141141

142142
template <class T>
143-
inline constexpr auto meta_v = meta_wrapper_v<decay_keep_volatile_t<T>>.value;
143+
inline constexpr auto meta_v = []() -> decltype(auto) {
144+
if constexpr (detail::meta_keys<T>) {
145+
return meta_wrapper_v<decay_keep_volatile_t<T>>;
146+
}
147+
else {
148+
return meta_wrapper_v<decay_keep_volatile_t<T>>.value;
149+
}
150+
}();
144151

145152
template <class T>
146153
using meta_t = decay_keep_volatile_t<decltype(meta_v<T>)>;

include/glaze/core/reflect.hpp

+30-89
Original file line numberDiff line numberDiff line change
@@ -13,62 +13,6 @@
1313
#pragma warning(disable : 4100 4189)
1414
#endif
1515

16-
namespace glz::detail
17-
{
18-
// We create const and not-const versions for when our reflected struct is const or non-const qualified
19-
template <class Tuple>
20-
struct tuple_ptr;
21-
22-
template <class... Ts>
23-
struct tuple_ptr<tuplet::tuple<Ts...>>
24-
{
25-
using type = tuplet::tuple<std::add_pointer_t<std::remove_reference_t<Ts>>...>;
26-
};
27-
28-
template <class Tuple>
29-
struct tuple_ptr_const;
30-
31-
template <class... Ts>
32-
struct tuple_ptr_const<tuplet::tuple<Ts...>>
33-
{
34-
using type = tuplet::tuple<std::add_pointer_t<std::add_const_t<std::remove_reference_t<Ts>>>...>;
35-
};
36-
37-
// This is needed to hack a fix for MSVC evaluating wrong `if constexpr` branches
38-
template <class T>
39-
requires(!reflectable<T>)
40-
constexpr auto make_tuple_from_struct() noexcept
41-
{
42-
return glz::tuplet::tuple{};
43-
}
44-
45-
// This needs to produce const qualified pointers so that we can write out const structs
46-
template <reflectable T>
47-
constexpr auto make_tuple_from_struct() noexcept
48-
{
49-
using V = decay_keep_volatile_t<decltype(to_tuple(std::declval<T>()))>;
50-
return typename tuple_ptr<V>::type{};
51-
}
52-
53-
template <reflectable T>
54-
constexpr auto make_const_tuple_from_struct() noexcept
55-
{
56-
using V = decay_keep_volatile_t<decltype(to_tuple(std::declval<T>()))>;
57-
return typename tuple_ptr_const<V>::type{};
58-
}
59-
60-
template <reflectable T, class TuplePtrs>
61-
requires(!std::is_const_v<TuplePtrs>)
62-
constexpr void populate_tuple_ptr(T&& value, TuplePtrs& tuple_of_ptrs) noexcept
63-
{
64-
// we have to populate the pointers in the reflection tuple from the structured binding
65-
auto t = to_tuple(std::forward<T>(value));
66-
[&]<size_t... I>(std::index_sequence<I...>) {
67-
((get<I>(tuple_of_ptrs) = &get<I>(t)), ...);
68-
}(std::make_index_sequence<count_members<T>>{});
69-
}
70-
}
71-
7216
namespace glz
7317
{
7418
// Get indices of elements satisfying a predicate
@@ -246,8 +190,6 @@ namespace glz
246190
using V = std::remove_cvref_t<T>;
247191
using tuple = decay_keep_volatile_t<decltype(to_tuple(std::declval<T>()))>;
248192

249-
// static constexpr auto values = typename detail::tuple_ptr<tuple>::type{};
250-
251193
static constexpr auto keys = member_names<V>;
252194
static constexpr auto size = keys.size();
253195

@@ -528,15 +470,6 @@ namespace glz::detail
528470
constexpr auto indices = std::make_index_sequence<reflect<T>::size>{};
529471
return make_map_impl<decay_keep_volatile_t<T>, use_hash_comparison>(indices);
530472
}
531-
532-
template <class T>
533-
constexpr auto make_key_int_map()
534-
{
535-
constexpr auto N = reflect<T>::size;
536-
return [&]<size_t... I>(std::index_sequence<I...>) {
537-
return normal_map<sv, size_t, reflect<T>::size>(pair<sv, size_t>{reflect<T>::keys[I], I}...);
538-
}(std::make_index_sequence<N>{});
539-
}
540473
}
541474

542475
namespace glz
@@ -705,18 +638,6 @@ namespace glz
705638
constexpr auto indices = std::make_index_sequence<count_members<T>>{};
706639
return make_reflection_map_impl<decay_keep_volatile_t<T>, use_hash_comparison>(indices);
707640
}
708-
709-
template <reflectable T>
710-
GLZ_ALWAYS_INLINE constexpr void populate_map(T&& value, auto& cmap) noexcept
711-
{
712-
// we have to populate the pointers in the reflection map from the structured binding
713-
auto t = to_tuple(std::forward<T>(value));
714-
[&]<size_t... I>(std::index_sequence<I...>) {
715-
((get<std::add_pointer_t<decay_keep_volatile_t<decltype(get<I>(t))>>>(get<I>(cmap.items).second) =
716-
&get<I>(t)),
717-
...);
718-
}(std::make_index_sequence<count_members<T>>{});
719-
}
720641
}
721642
}
722643

@@ -785,7 +706,12 @@ namespace glz::detail
785706
using V = decay_keep_volatile_t<std::variant_alternative_t<I, T>>;
786707
if constexpr (glaze_object_t<V> || reflectable<V> || is_memory_object<V>) {
787708
using X = std::conditional_t<is_memory_object<V>, memory_type<V>, V>;
788-
for_each<reflect<X>::size>([&](auto J) { deduction_map.find(reflect<X>::keys[J])->second[I] = true; });
709+
constexpr auto Size = reflect<X>::size;
710+
if constexpr (Size > 0) {
711+
for (size_t J = 0; J < Size; ++J) {
712+
deduction_map.find(reflect<X>::keys[J])->second[I] = true;
713+
}
714+
}
789715
}
790716
});
791717

@@ -795,6 +721,18 @@ namespace glz::detail
795721

796722
namespace glz::detail
797723
{
724+
template <class T>
725+
consteval size_t key_index(const std::string_view key)
726+
{
727+
const auto n = reflect<T>::keys.size();
728+
for (size_t i = 0; i < n; ++i) {
729+
if (key == reflect<T>::keys[i]) {
730+
return i;
731+
}
732+
}
733+
return n;
734+
}
735+
798736
GLZ_ALWAYS_INLINE constexpr uint64_t bitmix(uint64_t h, const uint64_t seed) noexcept
799737
{
800738
h *= seed;
@@ -851,7 +789,10 @@ namespace glz::detail
851789
return {};
852790
}
853791

792+
// This could be a std::array, but each length N for std::array causes unique template instaniations
793+
// This propagates to std::ranges::sort, so using std::vector means less template instaniations
854794
std::vector<std::string_view> strings{};
795+
strings.reserve(N);
855796
for (size_t i = 0; i < N; ++i) {
856797
strings.emplace_back(input_strings[i]);
857798
}
@@ -1262,7 +1203,7 @@ namespace glz::detail
12621203
break;
12631204
}
12641205
const auto bucket = hash % bsize;
1265-
if (contains(std::span{bucket_index.data(), index}, bucket)) {
1206+
if (contains(bucket_index.data(), index, bucket)) {
12661207
break;
12671208
}
12681209
bucket_index[index] = bucket;
@@ -1272,7 +1213,7 @@ namespace glz::detail
12721213
if (index == N) {
12731214
// make sure the seed does not collide with any hashes
12741215
const auto bucket = seed % bsize;
1275-
if (not contains(std::span{bucket_index.data(), N}, bucket)) {
1216+
if (not contains(bucket_index.data(), N, bucket)) {
12761217
return; // found working seed
12771218
}
12781219
}
@@ -1421,7 +1362,7 @@ namespace glz::detail
14211362
break;
14221363
}
14231364
const auto bucket = hash % bsize;
1424-
if (contains(std::span{bucket_index.data(), index}, bucket)) {
1365+
if (contains(bucket_index.data(), index, bucket)) {
14251366
break;
14261367
}
14271368
bucket_index[index] = bucket;
@@ -1431,7 +1372,7 @@ namespace glz::detail
14311372
if (index == N) {
14321373
// make sure the seed does not collide with any hashes
14331374
const auto bucket = seed % bsize;
1434-
if (not contains(std::span{bucket_index.data(), N}, bucket)) {
1375+
if (not contains(bucket_index.data(), N, bucket)) {
14351376
return; // found working seed
14361377
}
14371378
}
@@ -1466,7 +1407,7 @@ namespace glz::detail
14661407
break;
14671408
}
14681409
const auto bucket = hash % bsize;
1469-
if (contains(std::span{bucket_index.data(), index}, bucket)) {
1410+
if (contains(bucket_index.data(), index, bucket)) {
14701411
break;
14711412
}
14721413
bucket_index[index] = bucket;
@@ -1476,7 +1417,7 @@ namespace glz::detail
14761417
if (index == N) {
14771418
// make sure the seed does not collide with any hashes
14781419
const auto bucket = seed % bsize;
1479-
if (not contains(std::span{bucket_index.data(), N}, bucket)) {
1420+
if (not contains(bucket_index.data(), N, bucket)) {
14801421
return; // found working seed
14811422
}
14821423
}
@@ -1508,7 +1449,7 @@ namespace glz::detail
15081449
break;
15091450
}
15101451
const auto bucket = hash % bsize;
1511-
if (contains(std::span{bucket_index.data(), index}, bucket)) {
1452+
if (contains(bucket_index.data(), index, bucket)) {
15121453
break;
15131454
}
15141455
bucket_index[index] = bucket;
@@ -1518,7 +1459,7 @@ namespace glz::detail
15181459
if (index == N) {
15191460
// make sure the seed does not collide with any hashes
15201461
const auto bucket = seed % bsize;
1521-
if (not contains(std::span{bucket_index.data(), N}, bucket)) {
1462+
if (not contains(bucket_index.data(), N, bucket)) {
15221463
return; // found working seed
15231464
}
15241465
}
@@ -1542,7 +1483,7 @@ namespace glz::detail
15421483

15431484
template <class T>
15441485
constexpr auto hash_info = [] {
1545-
if constexpr ((glaze_object_t<T> || reflectable<T> ||
1486+
if constexpr ((glaze_object_t<T> || reflectable<T> || glaze_flags_t<T> ||
15461487
((std::is_enum_v<std::remove_cvref_t<T>> && meta_keys<T>) || glaze_enum_t<T>)) &&
15471488
(reflect<T>::size > 0)) {
15481489
constexpr auto& k_info = keys_info<T>;

include/glaze/core/seek.hpp

+17-25
Original file line numberDiff line numberDiff line change
@@ -533,48 +533,40 @@ namespace glz
533533
return arrs;
534534
}
535535

536-
template <class T, string_literal key_str>
537-
struct member_getter
538-
{
539-
static constexpr auto frozen_map = detail::make_map<T>();
540-
static constexpr auto member_it = frozen_map.find(key_str.sv());
541-
};
542-
543536
// TODO support custom types
544-
template <class Root_t, string_literal ptr, class Expected_t = void>
537+
template <class Root, string_literal ptr, class Expected = void>
545538
constexpr bool valid()
546539
{
547-
using V = std::decay_t<Root_t>;
540+
using V = std::decay_t<Root>;
548541
if constexpr (ptr.sv() == sv{""}) {
549-
return std::same_as<Expected_t, void> || std::same_as<V, Expected_t>;
542+
return std::same_as<Expected, void> || std::same_as<V, Expected>;
550543
}
551544
else {
552545
constexpr auto tokens = tokenize_json_ptr(ptr.sv());
553546
constexpr auto key_str = tokens.first;
554547
constexpr auto rem_ptr = glz::string_literal_from_view<tokens.second.size()>(tokens.second);
555548
if constexpr (glz::detail::glaze_object_t<V>) {
556-
constexpr auto string_literal_key = glz::string_literal_from_view<key_str.size()>(key_str);
557-
using G = member_getter<V, string_literal_key>;
558-
if constexpr (G::member_it != G::frozen_map.end()) {
559-
constexpr auto& element = G::member_it->second;
560-
constexpr auto I = element.index();
561-
constexpr auto& member_ptr = get<I>(element);
562-
563-
using mptr_t = std::decay_t<decltype(member_ptr)>;
564-
using T = member_t<V, mptr_t>;
549+
constexpr auto& HashInfo = detail::hash_info<V>;
550+
constexpr auto I = detail::decode_hash_with_size<JSON, V, HashInfo, HashInfo.type>::op(key_str.data(), key_str.data() + key_str.size(), key_str.size());
551+
552+
if constexpr (I < reflect<V>::size) {
553+
if constexpr (key_str != reflect<V>::keys[I]) {
554+
return false;
555+
}
556+
using T = refl_t<V, I>;
565557
if constexpr (is_specialization_v<T, includer>) {
566-
return valid<file_include, rem_ptr, Expected_t>();
558+
return valid<file_include, rem_ptr, Expected>();
567559
}
568560
else {
569-
return valid<T, rem_ptr, Expected_t>();
561+
return valid<T, rem_ptr, Expected>();
570562
}
571563
}
572564
else {
573565
return false;
574566
}
575567
}
576568
else if constexpr (glz::detail::writable_map_t<V>) {
577-
return valid<typename V::mapped_type, rem_ptr, Expected_t>();
569+
return valid<typename V::mapped_type, rem_ptr, Expected>();
578570
}
579571
else if constexpr (glz::detail::glaze_array_t<V>) {
580572
constexpr auto member_array = glz::detail::make_array<std::decay_t<V>>();
@@ -585,7 +577,7 @@ namespace glz
585577
constexpr auto member = member_array[index];
586578
constexpr auto member_ptr = std::get<member.index()>(member);
587579
using sub_t = decltype(glz::get_member(std::declval<V>(), member_ptr));
588-
return valid<sub_t, rem_ptr, Expected_t>();
580+
return valid<sub_t, rem_ptr, Expected>();
589581
}
590582
else {
591583
return false;
@@ -597,13 +589,13 @@ namespace glz
597589
}
598590
else if constexpr (glz::detail::array_t<V>) {
599591
if (glz::detail::stoui(key_str)) {
600-
return valid<range_value_t<V>, rem_ptr, Expected_t>();
592+
return valid<range_value_t<V>, rem_ptr, Expected>();
601593
}
602594
return false;
603595
}
604596
else if constexpr (glz::detail::nullable_t<V>) {
605597
using sub_t = decltype(*std::declval<V>());
606-
return valid<sub_t, ptr, Expected_t>();
598+
return valid<sub_t, ptr, Expected>();
607599
}
608600
else {
609601
return false;

0 commit comments

Comments
 (0)