Coverage Report

Created: 2026-01-10 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/immer/immer/detail/hamts/champ.hpp
Line
Count
Source
1
//
2
// immer: immutable data structures for C++
3
// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
4
//
5
// This software is distributed under the Boost Software License, Version 1.0.
6
// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
7
//
8
9
#pragma once
10
11
#include <immer/config.hpp>
12
#include <immer/detail/hamts/node.hpp>
13
14
#include <algorithm>
15
16
namespace immer {
17
namespace detail {
18
namespace hamts {
19
20
#if IMMER_DEBUG_STATS
21
struct champ_debug_stats
22
{
23
    std::size_t bits       = {};
24
    std::size_t value_size = {};
25
    std::size_t child_size = sizeof(void*);
26
27
    std::size_t inner_node_count         = {};
28
    std::size_t inner_node_w_value_count = {};
29
    std::size_t inner_node_w_child_count = {};
30
    std::size_t collision_node_count     = {};
31
32
    std::size_t child_count     = {};
33
    std::size_t value_count     = {};
34
    std::size_t collision_count = {};
35
36
    friend champ_debug_stats operator+(champ_debug_stats a, champ_debug_stats b)
37
    {
38
        if (a.bits != b.bits || a.value_size != b.value_size ||
39
            a.child_size != b.child_size)
40
            throw std::runtime_error{"accumulating incompatible stats"};
41
        return {
42
            a.bits,
43
            a.value_size,
44
            a.child_size,
45
            a.inner_node_count + b.inner_node_count,
46
            a.inner_node_w_value_count + b.inner_node_w_value_count,
47
            a.inner_node_w_child_count + b.inner_node_w_child_count,
48
            a.collision_node_count + b.collision_node_count,
49
            a.child_count + b.child_count,
50
            a.value_count + b.value_count,
51
            a.collision_count + b.collision_count,
52
        };
53
    }
54
55
    struct summary
56
    {
57
        double collision_ratio;
58
59
        double utilization;
60
        double child_utilization;
61
        double value_utilization;
62
63
        double dense_utilization;
64
        double dense_value_utilization;
65
        double dense_child_utilization;
66
67
        friend std::ostream& operator<<(std::ostream& os, const summary& s)
68
        {
69
            os << "---\n";
70
            os << "collisions\n"
71
               << "  ratio = " << s.collision_ratio << " %\n";
72
            os << "utilization\n"
73
               << "  total    = " << s.utilization << " %\n"
74
               << "  children = " << s.child_utilization << " %\n"
75
               << "  values   = " << s.value_utilization << " %\n";
76
            os << "utilization (dense)\n"
77
               << "  total    = " << s.dense_utilization << " %\n"
78
               << "  children = " << s.dense_child_utilization << " %\n"
79
               << "  values   = " << s.dense_value_utilization << " %\n";
80
            return os;
81
        }
82
    };
83
84
    summary get_summary() const
85
    {
86
        auto m = std::size_t{1} << bits;
87
88
        auto collision_ratio = 100. * collision_count / value_count;
89
90
        auto capacity          = m * inner_node_count;
91
        auto child_utilization = 100. * child_count / capacity;
92
        auto value_utilization = 100. * value_count / capacity;
93
        auto utilization =
94
            100. * (value_count * value_size + child_count * child_size) /
95
            (capacity * value_size + capacity * child_size);
96
97
        auto value_capacity = m * inner_node_w_value_count;
98
        auto child_capacity = m * inner_node_w_child_count;
99
        auto dense_child_utilization =
100
            child_capacity == 0 ? 100. : 100. * child_count / child_capacity;
101
        auto dense_value_utilization =
102
            value_capacity == 0 ? 100. : 100. * value_count / value_capacity;
103
        auto dense_utilization =
104
            value_capacity + child_capacity == 0
105
                ? 100.
106
                : 100. * (value_count * value_size + child_count * child_size) /
107
                      (value_capacity * value_size +
108
                       child_capacity * child_size);
109
110
        return {collision_ratio,
111
                utilization,
112
                child_utilization,
113
                value_utilization,
114
                dense_utilization,
115
                dense_value_utilization,
116
                dense_child_utilization};
117
    }
118
};
119
#endif
120
121
template <typename T,
122
          typename Hash,
123
          typename Equal,
124
          typename MemoryPolicy,
125
          bits_t B>
126
struct champ
127
{
128
    static constexpr auto bits = B;
129
130
    using node_t   = node<T, Hash, Equal, MemoryPolicy, B>;
131
    using edit_t   = typename MemoryPolicy::transience_t::edit;
132
    using owner_t  = typename MemoryPolicy::transience_t::owner;
133
    using bitmap_t = typename get_bitmap_type<B>::type;
134
    using hash_t   = typename node_t::hash_t;
135
136
    static_assert(branches<B> <= sizeof(bitmap_t) * 8, "");
137
138
    node_t* root;
139
    size_t size;
140
141
    static node_t* empty()
142
404k
    {
143
404k
        static const auto empty_ = [] {
144
1
            constexpr auto size = node_t::sizeof_inner_n(0);
145
1
            static std::aligned_storage_t<size, alignof(std::max_align_t)>
146
1
                storage;
147
1
            return node_t::make_inner_n_into(&storage, size, 0u);
148
1
        }();
149
404k
        return empty_->inc();
150
404k
    }
151
152
    champ(node_t* r, size_t sz = 0) noexcept
153
796k
        : root{r}
154
796k
        , size{sz}
155
796k
    {
156
796k
    }
157
158
    champ(const champ& other) noexcept
159
14.8k
        : champ{other.root, other.size}
160
14.8k
    {
161
14.8k
        inc();
162
14.8k
    }
163
164
    champ(champ&& other) noexcept
165
383k
        : champ{empty()}
166
383k
    {
167
383k
        swap(*this, other);
168
383k
    }
169
170
    champ& operator=(const champ& other)
171
    {
172
        auto next = other;
173
        swap(*this, next);
174
        return *this;
175
    }
176
177
    champ& operator=(champ&& other) noexcept
178
440k
    {
179
440k
        swap(*this, other);
180
440k
        return *this;
181
440k
    }
182
183
    friend void swap(champ& x, champ& y) noexcept
184
823k
    {
185
823k
        using std::swap;
186
823k
        swap(x.root, y.root);
187
823k
        swap(x.size, y.size);
188
823k
    }
189
190
796k
    ~champ() { dec(); }
191
192
14.8k
    void inc() const { root->inc(); }
193
194
    void dec() const
195
796k
    {
196
796k
        if (root->dec())
197
380k
            node_t::delete_deep(root, 0);
198
796k
    }
199
200
    std::size_t do_check_champ(node_t* node,
201
                               count_t depth,
202
                               size_t path_hash,
203
                               size_t hash_mask) const
204
    {
205
        auto result = std::size_t{};
206
        if (depth < max_depth<hash_t, B>) {
207
            auto nodemap = node->nodemap();
208
            if (nodemap) {
209
                auto fst = node->children();
210
                for (auto idx = std::size_t{}; idx < branches<B>; ++idx) {
211
                    if (nodemap & (1 << idx)) {
212
                        auto child = *fst++;
213
                        result +=
214
                            do_check_champ(child,
215
                                           depth + 1,
216
                                           path_hash | (idx << (B * depth)),
217
                                           (hash_mask << B) | mask<hash_t, B>);
218
                    }
219
                }
220
            }
221
            auto datamap = node->datamap();
222
            if (datamap) {
223
                auto fst = node->values();
224
                for (auto idx = std::size_t{}; idx < branches<B>; ++idx) {
225
                    if (datamap & (1 << idx)) {
226
                        auto hash  = Hash{}(*fst++);
227
                        auto check = (hash & hash_mask) ==
228
                                     (path_hash | (idx << (B * depth)));
229
                        // assert(check);
230
                        result += !!check;
231
                    }
232
                }
233
            }
234
        } else {
235
            auto fst = node->collisions();
236
            auto lst = fst + node->collision_count();
237
            for (; fst != lst; ++fst) {
238
                auto hash  = Hash{}(*fst);
239
                auto check = hash == path_hash;
240
                // assert(check);
241
                result += !!check;
242
            }
243
        }
244
        return result;
245
    }
246
247
    // Checks that the hashes of the values correspond with what has actually
248
    // been inserted.  If it doesn't it can mean that corruption has happened
249
    // due some value being moved out of the champ when it should have not.
250
    bool check_champ() const
251
    {
252
        auto r = do_check_champ(root, 0, 0, mask<hash_t, B>);
253
        // assert(r == size);
254
        return r == size;
255
    }
256
257
#if IMMER_DEBUG_STATS
258
    void do_get_debug_stats(champ_debug_stats& stats,
259
                            node_t* node,
260
                            count_t depth) const
261
    {
262
        if (depth < max_depth<hash_t, B>) {
263
            ++stats.inner_node_count;
264
            stats.inner_node_w_value_count += node->data_count() > 0;
265
            stats.inner_node_w_child_count += node->children_count() > 0;
266
            stats.value_count += node->data_count();
267
            stats.child_count += node->children_count();
268
            auto nodemap = node->nodemap();
269
            if (nodemap) {
270
                auto fst = node->children();
271
                auto lst = fst + node->children_count();
272
                for (; fst != lst; ++fst)
273
                    do_get_debug_stats(stats, *fst, depth + 1);
274
            }
275
        } else {
276
            ++stats.collision_node_count;
277
            stats.collision_count += node->collision_count();
278
        }
279
    }
280
281
    champ_debug_stats get_debug_stats() const
282
    {
283
        auto stats = champ_debug_stats{B, sizeof(T)};
284
        do_get_debug_stats(stats, root, 0);
285
        return stats;
286
    }
287
#endif
288
289
    template <typename U>
290
    static auto from_initializer_list(std::initializer_list<U> values)
291
    {
292
        auto e      = owner_t{};
293
        auto result = champ{empty()};
294
        for (auto&& v : values)
295
            result.add_mut(e, v);
296
        return result;
297
    }
298
299
    template <typename Iter,
300
              typename Sent,
301
              std::enable_if_t<compatible_sentinel_v<Iter, Sent>, bool> = true>
302
    static auto from_range(Iter first, Sent last)
303
    {
304
        auto e      = owner_t{};
305
        auto result = champ{empty()};
306
        for (; first != last; ++first)
307
            result.add_mut(e, *first);
308
        return result;
309
    }
310
311
    template <typename Fn>
312
    void for_each_chunk(Fn&& fn) const
313
    {
314
        for_each_chunk_traversal(root, 0, fn);
315
    }
316
317
    template <typename Fn>
318
    void
319
    for_each_chunk_traversal(const node_t* node, count_t depth, Fn&& fn) const
320
135k
    {
321
135k
        if (depth < max_depth<hash_t, B>) {
322
130k
            auto datamap = node->datamap();
323
130k
            if (datamap)
324
48.7k
                fn(node->values(), node->values() + node->data_count());
325
130k
            auto nodemap = node->nodemap();
326
130k
            if (nodemap) {
327
87.3k
                auto fst = node->children();
328
87.3k
                auto lst = fst + node->children_count();
329
185k
                for (; fst != lst; ++fst)
330
97.8k
                    for_each_chunk_traversal(*fst, depth + 1, fn);
331
87.3k
            }
332
130k
        } else {
333
4.82k
            fn(node->collisions(),
334
4.82k
               node->collisions() + node->collision_count());
335
4.82k
        }
336
135k
    }
map-st.cpp:void immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::for_each_chunk_traversal<immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::diff<std::__1::equal_to<std::__1::pair<unsigned long, int> >, immer::differ<LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#1}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&, auto:2&&)#1}> >(immer::detail::hamts::node<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u> const*, immer::detail::hamts::node, unsigned int, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}) const::{lambda(auto:1 const&, {lambda(auto:1&&)#2} const&)#1}>(immer::detail::hamts::node, unsigned int, fuzzer_input&&) const
Line
Count
Source
320
1.26k
    {
321
1.26k
        if (depth < max_depth<hash_t, B>) {
322
1.26k
            auto datamap = node->datamap();
323
1.26k
            if (datamap)
324
449
                fn(node->values(), node->values() + node->data_count());
325
1.26k
            auto nodemap = node->nodemap();
326
1.26k
            if (nodemap) {
327
917
                auto fst = node->children();
328
917
                auto lst = fst + node->children_count();
329
2.80k
                for (; fst != lst; ++fst)
330
1.89k
                    for_each_chunk_traversal(*fst, depth + 1, fn);
331
917
            }
332
1.26k
        } else {
333
0
            fn(node->collisions(),
334
0
               node->collisions() + node->collision_count());
335
0
        }
336
1.26k
    }
map-st.cpp:void immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::for_each_chunk_traversal<immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::diff<std::__1::equal_to<std::__1::pair<unsigned long, int> >, immer::differ<LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#1}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&, auto:2&&)#1}> >(immer::detail::hamts::node<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u> const*, immer::detail::hamts::node, unsigned int, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}) const::{lambda(auto:1 const&, {lambda(auto:1&&)#2} const&)#1}&>(immer::detail::hamts::node, unsigned int, fuzzer_input&&) const
Line
Count
Source
320
10.7k
    {
321
10.7k
        if (depth < max_depth<hash_t, B>) {
322
10.4k
            auto datamap = node->datamap();
323
10.4k
            if (datamap)
324
3.58k
                fn(node->values(), node->values() + node->data_count());
325
10.4k
            auto nodemap = node->nodemap();
326
10.4k
            if (nodemap) {
327
7.39k
                auto fst = node->children();
328
7.39k
                auto lst = fst + node->children_count();
329
16.2k
                for (; fst != lst; ++fst)
330
8.88k
                    for_each_chunk_traversal(*fst, depth + 1, fn);
331
7.39k
            }
332
10.4k
        } else {
333
331
            fn(node->collisions(),
334
331
               node->collisions() + node->collision_count());
335
331
        }
336
10.7k
    }
map-st.cpp:void immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::for_each_chunk_traversal<immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::diff<std::__1::equal_to<std::__1::pair<unsigned long, int> >, immer::differ<LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#1}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&, auto:2&&)#1}> >(immer::detail::hamts::node<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u> const*, immer::detail::hamts::node, unsigned int, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}) const::{lambda(auto:1 const&, {lambda(auto:1&&)#2} const&)#2}>(immer::detail::hamts::node, unsigned int, fuzzer_input&&) const
Line
Count
Source
320
1.32k
    {
321
1.32k
        if (depth < max_depth<hash_t, B>) {
322
1.32k
            auto datamap = node->datamap();
323
1.32k
            if (datamap)
324
495
                fn(node->values(), node->values() + node->data_count());
325
1.32k
            auto nodemap = node->nodemap();
326
1.32k
            if (nodemap) {
327
954
                auto fst = node->children();
328
954
                auto lst = fst + node->children_count();
329
3.03k
                for (; fst != lst; ++fst)
330
2.07k
                    for_each_chunk_traversal(*fst, depth + 1, fn);
331
954
            }
332
1.32k
        } else {
333
0
            fn(node->collisions(),
334
0
               node->collisions() + node->collision_count());
335
0
        }
336
1.32k
    }
map-st.cpp:void immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::for_each_chunk_traversal<immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::diff<std::__1::equal_to<std::__1::pair<unsigned long, int> >, immer::differ<LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#1}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&, auto:2&&)#1}> >(immer::detail::hamts::node<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u> const*, immer::detail::hamts::node, unsigned int, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}) const::{lambda(auto:1 const&, {lambda(auto:1&&)#2} const&)#2}&>(immer::detail::hamts::node, unsigned int, fuzzer_input&&) const
Line
Count
Source
320
11.0k
    {
321
11.0k
        if (depth < max_depth<hash_t, B>) {
322
10.6k
            auto datamap = node->datamap();
323
10.6k
            if (datamap)
324
3.62k
                fn(node->values(), node->values() + node->data_count());
325
10.6k
            auto nodemap = node->nodemap();
326
10.6k
            if (nodemap) {
327
7.56k
                auto fst = node->children();
328
7.56k
                auto lst = fst + node->children_count();
329
16.5k
                for (; fst != lst; ++fst)
330
8.96k
                    for_each_chunk_traversal(*fst, depth + 1, fn);
331
7.56k
            }
332
10.6k
        } else {
333
370
            fn(node->collisions(),
334
370
               node->collisions() + node->collision_count());
335
370
        }
336
11.0k
    }
map-st.cpp:void immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::for_each_chunk_traversal<immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::diff<std::__1::equal_to<std::__1::pair<unsigned long, int> >, immer::differ<LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#1}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&, auto:2&&)#1}>&>(immer::detail::hamts::node<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u> const*, immer::detail::hamts::node, unsigned int, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}) const::{lambda(auto:1 const&, {lambda(auto:1&&)#2} const&)#1}>(immer::detail::hamts::node, unsigned int, fuzzer_input&&) const
Line
Count
Source
320
3.41k
    {
321
3.41k
        if (depth < max_depth<hash_t, B>) {
322
3.13k
            auto datamap = node->datamap();
323
3.13k
            if (datamap)
324
1.60k
                fn(node->values(), node->values() + node->data_count());
325
3.13k
            auto nodemap = node->nodemap();
326
3.13k
            if (nodemap) {
327
1.68k
                auto fst = node->children();
328
1.68k
                auto lst = fst + node->children_count();
329
4.15k
                for (; fst != lst; ++fst)
330
2.47k
                    for_each_chunk_traversal(*fst, depth + 1, fn);
331
1.68k
            }
332
3.13k
        } else {
333
281
            fn(node->collisions(),
334
281
               node->collisions() + node->collision_count());
335
281
        }
336
3.41k
    }
map-st.cpp:void immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::for_each_chunk_traversal<immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::diff<std::__1::equal_to<std::__1::pair<unsigned long, int> >, immer::differ<LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#1}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&, auto:2&&)#1}>&>(immer::detail::hamts::node<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u> const*, immer::detail::hamts::node, unsigned int, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}) const::{lambda(auto:1 const&, {lambda(auto:1&&)#2} const&)#1}&>(immer::detail::hamts::node, unsigned int, fuzzer_input&&) const
Line
Count
Source
320
9.15k
    {
321
9.15k
        if (depth < max_depth<hash_t, B>) {
322
8.79k
            auto datamap = node->datamap();
323
8.79k
            if (datamap)
324
3.27k
                fn(node->values(), node->values() + node->data_count());
325
8.79k
            auto nodemap = node->nodemap();
326
8.79k
            if (nodemap) {
327
5.83k
                auto fst = node->children();
328
5.83k
                auto lst = fst + node->children_count();
329
12.5k
                for (; fst != lst; ++fst)
330
6.68k
                    for_each_chunk_traversal(*fst, depth + 1, fn);
331
5.83k
            }
332
8.79k
        } else {
333
359
            fn(node->collisions(),
334
359
               node->collisions() + node->collision_count());
335
359
        }
336
9.15k
    }
map-st.cpp:void immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::for_each_chunk_traversal<immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::diff<std::__1::equal_to<std::__1::pair<unsigned long, int> >, immer::differ<LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#1}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&, auto:2&&)#1}>&>(immer::detail::hamts::node<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u> const*, immer::detail::hamts::node, unsigned int, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}) const::{lambda(auto:1 const&, {lambda(auto:1&&)#2} const&)#2}>(immer::detail::hamts::node, unsigned int, fuzzer_input&&) const
Line
Count
Source
320
4.30k
    {
321
4.30k
        if (depth < max_depth<hash_t, B>) {
322
4.00k
            auto datamap = node->datamap();
323
4.00k
            if (datamap)
324
2.27k
                fn(node->values(), node->values() + node->data_count());
325
4.00k
            auto nodemap = node->nodemap();
326
4.00k
            if (nodemap) {
327
1.90k
                auto fst = node->children();
328
1.90k
                auto lst = fst + node->children_count();
329
4.57k
                for (; fst != lst; ++fst)
330
2.66k
                    for_each_chunk_traversal(*fst, depth + 1, fn);
331
1.90k
            }
332
4.00k
        } else {
333
309
            fn(node->collisions(),
334
309
               node->collisions() + node->collision_count());
335
309
        }
336
4.30k
    }
map-st.cpp:void immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::for_each_chunk_traversal<immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::diff<std::__1::equal_to<std::__1::pair<unsigned long, int> >, immer::differ<LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#1}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&, auto:2&&)#1}>&>(immer::detail::hamts::node<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u> const*, immer::detail::hamts::node, unsigned int, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}) const::{lambda(auto:1 const&, {lambda(auto:1&&)#2} const&)#2}&>(immer::detail::hamts::node, unsigned int, fuzzer_input&&) const
Line
Count
Source
320
9.19k
    {
321
9.19k
        if (depth < max_depth<hash_t, B>) {
322
8.86k
            auto datamap = node->datamap();
323
8.86k
            if (datamap)
324
3.13k
                fn(node->values(), node->values() + node->data_count());
325
8.86k
            auto nodemap = node->nodemap();
326
8.86k
            if (nodemap) {
327
6.12k
                auto fst = node->children();
328
6.12k
                auto lst = fst + node->children_count();
329
12.6k
                for (; fst != lst; ++fst)
330
6.52k
                    for_each_chunk_traversal(*fst, depth + 1, fn);
331
6.12k
            }
332
8.86k
        } else {
333
329
            fn(node->collisions(),
334
329
               node->collisions() + node->collision_count());
335
329
        }
336
9.19k
    }
map-st.cpp:void immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::for_each_chunk_traversal<immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::diff_data_node<std::__1::equal_to<std::__1::pair<unsigned long, int> >, immer::differ<LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#1}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&, auto:2&&)#1}>&>(immer::detail::hamts::node<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u> const*, immer::detail::hamts::node, unsigned int, unsigned int, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}) const::{lambda(auto:1 const&, {lambda(auto:1&&)#2} const&)#1}>(immer::detail::hamts::node, unsigned int, fuzzer_input&&) const
Line
Count
Source
320
12.6k
    {
321
12.6k
        if (depth < max_depth<hash_t, B>) {
322
12.3k
            auto datamap = node->datamap();
323
12.3k
            if (datamap)
324
6.27k
                fn(node->values(), node->values() + node->data_count());
325
12.3k
            auto nodemap = node->nodemap();
326
12.3k
            if (nodemap) {
327
6.52k
                auto fst = node->children();
328
6.52k
                auto lst = fst + node->children_count();
329
13.9k
                for (; fst != lst; ++fst)
330
7.46k
                    for_each_chunk_traversal(*fst, depth + 1, fn);
331
6.52k
            }
332
12.3k
        } else {
333
361
            fn(node->collisions(),
334
361
               node->collisions() + node->collision_count());
335
361
        }
336
12.6k
    }
map-st.cpp:void immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::for_each_chunk_traversal<immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::diff_data_node<std::__1::equal_to<std::__1::pair<unsigned long, int> >, immer::differ<LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#1}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&, auto:2&&)#1}>&>(immer::detail::hamts::node<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u> const*, immer::detail::hamts::node, unsigned int, unsigned int, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}) const::{lambda(auto:1 const&, {lambda(auto:1&&)#2} const&)#1}&>(immer::detail::hamts::node, unsigned int, fuzzer_input&&) const
Line
Count
Source
320
28.1k
    {
321
28.1k
        if (depth < max_depth<hash_t, B>) {
322
27.0k
            auto datamap = node->datamap();
323
27.0k
            if (datamap)
324
7.46k
                fn(node->values(), node->values() + node->data_count());
325
27.0k
            auto nodemap = node->nodemap();
326
27.0k
            if (nodemap) {
327
20.3k
                auto fst = node->children();
328
20.3k
                auto lst = fst + node->children_count();
329
40.9k
                for (; fst != lst; ++fst)
330
20.6k
                    for_each_chunk_traversal(*fst, depth + 1, fn);
331
20.3k
            }
332
27.0k
        } else {
333
1.05k
            fn(node->collisions(),
334
1.05k
               node->collisions() + node->collision_count());
335
1.05k
        }
336
28.1k
    }
map-st.cpp:void immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::for_each_chunk_traversal<immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::diff_node_data<std::__1::equal_to<std::__1::pair<unsigned long, int> >, immer::differ<LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#1}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&, auto:2&&)#1}>&>(immer::detail::hamts::node<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u> const*, immer::detail::hamts::node, unsigned int, unsigned int, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}) const::{lambda(auto:1 const&, {lambda(auto:1&&)#2} const&)#1}>(immer::detail::hamts::node, unsigned int, fuzzer_input&&) const
Line
Count
Source
320
14.2k
    {
321
14.2k
        if (depth < max_depth<hash_t, B>) {
322
13.8k
            auto datamap = node->datamap();
323
13.8k
            if (datamap)
324
7.51k
                fn(node->values(), node->values() + node->data_count());
325
13.8k
            auto nodemap = node->nodemap();
326
13.8k
            if (nodemap) {
327
7.32k
                auto fst = node->children();
328
7.32k
                auto lst = fst + node->children_count();
329
15.1k
                for (; fst != lst; ++fst)
330
7.82k
                    for_each_chunk_traversal(*fst, depth + 1, fn);
331
7.32k
            }
332
13.8k
        } else {
333
360
            fn(node->collisions(),
334
360
               node->collisions() + node->collision_count());
335
360
        }
336
14.2k
    }
map-st.cpp:void immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::for_each_chunk_traversal<immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::diff_node_data<std::__1::equal_to<std::__1::pair<unsigned long, int> >, immer::differ<LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#1}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&, auto:2&&)#1}>&>(immer::detail::hamts::node<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u> const*, immer::detail::hamts::node, unsigned int, unsigned int, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}) const::{lambda(auto:1 const&, {lambda(auto:1&&)#2} const&)#1}&>(immer::detail::hamts::node, unsigned int, fuzzer_input&&) const
Line
Count
Source
320
29.5k
    {
321
29.5k
        if (depth < max_depth<hash_t, B>) {
322
28.4k
            auto datamap = node->datamap();
323
28.4k
            if (datamap)
324
9.01k
                fn(node->values(), node->values() + node->data_count());
325
28.4k
            auto nodemap = node->nodemap();
326
28.4k
            if (nodemap) {
327
20.8k
                auto fst = node->children();
328
20.8k
                auto lst = fst + node->children_count();
329
42.6k
                for (; fst != lst; ++fst)
330
21.7k
                    for_each_chunk_traversal(*fst, depth + 1, fn);
331
20.8k
            }
332
28.4k
        } else {
333
1.07k
            fn(node->collisions(),
334
1.07k
               node->collisions() + node->collision_count());
335
1.07k
        }
336
29.5k
    }
337
338
    template <typename EqualValue, typename Differ>
339
    void diff(const champ& new_champ, Differ&& differ) const
340
16.7k
    {
341
16.7k
        diff<EqualValue>(root, new_champ.root, 0, std::forward<Differ>(differ));
342
16.7k
    }
343
344
    template <typename EqualValue, typename Differ>
345
    void diff(const node_t* old_node,
346
              const node_t* new_node,
347
              count_t depth,
348
              Differ&& differ) const
349
362k
    {
350
362k
        if (old_node == new_node)
351
97.6k
            return;
352
264k
        if (depth < max_depth<hash_t, B>) {
353
260k
            auto old_nodemap = old_node->nodemap();
354
260k
            auto new_nodemap = new_node->nodemap();
355
260k
            auto old_datamap = old_node->datamap();
356
260k
            auto new_datamap = new_node->datamap();
357
260k
            auto old_bits    = old_nodemap | old_datamap;
358
260k
            auto new_bits    = new_nodemap | new_datamap;
359
260k
            auto changes     = old_bits ^ new_bits;
360
361
            // added bits
362
260k
            for (auto bit : set_bits_range<bitmap_t>(new_bits & changes)) {
363
24.9k
                if (new_nodemap & bit) {
364
4.68k
                    auto offset = new_node->children_count(bit);
365
4.68k
                    auto child  = new_node->children()[offset];
366
4.68k
                    for_each_chunk_traversal(
367
4.68k
                        child,
368
4.68k
                        depth + 1,
369
9.88k
                        [&](auto const& begin, auto const& end) {
370
33.8k
                            for (auto it = begin; it != end; it++)
371
23.9k
                                differ.added(*it);
372
9.88k
                        });
map-st.cpp:auto immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::diff<std::__1::equal_to<std::__1::pair<unsigned long, int> >, immer::differ<LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#1}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&, auto:2&&)#1}> >(immer::detail::hamts::node<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u> const*, immer::detail::hamts::node, unsigned int, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}) const::{lambda(auto:1 const&, {lambda(auto:1&&)#2} const&)#1}::operator()<std::__1::pair<unsigned long, int> const*, {lambda(auto:1 const&, {lambda(auto:1&&)#2} const&)#1}>(immer::detail::hamts::node<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u> const, std::__1::pair<unsigned long, int> const* const) const
Line
Count
Source
369
4.36k
                        [&](auto const& begin, auto const& end) {
370
16.4k
                            for (auto it = begin; it != end; it++)
371
12.0k
                                differ.added(*it);
372
4.36k
                        });
map-st.cpp:auto immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::diff<std::__1::equal_to<std::__1::pair<unsigned long, int> >, immer::differ<LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#1}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&, auto:2&&)#1}>&>(immer::detail::hamts::node<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u> const*, immer::detail::hamts::node, unsigned int, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}) const::{lambda(auto:1 const&, {lambda(auto:1&&)#2} const&)#1}::operator()<std::__1::pair<unsigned long, int> const*, {lambda(auto:1 const&, {lambda(auto:1&&)#2} const&)#1}>(immer::detail::hamts::node<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u> const, std::__1::pair<unsigned long, int> const* const) const
Line
Count
Source
369
5.52k
                        [&](auto const& begin, auto const& end) {
370
17.4k
                            for (auto it = begin; it != end; it++)
371
11.9k
                                differ.added(*it);
372
5.52k
                        });
373
20.2k
                } else if (new_datamap & bit) {
374
20.2k
                    auto offset       = new_node->data_count(bit);
375
20.2k
                    auto const& value = new_node->values()[offset];
376
20.2k
                    differ.added(value);
377
20.2k
                }
378
24.9k
            }
379
380
            // removed bits
381
260k
            for (auto bit : set_bits_range<bitmap_t>(old_bits & changes)) {
382
34.6k
                if (old_nodemap & bit) {
383
5.63k
                    auto offset = old_node->children_count(bit);
384
5.63k
                    auto child  = old_node->children()[offset];
385
5.63k
                    for_each_chunk_traversal(
386
5.63k
                        child,
387
5.63k
                        depth + 1,
388
10.5k
                        [&](auto const& begin, auto const& end) {
389
36.5k
                            for (auto it = begin; it != end; it++)
390
26.0k
                                differ.removed(*it);
391
10.5k
                        });
map-st.cpp:auto immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::diff<std::__1::equal_to<std::__1::pair<unsigned long, int> >, immer::differ<LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#1}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&, auto:2&&)#1}> >(immer::detail::hamts::node<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u> const*, immer::detail::hamts::node, unsigned int, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}) const::{lambda(auto:1 const&, {lambda(auto:1&&)#2} const&)#2}::operator()<std::__1::pair<unsigned long, int> const*, {lambda(auto:1 const&, {lambda(auto:1&&)#2} const&)#2}>(immer::detail::hamts::node<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u> const, std::__1::pair<unsigned long, int> const* const) const
Line
Count
Source
388
4.49k
                        [&](auto const& begin, auto const& end) {
389
16.6k
                            for (auto it = begin; it != end; it++)
390
12.1k
                                differ.removed(*it);
391
4.49k
                        });
map-st.cpp:auto immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::diff<std::__1::equal_to<std::__1::pair<unsigned long, int> >, immer::differ<LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#1}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&, auto:2&&)#1}>&>(immer::detail::hamts::node<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u> const*, immer::detail::hamts::node, unsigned int, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}) const::{lambda(auto:1 const&, {lambda(auto:1&&)#2} const&)#2}::operator()<std::__1::pair<unsigned long, int> const*, {lambda(auto:1 const&, {lambda(auto:1&&)#2} const&)#2}>(immer::detail::hamts::node<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u> const, std::__1::pair<unsigned long, int> const* const) const
Line
Count
Source
388
6.03k
                        [&](auto const& begin, auto const& end) {
389
19.8k
                            for (auto it = begin; it != end; it++)
390
13.8k
                                differ.removed(*it);
391
6.03k
                        });
392
28.9k
                } else if (old_datamap & bit) {
393
28.9k
                    auto offset       = old_node->data_count(bit);
394
28.9k
                    auto const& value = old_node->values()[offset];
395
28.9k
                    differ.removed(value);
396
28.9k
                }
397
34.6k
            }
398
399
            // bits in both nodes
400
729k
            for (auto bit : set_bits_range<bitmap_t>(old_bits & new_bits)) {
401
729k
                if ((old_nodemap & bit) && (new_nodemap & bit)) {
402
345k
                    auto old_offset = old_node->children_count(bit);
403
345k
                    auto new_offset = new_node->children_count(bit);
404
345k
                    auto old_child  = old_node->children()[old_offset];
405
345k
                    auto new_child  = new_node->children()[new_offset];
406
345k
                    diff<EqualValue>(old_child, new_child, depth + 1, differ);
407
384k
                } else if ((old_datamap & bit) && (new_nodemap & bit)) {
408
12.6k
                    diff_data_node<EqualValue>(
409
12.6k
                        old_node, new_node, bit, depth, differ);
410
371k
                } else if ((old_nodemap & bit) && (new_datamap & bit)) {
411
14.2k
                    diff_node_data<EqualValue>(
412
14.2k
                        old_node, new_node, bit, depth, differ);
413
357k
                } else if ((old_datamap & bit) && (new_datamap & bit)) {
414
357k
                    diff_data_data<EqualValue>(old_node, new_node, bit, differ);
415
357k
                }
416
729k
            }
417
260k
        } else {
418
4.48k
            diff_collisions<EqualValue>(old_node, new_node, differ);
419
4.48k
        }
420
264k
    }
map-st.cpp:void immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::diff<std::__1::equal_to<std::__1::pair<unsigned long, int> >, immer::differ<LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#1}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&, auto:2&&)#1}> >(immer::detail::hamts::node<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u> const*, immer::detail::hamts::node, unsigned int, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}) const
Line
Count
Source
349
16.7k
    {
350
16.7k
        if (old_node == new_node)
351
616
            return;
352
16.1k
        if (depth < max_depth<hash_t, B>) {
353
16.1k
            auto old_nodemap = old_node->nodemap();
354
16.1k
            auto new_nodemap = new_node->nodemap();
355
16.1k
            auto old_datamap = old_node->datamap();
356
16.1k
            auto new_datamap = new_node->datamap();
357
16.1k
            auto old_bits    = old_nodemap | old_datamap;
358
16.1k
            auto new_bits    = new_nodemap | new_datamap;
359
16.1k
            auto changes     = old_bits ^ new_bits;
360
361
            // added bits
362
16.1k
            for (auto bit : set_bits_range<bitmap_t>(new_bits & changes)) {
363
2.06k
                if (new_nodemap & bit) {
364
1.26k
                    auto offset = new_node->children_count(bit);
365
1.26k
                    auto child  = new_node->children()[offset];
366
1.26k
                    for_each_chunk_traversal(
367
1.26k
                        child,
368
1.26k
                        depth + 1,
369
1.26k
                        [&](auto const& begin, auto const& end) {
370
1.26k
                            for (auto it = begin; it != end; it++)
371
1.26k
                                differ.added(*it);
372
1.26k
                        });
373
1.26k
                } else if (new_datamap & bit) {
374
803
                    auto offset       = new_node->data_count(bit);
375
803
                    auto const& value = new_node->values()[offset];
376
803
                    differ.added(value);
377
803
                }
378
2.06k
            }
379
380
            // removed bits
381
16.1k
            for (auto bit : set_bits_range<bitmap_t>(old_bits & changes)) {
382
2.14k
                if (old_nodemap & bit) {
383
1.32k
                    auto offset = old_node->children_count(bit);
384
1.32k
                    auto child  = old_node->children()[offset];
385
1.32k
                    for_each_chunk_traversal(
386
1.32k
                        child,
387
1.32k
                        depth + 1,
388
1.32k
                        [&](auto const& begin, auto const& end) {
389
1.32k
                            for (auto it = begin; it != end; it++)
390
1.32k
                                differ.removed(*it);
391
1.32k
                        });
392
1.32k
                } else if (old_datamap & bit) {
393
822
                    auto offset       = old_node->data_count(bit);
394
822
                    auto const& value = old_node->values()[offset];
395
822
                    differ.removed(value);
396
822
                }
397
2.14k
            }
398
399
            // bits in both nodes
400
20.0k
            for (auto bit : set_bits_range<bitmap_t>(old_bits & new_bits)) {
401
20.0k
                if ((old_nodemap & bit) && (new_nodemap & bit)) {
402
16.2k
                    auto old_offset = old_node->children_count(bit);
403
16.2k
                    auto new_offset = new_node->children_count(bit);
404
16.2k
                    auto old_child  = old_node->children()[old_offset];
405
16.2k
                    auto new_child  = new_node->children()[new_offset];
406
16.2k
                    diff<EqualValue>(old_child, new_child, depth + 1, differ);
407
16.2k
                } else if ((old_datamap & bit) && (new_nodemap & bit)) {
408
1.18k
                    diff_data_node<EqualValue>(
409
1.18k
                        old_node, new_node, bit, depth, differ);
410
2.57k
                } else if ((old_nodemap & bit) && (new_datamap & bit)) {
411
1.62k
                    diff_node_data<EqualValue>(
412
1.62k
                        old_node, new_node, bit, depth, differ);
413
1.62k
                } else if ((old_datamap & bit) && (new_datamap & bit)) {
414
953
                    diff_data_data<EqualValue>(old_node, new_node, bit, differ);
415
953
                }
416
20.0k
            }
417
16.1k
        } else {
418
0
            diff_collisions<EqualValue>(old_node, new_node, differ);
419
0
        }
420
16.1k
    }
map-st.cpp:void immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::diff<std::__1::equal_to<std::__1::pair<unsigned long, int> >, immer::differ<LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#1}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&, auto:2&&)#1}>&>(immer::detail::hamts::node<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u> const*, immer::detail::hamts::node, unsigned int, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(auto:1&&)#2}) const
Line
Count
Source
349
345k
    {
350
345k
        if (old_node == new_node)
351
96.9k
            return;
352
248k
        if (depth < max_depth<hash_t, B>) {
353
243k
            auto old_nodemap = old_node->nodemap();
354
243k
            auto new_nodemap = new_node->nodemap();
355
243k
            auto old_datamap = old_node->datamap();
356
243k
            auto new_datamap = new_node->datamap();
357
243k
            auto old_bits    = old_nodemap | old_datamap;
358
243k
            auto new_bits    = new_nodemap | new_datamap;
359
243k
            auto changes     = old_bits ^ new_bits;
360
361
            // added bits
362
243k
            for (auto bit : set_bits_range<bitmap_t>(new_bits & changes)) {
363
22.8k
                if (new_nodemap & bit) {
364
3.41k
                    auto offset = new_node->children_count(bit);
365
3.41k
                    auto child  = new_node->children()[offset];
366
3.41k
                    for_each_chunk_traversal(
367
3.41k
                        child,
368
3.41k
                        depth + 1,
369
3.41k
                        [&](auto const& begin, auto const& end) {
370
3.41k
                            for (auto it = begin; it != end; it++)
371
3.41k
                                differ.added(*it);
372
3.41k
                        });
373
19.4k
                } else if (new_datamap & bit) {
374
19.4k
                    auto offset       = new_node->data_count(bit);
375
19.4k
                    auto const& value = new_node->values()[offset];
376
19.4k
                    differ.added(value);
377
19.4k
                }
378
22.8k
            }
379
380
            // removed bits
381
243k
            for (auto bit : set_bits_range<bitmap_t>(old_bits & changes)) {
382
32.4k
                if (old_nodemap & bit) {
383
4.30k
                    auto offset = old_node->children_count(bit);
384
4.30k
                    auto child  = old_node->children()[offset];
385
4.30k
                    for_each_chunk_traversal(
386
4.30k
                        child,
387
4.30k
                        depth + 1,
388
4.30k
                        [&](auto const& begin, auto const& end) {
389
4.30k
                            for (auto it = begin; it != end; it++)
390
4.30k
                                differ.removed(*it);
391
4.30k
                        });
392
28.1k
                } else if (old_datamap & bit) {
393
28.1k
                    auto offset       = old_node->data_count(bit);
394
28.1k
                    auto const& value = old_node->values()[offset];
395
28.1k
                    differ.removed(value);
396
28.1k
                }
397
32.4k
            }
398
399
            // bits in both nodes
400
709k
            for (auto bit : set_bits_range<bitmap_t>(old_bits & new_bits)) {
401
709k
                if ((old_nodemap & bit) && (new_nodemap & bit)) {
402
329k
                    auto old_offset = old_node->children_count(bit);
403
329k
                    auto new_offset = new_node->children_count(bit);
404
329k
                    auto old_child  = old_node->children()[old_offset];
405
329k
                    auto new_child  = new_node->children()[new_offset];
406
329k
                    diff<EqualValue>(old_child, new_child, depth + 1, differ);
407
380k
                } else if ((old_datamap & bit) && (new_nodemap & bit)) {
408
11.4k
                    diff_data_node<EqualValue>(
409
11.4k
                        old_node, new_node, bit, depth, differ);
410
368k
                } else if ((old_nodemap & bit) && (new_datamap & bit)) {
411
12.6k
                    diff_node_data<EqualValue>(
412
12.6k
                        old_node, new_node, bit, depth, differ);
413
356k
                } else if ((old_datamap & bit) && (new_datamap & bit)) {
414
356k
                    diff_data_data<EqualValue>(old_node, new_node, bit, differ);
415
356k
                }
416
709k
            }
417
243k
        } else {
418
4.48k
            diff_collisions<EqualValue>(old_node, new_node, differ);
419
4.48k
        }
420
248k
    }
421
422
    template <typename EqualValue, typename Differ>
423
    void diff_data_node(const node_t* old_node,
424
                        const node_t* new_node,
425
                        bitmap_t bit,
426
                        count_t depth,
427
                        Differ&& differ) const
428
12.6k
    {
429
12.6k
        auto old_offset       = old_node->data_count(bit);
430
12.6k
        auto const& old_value = old_node->values()[old_offset];
431
12.6k
        auto new_offset       = new_node->children_count(bit);
432
12.6k
        auto new_child        = new_node->children()[new_offset];
433
434
12.6k
        bool found = false;
435
12.6k
        for_each_chunk_traversal(
436
15.1k
            new_child, depth + 1, [&](auto const& begin, auto const& end) {
437
46.9k
                for (auto it = begin; it != end; it++) {
438
31.8k
                    if (Equal{}(old_value, *it)) {
439
11.9k
                        if (!EqualValue{}(old_value, *it))
440
167
                            differ.changed(old_value, *it);
441
11.9k
                        found = true;
442
19.9k
                    } else {
443
19.9k
                        differ.added(*it);
444
19.9k
                    }
445
31.8k
                }
446
15.1k
            });
447
12.6k
        if (!found)
448
760
            differ.removed(old_value);
449
12.6k
    }
450
451
    template <typename EqualValue, typename Differ>
452
    void diff_node_data(const node_t* old_node,
453
                        const node_t* const new_node,
454
                        bitmap_t bit,
455
                        count_t depth,
456
                        Differ&& differ) const
457
14.2k
    {
458
14.2k
        auto old_offset       = old_node->children_count(bit);
459
14.2k
        auto old_child        = old_node->children()[old_offset];
460
14.2k
        auto new_offset       = new_node->data_count(bit);
461
14.2k
        auto const& new_value = new_node->values()[new_offset];
462
463
14.2k
        bool found = false;
464
14.2k
        for_each_chunk_traversal(
465
17.9k
            old_child, depth + 1, [&](auto const& begin, auto const& end) {
466
55.1k
                for (auto it = begin; it != end; it++) {
467
37.1k
                    if (Equal{}(*it, new_value)) {
468
13.2k
                        if (!EqualValue{}(*it, new_value))
469
185
                            differ.changed(*it, new_value);
470
13.2k
                        found = true;
471
23.9k
                    } else {
472
23.9k
                        differ.removed(*it);
473
23.9k
                    }
474
37.1k
                }
475
17.9k
            });
476
14.2k
        if (!found)
477
969
            differ.added(new_value);
478
14.2k
    }
479
480
    template <typename EqualValue, typename Differ>
481
    void diff_data_data(const node_t* old_node,
482
                        const node_t* new_node,
483
                        bitmap_t bit,
484
                        Differ&& differ) const
485
357k
    {
486
357k
        auto old_offset       = old_node->data_count(bit);
487
357k
        auto new_offset       = new_node->data_count(bit);
488
357k
        auto const& old_value = old_node->values()[old_offset];
489
357k
        auto const& new_value = new_node->values()[new_offset];
490
357k
        if (!Equal{}(old_value, new_value)) {
491
1.50k
            differ.removed(old_value);
492
1.50k
            differ.added(new_value);
493
355k
        } else {
494
355k
            if (!EqualValue{}(old_value, new_value))
495
2.90k
                differ.changed(old_value, new_value);
496
355k
        }
497
357k
    }
498
499
    template <typename EqualValue, typename Differ>
500
    void diff_collisions(const node_t* old_node,
501
                         const node_t* new_node,
502
                         Differ&& differ) const
503
4.48k
    {
504
4.48k
        auto old_begin = old_node->collisions();
505
4.48k
        auto old_end   = old_node->collisions() + old_node->collision_count();
506
4.48k
        auto new_begin = new_node->collisions();
507
4.48k
        auto new_end   = new_node->collisions() + new_node->collision_count();
508
        // search changes and removals
509
15.7k
        for (auto old_it = old_begin; old_it != old_end; old_it++) {
510
11.2k
            bool found = false;
511
22.8k
            for (auto new_it = new_begin; new_it != new_end; new_it++) {
512
22.1k
                if (Equal{}(*old_it, *new_it)) {
513
10.6k
                    if (!EqualValue{}(*old_it, *new_it))
514
768
                        differ.changed(*old_it, *new_it);
515
10.6k
                    found = true;
516
10.6k
                    break;
517
10.6k
                }
518
22.1k
            }
519
11.2k
            if (!found)
520
657
                differ.removed(*old_it);
521
11.2k
        }
522
        // search new entries
523
15.7k
        for (auto new_it = new_begin; new_it != new_end; new_it++) {
524
11.2k
            bool found = false;
525
22.7k
            for (auto old_it = old_begin; old_it != old_end; old_it++) {
526
22.1k
                if (Equal{}(*old_it, *new_it)) {
527
10.6k
                    found = true;
528
10.6k
                    break;
529
10.6k
                }
530
22.1k
            }
531
11.2k
            if (!found)
532
668
                differ.added(*new_it);
533
11.2k
        }
534
4.48k
    }
535
536
    template <typename Project, typename Default, typename K>
537
    decltype(auto) get(const K& k) const
538
300k
    {
539
300k
        auto node = root;
540
300k
        auto hash = Hash{}(k);
541
1.43M
        for (auto i = count_t{}; i < max_depth<hash_t, B>; ++i) {
542
1.41M
            auto bit = bitmap_t{1u} << (hash & mask<hash_t, B>);
543
1.41M
            if (node->nodemap() & bit) {
544
1.13M
                auto offset = node->children_count(bit);
545
1.13M
                node        = node->children()[offset];
546
1.13M
                hash        = hash >> B;
547
1.13M
            } else if (node->datamap() & bit) {
548
187k
                auto offset = node->data_count(bit);
549
187k
                auto val    = node->values() + offset;
550
187k
                if (Equal{}(*val, k))
551
139k
                    return Project{}(*val);
552
47.8k
                else
553
47.8k
                    return Default{}();
554
187k
            } else {
555
100k
                return Default{}();
556
100k
            }
557
1.41M
        }
558
12.3k
        auto fst = node->collisions();
559
12.3k
        auto lst = fst + node->collision_count();
560
25.8k
        for (; fst != lst; ++fst)
561
24.2k
            if (Equal{}(*fst, k))
562
10.7k
                return Project{}(*fst);
563
1.59k
        return Default{}();
564
12.3k
    }
decltype(auto) immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::get<immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::project_value_ptr, immer::detail::constantly<int const*, (int const*)0>, unsigned long>(unsigned long const&) const
Line
Count
Source
538
1.98k
    {
539
1.98k
        auto node = root;
540
1.98k
        auto hash = Hash{}(k);
541
11.9k
        for (auto i = count_t{}; i < max_depth<hash_t, B>; ++i) {
542
11.4k
            auto bit = bitmap_t{1u} << (hash & mask<hash_t, B>);
543
11.4k
            if (node->nodemap() & bit) {
544
9.98k
                auto offset = node->children_count(bit);
545
9.98k
                node        = node->children()[offset];
546
9.98k
                hash        = hash >> B;
547
9.98k
            } else if (node->datamap() & bit) {
548
940
                auto offset = node->data_count(bit);
549
940
                auto val    = node->values() + offset;
550
940
                if (Equal{}(*val, k))
551
503
                    return Project{}(*val);
552
437
                else
553
437
                    return Default{}();
554
940
            } else {
555
553
                return Default{}();
556
553
            }
557
11.4k
        }
558
492
        auto fst = node->collisions();
559
492
        auto lst = fst + node->collision_count();
560
1.18k
        for (; fst != lst; ++fst)
561
949
            if (Equal{}(*fst, k))
562
257
                return Project{}(*fst);
563
235
        return Default{}();
564
492
    }
decltype(auto) immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::get<immer::detail::constantly<unsigned long, 1ul>, immer::detail::constantly<unsigned long, 0ul>, unsigned long>(unsigned long const&) const
Line
Count
Source
538
298k
    {
539
298k
        auto node = root;
540
298k
        auto hash = Hash{}(k);
541
1.41M
        for (auto i = count_t{}; i < max_depth<hash_t, B>; ++i) {
542
1.40M
            auto bit = bitmap_t{1u} << (hash & mask<hash_t, B>);
543
1.40M
            if (node->nodemap() & bit) {
544
1.12M
                auto offset = node->children_count(bit);
545
1.12M
                node        = node->children()[offset];
546
1.12M
                hash        = hash >> B;
547
1.12M
            } else if (node->datamap() & bit) {
548
186k
                auto offset = node->data_count(bit);
549
186k
                auto val    = node->values() + offset;
550
186k
                if (Equal{}(*val, k))
551
138k
                    return Project{}(*val);
552
47.4k
                else
553
47.4k
                    return Default{}();
554
186k
            } else {
555
100k
                return Default{}();
556
100k
            }
557
1.40M
        }
558
11.8k
        auto fst = node->collisions();
559
11.8k
        auto lst = fst + node->collision_count();
560
24.6k
        for (; fst != lst; ++fst)
561
23.2k
            if (Equal{}(*fst, k))
562
10.4k
                return Project{}(*fst);
563
1.36k
        return Default{}();
564
11.8k
    }
565
566
    struct add_result
567
    {
568
        node_t* node;
569
        bool added;
570
    };
571
572
    add_result do_add(node_t* node, T v, hash_t hash, shift_t shift) const
573
2.16M
    {
574
2.16M
        assert(node);
575
2.16M
        if (shift == max_shift<hash_t, B>) {
576
24.4k
            auto fst = node->collisions();
577
24.4k
            auto lst = fst + node->collision_count();
578
62.5k
            for (; fst != lst; ++fst)
579
60.8k
                if (Equal{}(*fst, v))
580
22.7k
                    return {
581
22.7k
                        node_t::copy_collision_replace(node, fst, std::move(v)),
582
22.7k
                        false};
583
1.66k
            return {node_t::copy_collision_insert(node, std::move(v)), true};
584
2.13M
        } else {
585
2.13M
            auto idx = (hash & (mask<hash_t, B> << shift)) >> shift;
586
2.13M
            auto bit = bitmap_t{1u} << idx;
587
2.13M
            if (node->nodemap() & bit) {
588
1.79M
                auto offset = node->children_count(bit);
589
1.79M
                assert(node->children()[offset]);
590
1.79M
                auto result = do_add(
591
1.79M
                    node->children()[offset], std::move(v), hash, shift + B);
592
1.79M
                IMMER_TRY {
593
1.79M
                    result.node =
594
1.79M
                        node_t::copy_inner_replace(node, offset, result.node);
595
1.79M
                    return result;
596
1.79M
                }
597
1.79M
                IMMER_CATCH (...) {
598
0
                    node_t::delete_deep_shift(result.node, shift + B);
599
0
                    IMMER_RETHROW;
600
0
                }
601
1.79M
            } else if (node->datamap() & bit) {
602
291k
                auto offset = node->data_count(bit);
603
291k
                auto val    = node->values() + offset;
604
291k
                if (Equal{}(*val, v))
605
261k
                    return {node_t::copy_inner_replace_value(
606
261k
                                node, offset, std::move(v)),
607
261k
                            false};
608
29.6k
                else {
609
29.6k
                    auto child = node_t::make_merged(
610
29.6k
                        shift + B, std::move(v), hash, *val, Hash{}(*val));
611
29.6k
                    IMMER_TRY {
612
29.6k
                        return {node_t::copy_inner_replace_merged(
613
29.6k
                                    node, bit, offset, child),
614
29.6k
                                true};
615
29.6k
                    }
616
29.6k
                    IMMER_CATCH (...) {
617
0
                        node_t::delete_deep_shift(child, shift + B);
618
0
                        IMMER_RETHROW;
619
0
                    }
620
29.6k
                }
621
291k
            } else {
622
53.0k
                return {
623
53.0k
                    node_t::copy_inner_insert_value(node, bit, std::move(v)),
624
53.0k
                    true};
625
53.0k
            }
626
2.13M
        }
627
2.16M
    }
628
629
    champ add(T v) const
630
367k
    {
631
367k
        auto hash     = Hash{}(v);
632
367k
        auto res      = do_add(root, std::move(v), hash, 0);
633
367k
        auto new_size = size + (res.added ? 1 : 0);
634
367k
        return {res.node, new_size};
635
367k
    }
636
637
    struct add_mut_result
638
    {
639
        node_t* node;
640
        bool added;
641
        bool mutated;
642
    };
643
644
    add_mut_result
645
    do_add_mut(edit_t e, node_t* node, T v, hash_t hash, shift_t shift) const
646
101k
    {
647
101k
        assert(node);
648
101k
        if (shift == max_shift<hash_t, B>) {
649
3.31k
            auto fst = node->collisions();
650
3.31k
            auto lst = fst + node->collision_count();
651
6.58k
            for (; fst != lst; ++fst)
652
6.00k
                if (Equal{}(*fst, v)) {
653
2.72k
                    if (node->can_mutate(e)) {
654
2.52k
                        *fst = std::move(v);
655
2.52k
                        return {node, false, true};
656
2.52k
                    } else {
657
207
                        auto r = node_t::copy_collision_replace(
658
207
                            node, fst, std::move(v));
659
207
                        return {node_t::owned(r, e), false, false};
660
207
                    }
661
2.72k
                }
662
583
            auto mutate = node->can_mutate(e);
663
583
            auto r = mutate ? node_t::move_collision_insert(node, std::move(v))
664
583
                            : node_t::copy_collision_insert(node, std::move(v));
665
583
            return {node_t::owned(r, e), true, mutate};
666
98.6k
        } else {
667
98.6k
            auto idx = (hash & (mask<hash_t, B> << shift)) >> shift;
668
98.6k
            auto bit = bitmap_t{1u} << idx;
669
98.6k
            if (node->nodemap() & bit) {
670
86.5k
                auto offset = node->children_count(bit);
671
86.5k
                auto child  = node->children()[offset];
672
86.5k
                if (node->can_mutate(e)) {
673
85.1k
                    auto result =
674
85.1k
                        do_add_mut(e, child, std::move(v), hash, shift + B);
675
85.1k
                    node->children()[offset] = result.node;
676
85.1k
                    if (!result.mutated && child->dec())
677
0
                        node_t::delete_deep_shift(child, shift + B);
678
85.1k
                    return {node, result.added, true};
679
85.1k
                } else {
680
1.46k
                    assert(node->children()[offset]);
681
1.46k
                    auto result = do_add(child, std::move(v), hash, shift + B);
682
1.46k
                    IMMER_TRY {
683
1.46k
                        result.node = node_t::copy_inner_replace(
684
1.46k
                            node, offset, result.node);
685
1.46k
                        node_t::owned(result.node, e);
686
1.46k
                        return {result.node, result.added, false};
687
1.46k
                    }
688
1.46k
                    IMMER_CATCH (...) {
689
0
                        node_t::delete_deep_shift(result.node, shift + B);
690
0
                        IMMER_RETHROW;
691
0
                    }
692
1.46k
                }
693
86.5k
            } else if (node->datamap() & bit) {
694
7.82k
                auto offset = node->data_count(bit);
695
7.82k
                auto val    = node->values() + offset;
696
7.82k
                if (Equal{}(*val, v)) {
697
3.89k
                    if (node->can_mutate(e)) {
698
3.54k
                        auto vals    = node->ensure_mutable_values(e);
699
3.54k
                        vals[offset] = std::move(v);
700
3.54k
                        return {node, false, true};
701
3.54k
                    } else {
702
348
                        auto r = node_t::copy_inner_replace_value(
703
348
                            node, offset, std::move(v));
704
348
                        return {node_t::owned_values(r, e), false, false};
705
348
                    }
706
3.92k
                } else {
707
3.92k
                    auto mutate        = node->can_mutate(e);
708
3.92k
                    auto mutate_values = mutate && node->can_mutate_values(e);
709
3.92k
                    auto hash2         = Hash{}(*val);
710
3.92k
                    auto child         = node_t::make_merged_e(
711
3.92k
                        e,
712
3.92k
                        shift + B,
713
3.92k
                        std::move(v),
714
3.92k
                        hash,
715
3.92k
                        mutate_values ? std::move(*val) : *val,
716
3.92k
                        hash2);
717
3.92k
                    IMMER_TRY {
718
3.92k
                        auto r = mutate ? node_t::move_inner_replace_merged(
719
3.52k
                                              e, node, bit, offset, child)
720
3.92k
                                        : node_t::copy_inner_replace_merged(
721
396
                                              node, bit, offset, child);
722
3.92k
                        return {node_t::owned_values_safe(r, e), true, mutate};
723
3.92k
                    }
724
3.92k
                    IMMER_CATCH (...) {
725
0
                        node_t::delete_deep_shift(child, shift + B);
726
0
                        IMMER_RETHROW;
727
0
                    }
728
3.92k
                }
729
7.82k
            } else {
730
4.25k
                auto mutate = node->can_mutate(e);
731
4.25k
                auto r      = mutate ? node_t::move_inner_insert_value(
732
3.18k
                                      e, node, bit, std::move(v))
733
4.25k
                                     : node_t::copy_inner_insert_value(
734
1.07k
                                      node, bit, std::move(v));
735
4.25k
                return {node_t::owned_values(r, e), true, mutate};
736
4.25k
            }
737
98.6k
        }
738
101k
    }
739
740
    void add_mut(edit_t e, T v)
741
16.8k
    {
742
16.8k
        auto hash = Hash{}(v);
743
16.8k
        auto res  = do_add_mut(e, root, std::move(v), hash, 0);
744
16.8k
        if (!res.mutated && root->dec())
745
0
            node_t::delete_deep(root, 0);
746
16.8k
        root = res.node;
747
16.8k
        size += res.added ? 1 : 0;
748
16.8k
    }
749
750
    using update_result = add_result;
751
752
    template <typename Project,
753
              typename Default,
754
              typename Combine,
755
              typename K,
756
              typename Fn>
757
    update_result
758
    do_update(node_t* node, K&& k, Fn&& fn, hash_t hash, shift_t shift) const
759
68.0k
    {
760
68.0k
        if (shift == max_shift<hash_t, B>) {
761
1.65k
            auto fst = node->collisions();
762
1.65k
            auto lst = fst + node->collision_count();
763
4.35k
            for (; fst != lst; ++fst)
764
3.69k
                if (Equal{}(*fst, k))
765
992
                    return {node_t::copy_collision_replace(
766
992
                                node,
767
992
                                fst,
768
992
                                Combine{}(std::forward<K>(k),
769
992
                                          std::forward<Fn>(fn)(Project{}(
770
992
                                              detail::as_const(*fst))))),
771
992
                            false};
772
658
            return {node_t::copy_collision_insert(
773
658
                        node,
774
658
                        Combine{}(std::forward<K>(k),
775
658
                                  std::forward<Fn>(fn)(Default{}()))),
776
658
                    true};
777
66.3k
        } else {
778
66.3k
            auto idx = (hash & (mask<hash_t, B> << shift)) >> shift;
779
66.3k
            auto bit = bitmap_t{1u} << idx;
780
66.3k
            if (node->nodemap() & bit) {
781
57.6k
                auto offset = node->children_count(bit);
782
57.6k
                auto result = do_update<Project, Default, Combine>(
783
57.6k
                    node->children()[offset],
784
57.6k
                    k,
785
57.6k
                    std::forward<Fn>(fn),
786
57.6k
                    hash,
787
57.6k
                    shift + B);
788
57.6k
                IMMER_TRY {
789
57.6k
                    result.node =
790
57.6k
                        node_t::copy_inner_replace(node, offset, result.node);
791
57.6k
                    return result;
792
57.6k
                }
793
57.6k
                IMMER_CATCH (...) {
794
0
                    node_t::delete_deep_shift(result.node, shift + B);
795
0
                    IMMER_RETHROW;
796
0
                }
797
57.6k
            } else if (node->datamap() & bit) {
798
6.64k
                auto offset = node->data_count(bit);
799
6.64k
                auto val    = node->values() + offset;
800
6.64k
                if (Equal{}(*val, k))
801
5.02k
                    return {node_t::copy_inner_replace_value(
802
5.02k
                                node,
803
5.02k
                                offset,
804
5.02k
                                Combine{}(std::forward<K>(k),
805
5.02k
                                          std::forward<Fn>(fn)(Project{}(
806
5.02k
                                              detail::as_const(*val))))),
807
5.02k
                            false};
808
1.62k
                else {
809
1.62k
                    auto child = node_t::make_merged(
810
1.62k
                        shift + B,
811
1.62k
                        Combine{}(std::forward<K>(k),
812
1.62k
                                  std::forward<Fn>(fn)(Default{}())),
813
1.62k
                        hash,
814
1.62k
                        *val,
815
1.62k
                        Hash{}(*val));
816
1.62k
                    IMMER_TRY {
817
1.62k
                        return {node_t::copy_inner_replace_merged(
818
1.62k
                                    node, bit, offset, child),
819
1.62k
                                true};
820
1.62k
                    }
821
1.62k
                    IMMER_CATCH (...) {
822
0
                        node_t::delete_deep_shift(child, shift + B);
823
0
                        IMMER_RETHROW;
824
0
                    }
825
1.62k
                }
826
6.64k
            } else {
827
2.08k
                return {node_t::copy_inner_insert_value(
828
2.08k
                            node,
829
2.08k
                            bit,
830
2.08k
                            Combine{}(std::forward<K>(k),
831
2.08k
                                      std::forward<Fn>(fn)(Default{}()))),
832
2.08k
                        true};
833
2.08k
            }
834
66.3k
        }
835
68.0k
    }
map-st.cpp:immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::add_result immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::do_update<immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::project_value, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::default_value, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::combine_value, unsigned long const&, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(int)#1}>(immer::detail::hamts::node<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>*, unsigned long const&, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(int)#1}&&, unsigned long, unsigned int) const
Line
Count
Source
759
51.1k
    {
760
51.1k
        if (shift == max_shift<hash_t, B>) {
761
766
            auto fst = node->collisions();
762
766
            auto lst = fst + node->collision_count();
763
2.46k
            for (; fst != lst; ++fst)
764
2.08k
                if (Equal{}(*fst, k))
765
379
                    return {node_t::copy_collision_replace(
766
379
                                node,
767
379
                                fst,
768
379
                                Combine{}(std::forward<K>(k),
769
379
                                          std::forward<Fn>(fn)(Project{}(
770
379
                                              detail::as_const(*fst))))),
771
379
                            false};
772
387
            return {node_t::copy_collision_insert(
773
387
                        node,
774
387
                        Combine{}(std::forward<K>(k),
775
387
                                  std::forward<Fn>(fn)(Default{}()))),
776
387
                    true};
777
50.3k
        } else {
778
50.3k
            auto idx = (hash & (mask<hash_t, B> << shift)) >> shift;
779
50.3k
            auto bit = bitmap_t{1u} << idx;
780
50.3k
            if (node->nodemap() & bit) {
781
44.2k
                auto offset = node->children_count(bit);
782
44.2k
                auto result = do_update<Project, Default, Combine>(
783
44.2k
                    node->children()[offset],
784
44.2k
                    k,
785
44.2k
                    std::forward<Fn>(fn),
786
44.2k
                    hash,
787
44.2k
                    shift + B);
788
44.2k
                IMMER_TRY {
789
44.2k
                    result.node =
790
44.2k
                        node_t::copy_inner_replace(node, offset, result.node);
791
44.2k
                    return result;
792
44.2k
                }
793
44.2k
                IMMER_CATCH (...) {
794
0
                    node_t::delete_deep_shift(result.node, shift + B);
795
0
                    IMMER_RETHROW;
796
0
                }
797
44.2k
            } else if (node->datamap() & bit) {
798
4.75k
                auto offset = node->data_count(bit);
799
4.75k
                auto val    = node->values() + offset;
800
4.75k
                if (Equal{}(*val, k))
801
3.84k
                    return {node_t::copy_inner_replace_value(
802
3.84k
                                node,
803
3.84k
                                offset,
804
3.84k
                                Combine{}(std::forward<K>(k),
805
3.84k
                                          std::forward<Fn>(fn)(Project{}(
806
3.84k
                                              detail::as_const(*val))))),
807
3.84k
                            false};
808
917
                else {
809
917
                    auto child = node_t::make_merged(
810
917
                        shift + B,
811
917
                        Combine{}(std::forward<K>(k),
812
917
                                  std::forward<Fn>(fn)(Default{}())),
813
917
                        hash,
814
917
                        *val,
815
917
                        Hash{}(*val));
816
917
                    IMMER_TRY {
817
917
                        return {node_t::copy_inner_replace_merged(
818
917
                                    node, bit, offset, child),
819
917
                                true};
820
917
                    }
821
917
                    IMMER_CATCH (...) {
822
0
                        node_t::delete_deep_shift(child, shift + B);
823
0
                        IMMER_RETHROW;
824
0
                    }
825
917
                }
826
4.75k
            } else {
827
1.35k
                return {node_t::copy_inner_insert_value(
828
1.35k
                            node,
829
1.35k
                            bit,
830
1.35k
                            Combine{}(std::forward<K>(k),
831
1.35k
                                      std::forward<Fn>(fn)(Default{}()))),
832
1.35k
                        true};
833
1.35k
            }
834
50.3k
        }
835
51.1k
    }
map-st.cpp:immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::add_result immer::detail::hamts::champ<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::do_update<immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::project_value, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::default_value, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::combine_value, unsigned long const&, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(int)#2}>(immer::detail::hamts::node<std::__1::pair<unsigned long, int>, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::hash_key, immer::map<unsigned long, int, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 5u>*, unsigned long const&, LLVMFuzzerTestOneInput::$_1::operator()<fuzzer_input>(fuzzer_input&) const::{lambda(int)#2}&&, unsigned long, unsigned int) const
Line
Count
Source
759
16.9k
    {
760
16.9k
        if (shift == max_shift<hash_t, B>) {
761
884
            auto fst = node->collisions();
762
884
            auto lst = fst + node->collision_count();
763
1.88k
            for (; fst != lst; ++fst)
764
1.61k
                if (Equal{}(*fst, k))
765
613
                    return {node_t::copy_collision_replace(
766
613
                                node,
767
613
                                fst,
768
613
                                Combine{}(std::forward<K>(k),
769
613
                                          std::forward<Fn>(fn)(Project{}(
770
613
                                              detail::as_const(*fst))))),
771
613
                            false};
772
271
            return {node_t::copy_collision_insert(
773
271
                        node,
774
271
                        Combine{}(std::forward<K>(k),
775
271
                                  std::forward<Fn>(fn)(Default{}()))),
776
271
                    true};
777
16.0k
        } else {
778
16.0k
            auto idx = (hash & (mask<hash_t, B> << shift)) >> shift;
779
16.0k
            auto bit = bitmap_t{1u} << idx;
780
16.0k
            if (node->nodemap() & bit) {
781
13.4k
                auto offset = node->children_count(bit);
782
13.4k
                auto result = do_update<Project, Default, Combine>(
783
13.4k
                    node->children()[offset],
784
13.4k
                    k,
785
13.4k
                    std::forward<Fn>(fn),
786
13.4k
                    hash,
787
13.4k
                    shift + B);
788
13.4k
                IMMER_TRY {
789
13.4k
                    result.node =
790
13.4k
                        node_t::copy_inner_replace(node, offset, result.node);
791
13.4k
                    return result;
792
13.4k
                }
793
13.4k
                IMMER_CATCH (...) {
794
0
                    node_t::delete_deep_shift(result.node, shift + B);
795
0
                    IMMER_RETHROW;
796
0
                }
797
13.4k
            } else if (node->datamap() & bit) {
798
1.88k
                auto offset = node->data_count(bit);
799
1.88k
                auto val    = node->values() + offset;
800
1.88k
                if (Equal{}(*val, k))
801
1.18k
                    return {node_t::copy_inner_replace_value(
802
1.18k
                                node,
803
1.18k
                                offset,
804
1.18k
                                Combine{}(std::forward<K>(k),
805
1.18k
                                          std::forward<Fn>(fn)(Project{}(
806
1.18k
                                              detail::as_const(*val))))),
807
1.18k
                            false};
808
706
                else {
809
706
                    auto child = node_t::make_merged(
810
706
                        shift + B,
811
706
                        Combine{}(std::forward<K>(k),
812
706
                                  std::forward<Fn>(fn)(Default{}())),
813
706
                        hash,
814
706
                        *val,
815
706
                        Hash{}(*val));
816
706
                    IMMER_TRY {
817
706
                        return {node_t::copy_inner_replace_merged(
818
706
                                    node, bit, offset, child),
819
706
                                true};
820
706
                    }
821
706
                    IMMER_CATCH (...) {
822
0
                        node_t::delete_deep_shift(child, shift + B);
823
0
                        IMMER_RETHROW;
824
0
                    }
825
706
                }
826
1.88k
            } else {
827
731
                return {node_t::copy_inner_insert_value(
828
731
                            node,
829
731
                            bit,
830
731
                            Combine{}(std::forward<K>(k),
831
731
                                      std::forward<Fn>(fn)(Default{}()))),
832
731
                        true};
833
731
            }
834
16.0k
        }
835
16.9k
    }
836
837
    template <typename Project,
838
              typename Default,
839
              typename Combine,
840
              typename K,
841
              typename Fn>
842
    champ update(const K& k, Fn&& fn) const
843
6.87k
    {
844
6.87k
        auto hash = Hash{}(k);
845
6.87k
        auto res  = do_update<Project, Default, Combine>(
846
6.87k
            root, k, std::forward<Fn>(fn), hash, 0);
847
6.87k
        auto new_size = size + (res.added ? 1 : 0);
848
6.87k
        return {res.node, new_size};
849
6.87k
    }
850
851
    template <typename Project, typename Combine, typename K, typename Fn>
852
    node_t* do_update_if_exists(
853
        node_t* node, K&& k, Fn&& fn, hash_t hash, shift_t shift) const
854
    {
855
        if (shift == max_shift<hash_t, B>) {
856
            auto fst = node->collisions();
857
            auto lst = fst + node->collision_count();
858
            for (; fst != lst; ++fst)
859
                if (Equal{}(*fst, k))
860
                    return node_t::copy_collision_replace(
861
                        node,
862
                        fst,
863
                        Combine{}(std::forward<K>(k),
864
                                  std::forward<Fn>(fn)(
865
                                      Project{}(detail::as_const(*fst)))));
866
            return nullptr;
867
        } else {
868
            auto idx = (hash & (mask<hash_t, B> << shift)) >> shift;
869
            auto bit = bitmap_t{1u} << idx;
870
            if (node->nodemap() & bit) {
871
                auto offset = node->children_count(bit);
872
                auto result = do_update_if_exists<Project, Combine>(
873
                    node->children()[offset],
874
                    k,
875
                    std::forward<Fn>(fn),
876
                    hash,
877
                    shift + B);
878
                IMMER_TRY {
879
                    return result ? node_t::copy_inner_replace(
880
                                        node, offset, result)
881
                                  : nullptr;
882
                }
883
                IMMER_CATCH (...) {
884
                    node_t::delete_deep_shift(result, shift + B);
885
                    IMMER_RETHROW;
886
                }
887
            } else if (node->datamap() & bit) {
888
                auto offset = node->data_count(bit);
889
                auto val    = node->values() + offset;
890
                if (Equal{}(*val, k))
891
                    return node_t::copy_inner_replace_value(
892
                        node,
893
                        offset,
894
                        Combine{}(std::forward<K>(k),
895
                                  std::forward<Fn>(fn)(
896
                                      Project{}(detail::as_const(*val)))));
897
                else {
898
                    return nullptr;
899
                }
900
            } else {
901
                return nullptr;
902
            }
903
        }
904
    }
905
906
    template <typename Project, typename Combine, typename K, typename Fn>
907
    champ update_if_exists(const K& k, Fn&& fn) const
908
    {
909
        auto hash = Hash{}(k);
910
        auto res  = do_update_if_exists<Project, Combine>(
911
            root, k, std::forward<Fn>(fn), hash, 0);
912
        if (res) {
913
            return {res, size};
914
        } else {
915
            return {root->inc(), size};
916
        };
917
    }
918
919
    using update_mut_result = add_mut_result;
920
921
    template <typename Project,
922
              typename Default,
923
              typename Combine,
924
              typename K,
925
              typename Fn>
926
    update_mut_result do_update_mut(edit_t e,
927
                                    node_t* node,
928
                                    K&& k,
929
                                    Fn&& fn,
930
                                    hash_t hash,
931
                                    shift_t shift) const
932
109k
    {
933
109k
        if (shift == max_shift<hash_t, B>) {
934
2.36k
            auto fst = node->collisions();
935
2.36k
            auto lst = fst + node->collision_count();
936
4.95k
            for (; fst != lst; ++fst)
937
4.38k
                if (Equal{}(*fst, k)) {
938
1.79k
                    if (node->can_mutate(e)) {
939
1.59k
                        *fst = Combine{}(
940
1.59k
                            std::forward<K>(k),
941
1.59k
                            std::forward<Fn>(fn)(Project{}(std::move(*fst))));
942
1.59k
                        return {node, false, true};
943
1.59k
                    } else {
944
201
                        auto r = node_t::copy_collision_replace(
945
201
                            node,
946
201
                            fst,
947
201
                            Combine{}(std::forward<K>(k),
948
201
                                      std::forward<Fn>(fn)(
949
201
                                          Project{}(detail::as_const(*fst)))));
950
201
                        return {node_t::owned(r, e), false, false};
951
201
                    }
952
1.79k
                }
953
570
            auto v      = Combine{}(std::forward<K>(k),
954
570
                               std::forward<Fn>(fn)(Default{}()));
955
570
            auto mutate = node->can_mutate(e);
956
570
            auto r = mutate ? node_t::move_collision_insert(node, std::move(v))
957
570
                            : node_t::copy_collision_insert(node, std::move(v));
958
570
            return {node_t::owned(r, e), true, mutate};
959
106k
        } else {
960
106k
            auto idx = (hash & (mask<hash_t, B> << shift)) >> shift;
961
106k
            auto bit = bitmap_t{1u} << idx;
962
106k
            if (node->nodemap() & bit) {
963
94.6k
                auto offset = node->children_count(bit);
964
94.6k
                auto child  = node->children()[offset];
965
94.6k
                if (node->can_mutate(e)) {
966
91.1k
                    auto result = do_update_mut<Project, Default, Combine>(
967
91.1k
                        e, child, k, std::forward<Fn>(fn), hash, shift + B);
968
91.1k
                    node->children()[offset] = result.node;
969
91.1k
                    if (!result.mutated && child->dec())
970
0
                        node_t::delete_deep_shift(child, shift + B);
971
91.1k
                    return {node, result.added, true};
972
91.1k
                } else {
973
3.50k
                    auto result = do_update<Project, Default, Combine>(
974
3.50k
                        child, k, std::forward<Fn>(fn), hash, shift + B);
975
3.50k
                    IMMER_TRY {
976
3.50k
                        result.node = node_t::copy_inner_replace(
977
3.50k
                            node, offset, result.node);
978
3.50k
                        node_t::owned(result.node, e);
979
3.50k
                        return {result.node, result.added, false};
980
3.50k
                    }
981
3.50k
                    IMMER_CATCH (...) {
982
0
                        node_t::delete_deep_shift(result.node, shift + B);
983
0
                        IMMER_RETHROW;
984
0
                    }
985
3.50k
                }
986
94.6k
            } else if (node->datamap() & bit) {
987
8.69k
                auto offset = node->data_count(bit);
988
8.69k
                auto val    = node->values() + offset;
989
8.69k
                if (Equal{}(*val, k)) {
990
5.44k
                    if (node->can_mutate(e)) {
991
5.04k
                        auto vals    = node->ensure_mutable_values(e);
992
5.04k
                        vals[offset] = Combine{}(std::forward<K>(k),
993
5.04k
                                                 std::forward<Fn>(fn)(Project{}(
994
5.04k
                                                     std::move(vals[offset]))));
995
5.04k
                        return {node, false, true};
996
5.04k
                    } else {
997
398
                        auto r = node_t::copy_inner_replace_value(
998
398
                            node,
999
398
                            offset,
1000
398
                            Combine{}(std::forward<K>(k),
1001
398
                                      std::forward<Fn>(fn)(
1002
398
                                          Project{}(detail::as_const(*val)))));
1003
398
                        return {node_t::owned_values(r, e), false, false};
1004
398
                    }
1005
5.44k
                } else {
1006
3.25k
                    auto mutate        = node->can_mutate(e);
1007
3.25k
                    auto mutate_values = mutate && node->can_mutate_values(e);
1008
3.25k
                    auto hash2         = Hash{}(*val);
1009
3.25k
                    auto child         = node_t::make_merged_e(
1010
3.25k
                        e,
1011
3.25k
                        shift + B,
1012
3.25k
                        Combine{}(std::forward<K>(k),
1013
3.25k
                                  std::forward<Fn>(fn)(Default{}())),
1014
3.25k
                        hash,
1015
3.25k
                        mutate_values ? std::move(*val) : *val,
1016
3.25k
                        hash2);
1017
3.25k
                    IMMER_TRY {
1018
3.25k
                        auto r = mutate ? node_t::move_inner_replace_merged(
1019
2.83k
                                              e, node, bit, offset, child)
1020
3.25k
                                        : node_t::copy_inner_replace_merged(
1021
412
                                              node, bit, offset, child);
1022
3.25k
                        return {node_t::owned_values_safe(r, e), true, mutate};
1023
3.25k
                    }
1024
3.25k
                    IMMER_CATCH (...) {
1025
0
                        node_t::delete_deep_shift(child, shift + B);
1026
0
                        IMMER_RETHROW;
1027
0
                    }
1028
3.25k
                }
1029
8.69k
            } else {
1030
3.47k
                auto mutate = node->can_mutate(e);
1031
3.47k
                auto v      = Combine{}(std::forward<K>(k),
1032
3.47k
                                   std::forward<Fn>(fn)(Default{}()));
1033
3.47k
                auto r      = mutate ? node_t::move_inner_insert_value(
1034
2.57k
                                      e, node, bit, std::move(v))
1035
3.47k
                                     : node_t::copy_inner_insert_value(
1036
903
                                      node, bit, std::move(v));
1037
3.47k
                return {node_t::owned_values(r, e), true, mutate};
1038
3.47k
            }
1039
106k
        }
1040
109k
    }
1041
1042
    template <typename Project,
1043
              typename Default,
1044
              typename Combine,
1045
              typename K,
1046
              typename Fn>
1047
    void update_mut(edit_t e, const K& k, Fn&& fn)
1048
18.0k
    {
1049
18.0k
        auto hash = Hash{}(k);
1050
18.0k
        auto res  = do_update_mut<Project, Default, Combine>(
1051
18.0k
            e, root, k, std::forward<Fn>(fn), hash, 0);
1052
18.0k
        if (!res.mutated && root->dec())
1053
0
            node_t::delete_deep(root, 0);
1054
18.0k
        root = res.node;
1055
18.0k
        size += res.added ? 1 : 0;
1056
18.0k
    }
1057
1058
    struct update_if_exists_mut_result
1059
    {
1060
        node_t* node;
1061
        bool mutated;
1062
    };
1063
1064
    template <typename Project, typename Combine, typename K, typename Fn>
1065
    update_if_exists_mut_result do_update_if_exists_mut(edit_t e,
1066
                                                        node_t* node,
1067
                                                        K&& k,
1068
                                                        Fn&& fn,
1069
                                                        hash_t hash,
1070
                                                        shift_t shift) const
1071
    {
1072
        if (shift == max_shift<hash_t, B>) {
1073
            auto fst = node->collisions();
1074
            auto lst = fst + node->collision_count();
1075
            for (; fst != lst; ++fst)
1076
                if (Equal{}(*fst, k)) {
1077
                    if (node->can_mutate(e)) {
1078
                        *fst = Combine{}(
1079
                            std::forward<K>(k),
1080
                            std::forward<Fn>(fn)(Project{}(std::move(*fst))));
1081
                        return {node, true};
1082
                    } else {
1083
                        auto r = node_t::copy_collision_replace(
1084
                            node,
1085
                            fst,
1086
                            Combine{}(std::forward<K>(k),
1087
                                      std::forward<Fn>(fn)(
1088
                                          Project{}(detail::as_const(*fst)))));
1089
                        return {node_t::owned(r, e), false};
1090
                    }
1091
                }
1092
            return {nullptr, false};
1093
        } else {
1094
            auto idx = (hash & (mask<hash_t, B> << shift)) >> shift;
1095
            auto bit = bitmap_t{1u} << idx;
1096
            if (node->nodemap() & bit) {
1097
                auto offset = node->children_count(bit);
1098
                auto child  = node->children()[offset];
1099
                if (node->can_mutate(e)) {
1100
                    auto result = do_update_if_exists_mut<Project, Combine>(
1101
                        e, child, k, std::forward<Fn>(fn), hash, shift + B);
1102
                    if (result.node) {
1103
                        node->children()[offset] = result.node;
1104
                        if (!result.mutated && child->dec())
1105
                            node_t::delete_deep_shift(child, shift + B);
1106
                        return {node, true};
1107
                    } else {
1108
                        return {nullptr, false};
1109
                    }
1110
                } else {
1111
                    auto result = do_update_if_exists<Project, Combine>(
1112
                        child, k, std::forward<Fn>(fn), hash, shift + B);
1113
                    IMMER_TRY {
1114
                        if (result) {
1115
                            result = node_t::copy_inner_replace(
1116
                                node, offset, result);
1117
                            node_t::owned(result, e);
1118
                            return {result, false};
1119
                        } else {
1120
                            return {nullptr, false};
1121
                        }
1122
                    }
1123
                    IMMER_CATCH (...) {
1124
                        node_t::delete_deep_shift(result, shift + B);
1125
                        IMMER_RETHROW;
1126
                    }
1127
                }
1128
            } else if (node->datamap() & bit) {
1129
                auto offset = node->data_count(bit);
1130
                auto val    = node->values() + offset;
1131
                if (Equal{}(*val, k)) {
1132
                    if (node->can_mutate(e)) {
1133
                        auto vals    = node->ensure_mutable_values(e);
1134
                        vals[offset] = Combine{}(std::forward<K>(k),
1135
                                                 std::forward<Fn>(fn)(Project{}(
1136
                                                     std::move(vals[offset]))));
1137
                        return {node, true};
1138
                    } else {
1139
                        auto r = node_t::copy_inner_replace_value(
1140
                            node,
1141
                            offset,
1142
                            Combine{}(std::forward<K>(k),
1143
                                      std::forward<Fn>(fn)(
1144
                                          Project{}(detail::as_const(*val)))));
1145
                        return {node_t::owned_values(r, e), false};
1146
                    }
1147
                } else {
1148
                    return {nullptr, false};
1149
                }
1150
            } else {
1151
                return {nullptr, false};
1152
            }
1153
        }
1154
    }
1155
1156
    template <typename Project, typename Combine, typename K, typename Fn>
1157
    void update_if_exists_mut(edit_t e, const K& k, Fn&& fn)
1158
    {
1159
        auto hash = Hash{}(k);
1160
        auto res  = do_update_if_exists_mut<Project, Combine>(
1161
            e, root, k, std::forward<Fn>(fn), hash, 0);
1162
        if (res.node) {
1163
            if (!res.mutated && root->dec())
1164
                node_t::delete_deep(root, 0);
1165
            root = res.node;
1166
        }
1167
    }
1168
1169
    // basically:
1170
    //      variant<monostate_t, T*, node_t*>
1171
    // boo bad we are not using... C++17 :'(
1172
    struct sub_result
1173
    {
1174
        enum kind_t
1175
        {
1176
            nothing,
1177
            singleton,
1178
            tree
1179
        };
1180
1181
        union data_t
1182
        {
1183
            T* singleton;
1184
            node_t* tree;
1185
        };
1186
1187
        kind_t kind;
1188
        data_t data;
1189
1190
        sub_result()
1191
32.2k
            : kind{nothing} {};
1192
        sub_result(T* x)
1193
2.56k
            : kind{singleton}
1194
2.56k
        {
1195
2.56k
            data.singleton = x;
1196
2.56k
        };
1197
        sub_result(node_t* x)
1198
21.6k
            : kind{tree}
1199
21.6k
        {
1200
21.6k
            data.tree = x;
1201
21.6k
        };
1202
    };
1203
1204
    template <typename K>
1205
    sub_result
1206
    do_sub(node_t* node, const K& k, hash_t hash, shift_t shift) const
1207
64.3k
    {
1208
64.3k
        if (shift == max_shift<hash_t, B>) {
1209
1.28k
            auto fst = node->collisions();
1210
1.28k
            auto lst = fst + node->collision_count();
1211
3.15k
            for (auto cur = fst; cur != lst; ++cur)
1212
2.81k
                if (Equal{}(*cur, k))
1213
943
                    return node->collision_count() > 2
1214
943
                               ? node_t::copy_collision_remove(node, cur)
1215
943
                               : sub_result{fst + (cur == fst)};
1216
339
#if !defined(_MSC_VER)
1217
#if defined(__GNUC__) && !defined(__clang__)
1218
#pragma GCC diagnostic push
1219
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
1220
#endif
1221
339
#endif
1222
            // Apparently GCC is generating this warning sometimes when
1223
            // compiling the benchmarks. It makes however no sense at all.
1224
339
            return {};
1225
1.28k
#if !defined(_MSC_VER)
1226
#if defined(__GNUC__) && !defined(__clang__)
1227
#pragma GCC diagnostic pop
1228
#endif
1229
1.28k
#endif
1230
63.0k
        } else {
1231
63.0k
            auto idx = (hash & (mask<hash_t, B> << shift)) >> shift;
1232
63.0k
            auto bit = bitmap_t{1u} << idx;
1233
63.0k
            if (node->nodemap() & bit) {
1234
51.5k
                auto offset = node->children_count(bit);
1235
51.5k
                auto result =
1236
51.5k
                    do_sub(node->children()[offset], k, hash, shift + B);
1237
51.5k
                switch (result.kind) {
1238
24.3k
                case sub_result::nothing:
1239
24.3k
                    return {};
1240
9.87k
                case sub_result::singleton:
1241
9.87k
                    return node->datamap() == 0 &&
1242
8.82k
                                   node->children_count() == 1 && shift > 0
1243
9.87k
                               ? result
1244
9.87k
                               : node_t::copy_inner_replace_inline(
1245
2.03k
                                     node, bit, offset, *result.data.singleton);
1246
17.2k
                case sub_result::tree:
1247
17.2k
                    IMMER_TRY {
1248
17.2k
                        return node_t::copy_inner_replace(
1249
17.2k
                            node, offset, result.data.tree);
1250
17.2k
                    }
1251
17.2k
                    IMMER_CATCH (...) {
1252
0
                        node_t::delete_deep_shift(result.data.tree, shift + B);
1253
0
                        IMMER_RETHROW;
1254
0
                    }
1255
51.5k
                }
1256
51.5k
            } else if (node->datamap() & bit) {
1257
7.71k
                auto offset = node->data_count(bit);
1258
7.71k
                auto val    = node->values() + offset;
1259
7.71k
                if (Equal{}(*val, k)) {
1260
3.98k
                    auto nv = node->data_count();
1261
3.98k
                    if (node->nodemap() || nv > 2)
1262
1.42k
                        return node_t::copy_inner_remove_value(
1263
1.42k
                            node, bit, offset);
1264
2.56k
                    else if (nv == 2) {
1265
2.36k
                        return shift > 0 ? sub_result{node->values() + !offset}
1266
2.36k
                                         : node_t::make_inner_n(
1267
216
                                               0,
1268
216
                                               node->datamap() & ~bit,
1269
216
                                               node->values()[!offset]);
1270
2.36k
                    } else {
1271
196
                        assert(shift == 0);
1272
196
                        return empty();
1273
196
                    }
1274
3.98k
                }
1275
7.71k
            }
1276
7.55k
            return {};
1277
63.0k
        }
1278
64.3k
    }
1279
1280
    template <typename K>
1281
    champ sub(const K& k) const
1282
9.55k
    {
1283
9.55k
        auto hash = Hash{}(k);
1284
9.55k
        auto res  = do_sub(root, k, hash, 0);
1285
9.55k
        switch (res.kind) {
1286
5.91k
        case sub_result::nothing:
1287
5.91k
            return *this;
1288
3.64k
        case sub_result::tree:
1289
3.64k
            return {res.data.tree, size - 1};
1290
0
        default:
1291
0
            IMMER_UNREACHABLE;
1292
9.55k
        }
1293
9.55k
    }
1294
1295
    struct sub_result_mut
1296
    {
1297
        using kind_t = typename sub_result::kind_t;
1298
        using data_t = typename sub_result::data_t;
1299
1300
        kind_t kind;
1301
        data_t data;
1302
        bool owned;
1303
        bool mutated;
1304
1305
        sub_result_mut(sub_result a)
1306
3.25k
            : kind{a.kind}
1307
3.25k
            , data{a.data}
1308
3.25k
            , owned{false}
1309
3.25k
            , mutated{false}
1310
3.25k
        {
1311
3.25k
        }
1312
        sub_result_mut(sub_result a, bool m)
1313
            : kind{a.kind}
1314
            , data{a.data}
1315
            , owned{false}
1316
            , mutated{m}
1317
        {
1318
        }
1319
        sub_result_mut()
1320
57.6k
            : kind{kind_t::nothing}
1321
57.6k
            , mutated{false} {};
1322
        sub_result_mut(T* x, bool m)
1323
4.06k
            : kind{kind_t::singleton}
1324
4.06k
            , owned{m}
1325
4.06k
            , mutated{m}
1326
4.06k
        {
1327
4.06k
            data.singleton = x;
1328
4.06k
        };
1329
        sub_result_mut(T* x, bool o, bool m)
1330
11.4k
            : kind{kind_t::singleton}
1331
11.4k
            , owned{o}
1332
11.4k
            , mutated{m}
1333
11.4k
        {
1334
11.4k
            data.singleton = x;
1335
11.4k
        };
1336
        sub_result_mut(node_t* x, bool m)
1337
42.5k
            : kind{kind_t::tree}
1338
42.5k
            , owned{false}
1339
42.5k
            , mutated{m}
1340
42.5k
        {
1341
42.5k
            data.tree = x;
1342
42.5k
        };
1343
    };
1344
1345
    template <typename K>
1346
    sub_result_mut do_sub_mut(edit_t e,
1347
                              node_t* node,
1348
                              const K& k,
1349
                              hash_t hash,
1350
                              shift_t shift,
1351
                              void* store) const
1352
115k
    {
1353
115k
        auto mutate = node->can_mutate(e);
1354
115k
        if (shift == max_shift<hash_t, B>) {
1355
2.62k
            auto fst = node->collisions();
1356
2.62k
            auto lst = fst + node->collision_count();
1357
6.21k
            for (auto cur = fst; cur != lst; ++cur) {
1358
5.54k
                if (Equal{}(*cur, k)) {
1359
1.95k
                    if (node->collision_count() <= 2) {
1360
1.15k
                        if (mutate) {
1361
958
                            auto r = new (store)
1362
958
                                T{std::move(node->collisions()[cur == fst])};
1363
958
                            node_t::delete_collision(node);
1364
958
                            return sub_result_mut{r, true};
1365
958
                        } else {
1366
199
                            return sub_result_mut{fst + (cur == fst), false};
1367
199
                        }
1368
1.15k
                    } else {
1369
796
                        auto r = mutate
1370
796
                                     ? node_t::move_collision_remove(node, cur)
1371
796
                                     : node_t::copy_collision_remove(node, cur);
1372
796
                        return {node_t::owned(r, e), mutate};
1373
796
                    }
1374
1.95k
                }
1375
5.54k
            }
1376
669
            return {};
1377
113k
        } else {
1378
113k
            auto idx = (hash & (mask<hash_t, B> << shift)) >> shift;
1379
113k
            auto bit = bitmap_t{1u} << idx;
1380
113k
            if (node->nodemap() & bit) {
1381
97.1k
                auto offset   = node->children_count(bit);
1382
97.1k
                auto children = node->children();
1383
97.1k
                auto child    = children[offset];
1384
97.1k
                auto result =
1385
97.1k
                    mutate ? do_sub_mut(e, child, k, hash, shift + B, store)
1386
97.1k
                           : do_sub(child, k, hash, shift + B);
1387
97.1k
                switch (result.kind) {
1388
48.0k
                case sub_result::nothing:
1389
48.0k
                    return {};
1390
16.0k
                case sub_result::singleton:
1391
16.0k
                    if (node->datamap() == 0 && node->children_count() == 1 &&
1392
12.2k
                        shift > 0) {
1393
11.4k
                        if (mutate) {
1394
11.1k
                            node_t::delete_inner(node);
1395
11.1k
                            if (!result.mutated && child->dec())
1396
0
                                node_t::delete_deep_shift(child, shift + B);
1397
11.1k
                        }
1398
11.4k
                        return {result.data.singleton, result.owned, mutate};
1399
11.4k
                    } else {
1400
4.60k
                        auto r =
1401
4.60k
                            mutate ? node_t::move_inner_replace_inline(
1402
4.33k
                                         e,
1403
4.33k
                                         node,
1404
4.33k
                                         bit,
1405
4.33k
                                         offset,
1406
4.33k
                                         result.owned
1407
4.33k
                                             ? std::move(*result.data.singleton)
1408
4.33k
                                             : *result.data.singleton)
1409
4.60k
                                   : node_t::copy_inner_replace_inline(
1410
268
                                         node,
1411
268
                                         bit,
1412
268
                                         offset,
1413
268
                                         *result.data.singleton);
1414
4.60k
                        if (result.owned)
1415
3.23k
                            detail::destroy_at(result.data.singleton);
1416
4.60k
                        if (!result.mutated && mutate && child->dec())
1417
0
                            node_t::delete_deep_shift(child, shift + B);
1418
4.60k
                        return {node_t::owned_values(r, e), mutate};
1419
4.60k
                    }
1420
33.0k
                case sub_result::tree:
1421
33.0k
                    if (mutate) {
1422
32.3k
                        children[offset] = result.data.tree;
1423
32.3k
                        if (!result.mutated && child->dec())
1424
0
                            node_t::delete_deep_shift(child, shift + B);
1425
32.3k
                        return {node, true};
1426
32.3k
                    } else {
1427
748
                        IMMER_TRY {
1428
748
                            auto r = node_t::copy_inner_replace(
1429
748
                                node, offset, result.data.tree);
1430
748
                            return {node_t::owned(r, e), false};
1431
748
                        }
1432
748
                        IMMER_CATCH (...) {
1433
0
                            node_t::delete_deep_shift(result.data.tree,
1434
0
                                                      shift + B);
1435
0
                            IMMER_RETHROW;
1436
0
                        }
1437
748
                    }
1438
97.1k
                }
1439
97.1k
            } else if (node->datamap() & bit) {
1440
11.7k
                auto offset        = node->data_count(bit);
1441
11.7k
                auto val           = node->values() + offset;
1442
11.7k
                auto mutate_values = mutate && node->can_mutate_values(e);
1443
11.7k
                if (Equal{}(*val, k)) {
1444
7.01k
                    auto nv = node->data_count();
1445
7.01k
                    if (node->nodemap() || nv > 2) {
1446
2.85k
                        auto r = mutate ? node_t::move_inner_remove_value(
1447
2.64k
                                              e, node, bit, offset)
1448
2.85k
                                        : node_t::copy_inner_remove_value(
1449
209
                                              node, bit, offset);
1450
2.85k
                        return {node_t::owned_values_safe(r, e), mutate};
1451
4.16k
                    } else if (nv == 2) {
1452
3.42k
                        if (shift > 0) {
1453
2.90k
                            if (mutate_values) {
1454
2.27k
                                auto r = new (store)
1455
2.27k
                                    T{std::move(node->values()[!offset])};
1456
2.27k
                                node_t::delete_inner(node);
1457
2.27k
                                return {r, true};
1458
2.27k
                            } else {
1459
633
                                return {node->values() + !offset, false};
1460
633
                            }
1461
2.90k
                        } else {
1462
512
                            auto& v = node->values()[!offset];
1463
512
                            auto r  = node_t::make_inner_n(
1464
512
                                0,
1465
512
                                node->datamap() & ~bit,
1466
512
                                mutate_values ? std::move(v) : v);
1467
512
                            assert(!node->nodemap());
1468
512
                            if (mutate)
1469
195
                                node_t::delete_inner(node);
1470
512
                            return {node_t::owned_values(r, e), mutate};
1471
512
                        }
1472
3.42k
                    } else {
1473
740
                        assert(shift == 0);
1474
740
                        if (mutate)
1475
543
                            node_t::delete_inner(node);
1476
740
                        return {empty(), mutate};
1477
740
                    }
1478
7.01k
                }
1479
11.7k
            }
1480
8.89k
            return {};
1481
113k
        }
1482
115k
    }
1483
1484
    template <typename K>
1485
    void sub_mut(edit_t e, const K& k)
1486
21.7k
    {
1487
21.7k
        auto store = aligned_storage_for<T>{};
1488
21.7k
        auto hash  = Hash{}(k);
1489
21.7k
        auto res   = do_sub_mut(e, root, k, hash, 0, &store);
1490
21.7k
        switch (res.kind) {
1491
11.5k
        case sub_result::nothing:
1492
11.5k
            break;
1493
10.2k
        case sub_result::tree:
1494
10.2k
            if (!res.mutated && root->dec())
1495
0
                node_t::delete_deep(root, 0);
1496
10.2k
            root = res.data.tree;
1497
10.2k
            --size;
1498
10.2k
            break;
1499
0
        default:
1500
0
            IMMER_UNREACHABLE;
1501
21.7k
        }
1502
21.7k
    }
1503
1504
    template <typename Eq = Equal>
1505
    bool equals(const champ& other) const
1506
    {
1507
        return size == other.size && equals_tree<Eq>(root, other.root, 0);
1508
    }
1509
1510
    template <typename Eq>
1511
    static bool equals_tree(const node_t* a, const node_t* b, count_t depth)
1512
    {
1513
        if (a == b)
1514
            return true;
1515
        else if (depth == max_depth<hash_t, B>) {
1516
            auto nv = a->collision_count();
1517
            return nv == b->collision_count() &&
1518
                   equals_collisions<Eq>(a->collisions(), b->collisions(), nv);
1519
        } else {
1520
            if (a->nodemap() != b->nodemap() || a->datamap() != b->datamap())
1521
                return false;
1522
            auto n = a->children_count();
1523
            for (auto i = count_t{}; i < n; ++i)
1524
                if (!equals_tree<Eq>(
1525
                        a->children()[i], b->children()[i], depth + 1))
1526
                    return false;
1527
            auto nv = a->data_count();
1528
            return !nv || equals_values<Eq>(a->values(), b->values(), nv);
1529
        }
1530
    }
1531
1532
    template <typename Eq>
1533
    static bool equals_values(const T* a, const T* b, count_t n)
1534
    {
1535
        return std::equal(a, a + n, b, Eq{});
1536
    }
1537
1538
    template <typename Eq>
1539
    static bool equals_collisions(const T* a, const T* b, count_t n)
1540
    {
1541
        auto ae = a + n;
1542
        auto be = b + n;
1543
        for (; a != ae; ++a) {
1544
            for (auto fst = b; fst != be; ++fst)
1545
                if (Eq{}(*a, *fst))
1546
                    goto good;
1547
            return false;
1548
        good:
1549
            continue;
1550
        }
1551
        return true;
1552
    }
1553
};
1554
1555
} // namespace hamts
1556
} // namespace detail
1557
} // namespace immer