Coverage Report

Created: 2025-08-03 07:06

/src/immer/immer/detail/hamts/node.hpp
Line
Count
Source (jump to first uncovered line)
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/combine_standard_layout.hpp>
13
#include <immer/detail/hamts/bits.hpp>
14
#include <immer/detail/util.hpp>
15
16
#include <cassert>
17
#include <cstddef>
18
19
namespace immer {
20
namespace detail {
21
namespace hamts {
22
23
// For C++14 support.
24
// Calling the destructor inline breaks MSVC in some obscure
25
// corner cases.
26
template <typename T>
27
constexpr void destroy_at(T* p)
28
0
{
29
0
    p->~T();
30
0
}
31
32
template <typename T,
33
          typename Hash,
34
          typename Equal,
35
          typename MemoryPolicy,
36
          bits_t B>
37
struct node
38
{
39
    using node_t = node;
40
41
    using memory      = MemoryPolicy;
42
    using heap_policy = typename memory::heap;
43
    using heap        = typename heap_policy::type;
44
    using transience  = typename memory::transience_t;
45
    using refs_t      = typename memory::refcount;
46
    using ownee_t     = typename transience::ownee;
47
    using edit_t      = typename transience::edit;
48
    using value_t     = T;
49
    using bitmap_t    = typename get_bitmap_type<B>::type;
50
    using hash_t      = decltype(Hash{}(std::declval<const T&>()));
51
52
    enum class kind_t
53
    {
54
        collision,
55
        inner
56
    };
57
58
    struct collision_t
59
    {
60
        count_t count;
61
        aligned_storage_for<T> buffer;
62
    };
63
64
    struct values_data_t
65
    {
66
        aligned_storage_for<T> buffer;
67
    };
68
69
    using values_t = combine_standard_layout_t<values_data_t, refs_t, ownee_t>;
70
71
    struct inner_t
72
    {
73
        bitmap_t nodemap;
74
        bitmap_t datamap;
75
        values_t* values;
76
        aligned_storage_for<node_t*> buffer;
77
    };
78
79
    union data_t
80
    {
81
        inner_t inner;
82
        collision_t collision;
83
    };
84
85
    struct impl_data_t
86
    {
87
#if IMMER_TAGGED_NODE
88
        kind_t kind;
89
#endif
90
        data_t data;
91
    };
92
93
    using impl_t = combine_standard_layout_t<impl_data_t, refs_t, ownee_t>;
94
95
    impl_t impl;
96
97
    constexpr static std::size_t sizeof_values_n(count_t count)
98
1.12M
    {
99
1.12M
        return std::max(sizeof(values_t),
100
1.12M
                        immer_offsetof(values_t, d.buffer) +
101
1.12M
                            sizeof(values_data_t::buffer) * count);
102
1.12M
    }
103
104
    constexpr static std::size_t sizeof_collision_n(count_t count)
105
0
    {
106
0
        return immer_offsetof(impl_t, d.data.collision.buffer) +
107
0
               sizeof(collision_t::buffer) * count;
108
0
    }
109
110
    constexpr static std::size_t sizeof_inner_n(count_t count)
111
6.30M
    {
112
6.30M
        return immer_offsetof(impl_t, d.data.inner.buffer) +
113
6.30M
               sizeof(inner_t::buffer) * count;
114
6.30M
    }
115
116
#if IMMER_TAGGED_NODE
117
60.7M
    kind_t kind() const { return impl.d.kind; }
118
#endif
119
120
    auto values()
121
8.36M
    {
122
8.36M
        IMMER_ASSERT_TAGGED(kind() == kind_t::inner);
123
8.36M
        assert(impl.d.data.inner.values);
124
8.36M
        return (T*) &impl.d.data.inner.values->d.buffer;
125
8.36M
    }
126
127
    auto values() const
128
783k
    {
129
783k
        IMMER_ASSERT_TAGGED(kind() == kind_t::inner);
130
783k
        assert(impl.d.data.inner.values);
131
783k
        return (const T*) &impl.d.data.inner.values->d.buffer;
132
783k
    }
133
134
    auto children()
135
10.0M
    {
136
10.0M
        IMMER_ASSERT_TAGGED(kind() == kind_t::inner);
137
10.0M
        return (node_t**) &impl.d.data.inner.buffer;
138
10.0M
    }
139
140
    auto children() const
141
363k
    {
142
363k
        IMMER_ASSERT_TAGGED(kind() == kind_t::inner);
143
363k
        return (const node_t* const*) &impl.d.data.inner.buffer;
144
363k
    }
145
146
    auto datamap() const
147
11.5M
    {
148
11.5M
        IMMER_ASSERT_TAGGED(kind() == kind_t::inner);
149
11.5M
        return impl.d.data.inner.datamap;
150
11.5M
    }
151
152
    auto nodemap() const
153
16.6M
    {
154
16.6M
        IMMER_ASSERT_TAGGED(kind() == kind_t::inner);
155
16.6M
        return impl.d.data.inner.nodemap;
156
16.6M
    }
157
158
    auto data_count() const
159
1.72M
    {
160
1.72M
        IMMER_ASSERT_TAGGED(kind() == kind_t::inner);
161
1.72M
        return popcount(datamap());
162
1.72M
    }
163
164
    auto data_count(bitmap_t bit) const
165
1.47M
    {
166
1.47M
        IMMER_ASSERT_TAGGED(kind() == kind_t::inner);
167
1.47M
        return popcount(static_cast<bitmap_t>(datamap() & (bit - 1)));
168
1.47M
    }
169
170
    auto children_count() const
171
4.81M
    {
172
4.81M
        IMMER_ASSERT_TAGGED(kind() == kind_t::inner);
173
4.81M
        return popcount(nodemap());
174
4.81M
    }
175
176
    auto children_count(bitmap_t bit) const
177
1.91M
    {
178
1.91M
        IMMER_ASSERT_TAGGED(kind() == kind_t::inner);
179
1.91M
        return popcount(static_cast<bitmap_t>(nodemap() & (bit - 1)));
180
1.91M
    }
181
182
    auto collision_count() const
183
0
    {
184
0
        IMMER_ASSERT_TAGGED(kind() == kind_t::collision);
185
0
        return impl.d.data.collision.count;
186
0
    }
187
188
    T* collisions()
189
0
    {
190
0
        IMMER_ASSERT_TAGGED(kind() == kind_t::collision);
191
0
        return (T*) &impl.d.data.collision.buffer;
192
0
    }
193
194
    const T* collisions() const
195
0
    {
196
0
        IMMER_ASSERT_TAGGED(kind() == kind_t::collision);
197
0
        return (const T*) &impl.d.data.collision.buffer;
198
0
    }
199
200
    static refs_t& refs(const values_t* x)
201
1.11M
    {
202
1.11M
        return auto_const_cast(get<refs_t>(*x));
203
1.11M
    }
204
    static const ownee_t& ownee(const values_t* x) { return get<ownee_t>(*x); }
205
47.4k
    static ownee_t& ownee(values_t* x) { return get<ownee_t>(*x); }
206
    static bool can_mutate(values_t* x, edit_t e)
207
42.7k
    {
208
42.7k
        return refs(x).unique() || ownee(x).can_mutate(e);
209
42.7k
    }
210
211
    static refs_t& refs(const node_t* x)
212
27.5M
    {
213
27.5M
        return auto_const_cast(get<refs_t>(x->impl));
214
27.5M
    }
215
    static const ownee_t& ownee(const node_t* x)
216
21.2k
    {
217
21.2k
        return get<ownee_t>(x->impl);
218
21.2k
    }
219
50.0k
    static ownee_t& ownee(node_t* x) { return get<ownee_t>(x->impl); }
220
221
    bool can_mutate(edit_t e) const
222
150k
    {
223
150k
        return refs(this).unique() || ownee(this).can_mutate(e);
224
150k
    }
225
    bool can_mutate_values(edit_t e) const
226
14.2k
    {
227
14.2k
        return can_mutate(impl.d.data.inner.values, e);
228
14.2k
    }
229
230
    static node_t* make_inner_n_into(void* buffer, std::size_t size, count_t n)
231
1.57M
    {
232
1.57M
        assert(n <= branches<B>);
233
1.57M
        assert(size >= sizeof_inner_n(n));
234
1.57M
        auto p = new (buffer) node_t;
235
1.57M
#if IMMER_TAGGED_NODE
236
1.57M
        p->impl.d.kind = node_t::kind_t::inner;
237
1.57M
#endif
238
1.57M
        p->impl.d.data.inner.nodemap = 0;
239
1.57M
        p->impl.d.data.inner.datamap = 0;
240
1.57M
        p->impl.d.data.inner.values  = nullptr;
241
1.57M
        return p;
242
1.57M
    }
243
244
    static node_t* make_inner_n(count_t n)
245
1.57M
    {
246
1.57M
        assert(n <= branches<B>);
247
1.57M
        auto m = heap::allocate(sizeof_inner_n(n));
248
1.57M
        return make_inner_n_into(m, sizeof_inner_n(n), n);
249
1.57M
    }
250
251
    static node_t* make_inner_n(count_t n, values_t* values)
252
998k
    {
253
998k
        auto p = make_inner_n(n);
254
998k
        if (values) {
255
254k
            p->impl.d.data.inner.values = values;
256
254k
            refs(values).inc();
257
254k
        }
258
998k
        return p;
259
998k
    }
260
261
    static node_t* make_inner_n(count_t n, count_t nv)
262
571k
    {
263
571k
        assert(nv <= branches<B>);
264
571k
        auto p = make_inner_n(n);
265
571k
        if (nv) {
266
562k
            IMMER_TRY {
267
562k
                p->impl.d.data.inner.values =
268
562k
                    new (heap::allocate(sizeof_values_n(nv))) values_t{};
269
562k
            }
270
562k
            IMMER_CATCH (...) {
271
0
                deallocate_inner(p, n);
272
0
                IMMER_RETHROW;
273
0
            }
274
562k
        }
275
571k
        return p;
276
571k
    }
277
278
    static node_t* make_inner_n(count_t n, count_t idx, node_t* child)
279
6.66k
    {
280
6.66k
        assert(n >= 1);
281
6.66k
        auto p                       = make_inner_n(n);
282
6.66k
        p->impl.d.data.inner.nodemap = bitmap_t{1u} << idx;
283
6.66k
        p->children()[0]             = child;
284
6.66k
        return p;
285
6.66k
    }
286
287
    static node_t* make_inner_n(count_t n, bitmap_t bitmap, T x)
288
711
    {
289
711
        auto p                       = make_inner_n(n, 1);
290
711
        p->impl.d.data.inner.datamap = bitmap;
291
711
        IMMER_TRY {
292
711
            new (p->values()) T{std::move(x)};
293
711
        }
294
711
        IMMER_CATCH (...) {
295
0
            deallocate_inner(p, n, 1);
296
0
            IMMER_RETHROW;
297
0
        }
298
0
        return p;
299
711
    }
300
301
    static node_t*
302
    make_inner_n(count_t n, count_t idx1, T x1, count_t idx2, T x2)
303
30.6k
    {
304
30.6k
        assert(idx1 != idx2);
305
30.6k
        auto p = make_inner_n(n, 2);
306
30.6k
        p->impl.d.data.inner.datamap =
307
30.6k
            (bitmap_t{1u} << idx1) | (bitmap_t{1u} << idx2);
308
30.6k
        auto assign = [&](auto&& x1, auto&& x2) {
309
30.6k
            auto vp = p->values();
310
30.6k
            IMMER_TRY {
311
30.6k
                new (vp) T{std::move(x1)};
312
30.6k
                IMMER_TRY {
313
30.6k
                    new (vp + 1) T{std::move(x2)};
314
30.6k
                }
315
30.6k
                IMMER_CATCH (...) {
316
0
                    immer::detail::hamts::destroy_at(vp);
317
0
                    IMMER_RETHROW;
318
0
                }
319
30.6k
            }
320
30.6k
            IMMER_CATCH (...) {
321
0
                deallocate_inner(p, n, 2);
322
0
                IMMER_RETHROW;
323
0
            }
324
30.6k
        };
325
30.6k
        if (idx1 < idx2)
326
13.7k
            assign(x1, x2);
327
16.9k
        else
328
16.9k
            assign(x2, x1);
329
30.6k
        return p;
330
30.6k
    }
331
332
    static node_t* make_collision_n(count_t n)
333
0
    {
334
0
        auto m = heap::allocate(sizeof_collision_n(n));
335
0
        auto p = new (m) node_t;
336
0
#if IMMER_TAGGED_NODE
337
0
        p->impl.d.kind = node_t::kind_t::collision;
338
0
#endif
339
0
        p->impl.d.data.collision.count = n;
340
0
        return p;
341
0
    }
342
343
    static node_t* make_collision(T v1, T v2)
344
0
    {
345
0
        auto m = heap::allocate(sizeof_collision_n(2));
346
0
        auto p = new (m) node_t;
347
0
#if IMMER_TAGGED_NODE
348
0
        p->impl.d.kind = node_t::kind_t::collision;
349
0
#endif
350
0
        p->impl.d.data.collision.count = 2;
351
0
        auto cols                      = p->collisions();
352
0
        IMMER_TRY {
353
0
            new (cols) T{std::move(v1)};
354
0
            IMMER_TRY {
355
0
                new (cols + 1) T{std::move(v2)};
356
0
            }
357
0
            IMMER_CATCH (...) {
358
0
                cols->~T();
359
0
                IMMER_RETHROW;
360
0
            }
361
0
        }
362
0
        IMMER_CATCH (...) {
363
0
            deallocate_collision(p, 2);
364
0
            IMMER_RETHROW;
365
0
        }
366
0
        return p;
367
0
    }
368
369
    T* ensure_mutable_values(edit_t e)
370
6.39k
    {
371
6.39k
        assert(can_mutate(e));
372
6.39k
        auto old = impl.d.data.inner.values;
373
6.39k
        if (node_t::can_mutate(old, e))
374
5.59k
            return values();
375
802
        else {
376
802
            auto nv    = data_count();
377
802
            auto nxt   = new (heap::allocate(sizeof_values_n(nv))) values_t{};
378
802
            auto dst   = (T*) &nxt->d.buffer;
379
802
            auto src   = values();
380
802
            ownee(nxt) = e;
381
802
            IMMER_TRY {
382
802
                detail::uninitialized_copy(src, src + nv, dst);
383
802
            }
384
802
            IMMER_CATCH (...) {
385
0
                deallocate_values(nxt, nv);
386
0
                IMMER_RETHROW;
387
0
            }
388
802
            impl.d.data.inner.values = nxt;
389
802
            if (refs(old).dec())
390
0
                delete_values(old, nv);
391
802
            return dst;
392
802
        }
393
6.39k
    }
394
395
    static node_t* copy_collision_insert(node_t* src, T v)
396
0
    {
397
0
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::collision);
398
0
        auto n    = src->collision_count();
399
0
        auto dst  = make_collision_n(n + 1);
400
0
        auto srcp = src->collisions();
401
0
        auto dstp = dst->collisions();
402
0
        IMMER_TRY {
403
0
            new (dstp) T{std::move(v)};
404
0
            IMMER_TRY {
405
0
                detail::uninitialized_copy(srcp, srcp + n, dstp + 1);
406
0
            }
407
0
            IMMER_CATCH (...) {
408
0
                dstp->~T();
409
0
                IMMER_RETHROW;
410
0
            }
411
0
        }
412
0
        IMMER_CATCH (...) {
413
0
            deallocate_collision(dst, n + 1);
414
0
            IMMER_RETHROW;
415
0
        }
416
0
        return dst;
417
0
    }
418
419
    static node_t* move_collision_insert(node_t* src, T v)
420
0
    {
421
0
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::collision);
422
0
        auto n    = src->collision_count();
423
0
        auto dst  = make_collision_n(n + 1);
424
0
        auto srcp = src->collisions();
425
0
        auto dstp = dst->collisions();
426
0
        IMMER_TRY {
427
0
            new (dstp) T{std::move(v)};
428
0
            IMMER_TRY {
429
0
                detail::uninitialized_move(srcp, srcp + n, dstp + 1);
430
0
            }
431
0
            IMMER_CATCH (...) {
432
0
                dstp->~T();
433
0
                IMMER_RETHROW;
434
0
            }
435
0
        }
436
0
        IMMER_CATCH (...) {
437
0
            deallocate_collision(dst, n + 1);
438
0
            IMMER_RETHROW;
439
0
        }
440
0
        delete_collision(src);
441
0
        return dst;
442
0
    }
443
444
    static node_t* copy_collision_remove(node_t* src, T* v)
445
0
    {
446
0
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::collision);
447
0
        assert(src->collision_count() > 1);
448
0
        auto n    = src->collision_count();
449
0
        auto dst  = make_collision_n(n - 1);
450
0
        auto srcp = src->collisions();
451
0
        auto dstp = dst->collisions();
452
0
        IMMER_TRY {
453
0
            dstp = detail::uninitialized_copy(srcp, v, dstp);
454
0
            IMMER_TRY {
455
0
                detail::uninitialized_copy(v + 1, srcp + n, dstp);
456
0
            }
457
0
            IMMER_CATCH (...) {
458
0
                detail::destroy(dst->collisions(), dstp);
459
0
                IMMER_RETHROW;
460
0
            }
461
0
        }
462
0
        IMMER_CATCH (...) {
463
0
            deallocate_collision(dst, n - 1);
464
0
            IMMER_RETHROW;
465
0
        }
466
0
        return dst;
467
0
    }
468
469
    static node_t* move_collision_remove(node_t* src, T* v)
470
0
    {
471
0
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::collision);
472
0
        assert(src->collision_count() > 1);
473
0
        auto n    = src->collision_count();
474
0
        auto dst  = make_collision_n(n - 1);
475
0
        auto srcp = src->collisions();
476
0
        auto dstp = dst->collisions();
477
0
        IMMER_TRY {
478
0
            dstp = detail::uninitialized_move(srcp, v, dstp);
479
0
            IMMER_TRY {
480
0
                detail::uninitialized_move(v + 1, srcp + n, dstp);
481
0
            }
482
0
            IMMER_CATCH (...) {
483
0
                detail::destroy(dst->collisions(), dstp);
484
0
                IMMER_RETHROW;
485
0
            }
486
0
        }
487
0
        IMMER_CATCH (...) {
488
0
            deallocate_collision(dst, n - 1);
489
0
            IMMER_RETHROW;
490
0
        }
491
0
        delete_collision(src);
492
0
        return dst;
493
0
    }
494
495
    static node_t* copy_collision_replace(node_t* src, T* pos, T v)
496
0
    {
497
0
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::collision);
498
0
        auto n    = src->collision_count();
499
0
        auto dst  = make_collision_n(n);
500
0
        auto srcp = src->collisions();
501
0
        auto dstp = dst->collisions();
502
0
        assert(pos >= srcp && pos < srcp + n);
503
0
        IMMER_TRY {
504
0
            new (dstp) T{std::move(v)};
505
0
            IMMER_TRY {
506
0
                dstp = detail::uninitialized_copy(srcp, pos, dstp + 1);
507
0
                IMMER_TRY {
508
0
                    detail::uninitialized_copy(pos + 1, srcp + n, dstp);
509
0
                }
510
0
                IMMER_CATCH (...) {
511
0
                    detail::destroy(dst->collisions(), dstp);
512
0
                    IMMER_RETHROW;
513
0
                }
514
0
            }
515
0
            IMMER_CATCH (...) {
516
0
                dst->collisions()->~T();
517
0
                IMMER_RETHROW;
518
0
            }
519
0
        }
520
0
        IMMER_CATCH (...) {
521
0
            deallocate_collision(dst, n);
522
0
            IMMER_RETHROW;
523
0
        }
524
0
        return dst;
525
0
    }
526
527
    static node_t*
528
    copy_inner_replace(node_t* src, count_t offset, node_t* child)
529
998k
    {
530
998k
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
531
998k
        auto n    = src->children_count();
532
998k
        auto dst  = make_inner_n(n, src->impl.d.data.inner.values);
533
998k
        auto srcp = src->children();
534
998k
        auto dstp = dst->children();
535
998k
        dst->impl.d.data.inner.datamap = src->datamap();
536
998k
        dst->impl.d.data.inner.nodemap = src->nodemap();
537
998k
        std::copy(srcp, srcp + n, dstp);
538
998k
        inc_nodes(srcp, offset);
539
998k
        inc_nodes(srcp + offset + 1, n - offset - 1);
540
998k
        dstp[offset] = child;
541
998k
        return dst;
542
998k
    }
543
544
    static node_t* owned(node_t* n, edit_t e)
545
4.26k
    {
546
4.26k
        ownee(n) = e;
547
4.26k
        return n;
548
4.26k
    }
549
550
    static node_t* owned_values(node_t* n, edit_t e)
551
35.3k
    {
552
35.3k
        ownee(n)                           = e;
553
35.3k
        ownee(n->impl.d.data.inner.values) = e;
554
35.3k
        return n;
555
35.3k
    }
556
557
    static node_t* owned_values_safe(node_t* n, edit_t e)
558
10.4k
    {
559
10.4k
        ownee(n) = e;
560
10.4k
        if (n->impl.d.data.inner.values)
561
8.01k
            ownee(n->impl.d.data.inner.values) = e;
562
10.4k
        return n;
563
10.4k
    }
564
565
    static node_t* copy_inner_replace_value(node_t* src, count_t offset, T v)
566
437k
    {
567
437k
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
568
437k
        assert(offset < src->data_count());
569
437k
        auto n                         = src->children_count();
570
437k
        auto nv                        = src->data_count();
571
437k
        auto dst                       = make_inner_n(n, nv);
572
437k
        dst->impl.d.data.inner.datamap = src->datamap();
573
437k
        dst->impl.d.data.inner.nodemap = src->nodemap();
574
437k
        IMMER_TRY {
575
437k
            detail::uninitialized_copy(
576
437k
                src->values(), src->values() + nv, dst->values());
577
437k
            IMMER_TRY {
578
437k
                dst->values()[offset] = std::move(v);
579
437k
            }
580
437k
            IMMER_CATCH (...) {
581
0
                detail::destroy_n(dst->values(), nv);
582
0
                IMMER_RETHROW;
583
0
            }
584
437k
        }
585
437k
        IMMER_CATCH (...) {
586
0
            deallocate_inner(dst, n, nv);
587
0
            IMMER_RETHROW;
588
0
        }
589
437k
        inc_nodes(src->children(), n);
590
437k
        std::copy(src->children(), src->children() + n, dst->children());
591
437k
        return dst;
592
437k
    }
593
594
    static node_t* copy_inner_replace_merged(node_t* src,
595
                                             bitmap_t bit,
596
                                             count_t voffset,
597
                                             node_t* node)
598
23.2k
    {
599
23.2k
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
600
23.2k
        assert(!(src->nodemap() & bit));
601
23.2k
        assert(src->datamap() & bit);
602
23.2k
        assert(voffset == src->data_count(bit));
603
23.2k
        auto n                         = src->children_count();
604
23.2k
        auto nv                        = src->data_count();
605
23.2k
        auto dst                       = make_inner_n(n + 1, nv - 1);
606
23.2k
        auto noffset                   = src->children_count(bit);
607
23.2k
        dst->impl.d.data.inner.datamap = src->datamap() & ~bit;
608
23.2k
        dst->impl.d.data.inner.nodemap = src->nodemap() | bit;
609
23.2k
        if (nv > 1) {
610
17.6k
            IMMER_TRY {
611
17.6k
                detail::uninitialized_copy(
612
17.6k
                    src->values(), src->values() + voffset, dst->values());
613
17.6k
                IMMER_TRY {
614
17.6k
                    detail::uninitialized_copy(src->values() + voffset + 1,
615
17.6k
                                               src->values() + nv,
616
17.6k
                                               dst->values() + voffset);
617
17.6k
                }
618
17.6k
                IMMER_CATCH (...) {
619
0
                    detail::destroy_n(dst->values(), voffset);
620
0
                    IMMER_RETHROW;
621
0
                }
622
17.6k
            }
623
17.6k
            IMMER_CATCH (...) {
624
0
                deallocate_inner(dst, n + 1, nv - 1);
625
0
                IMMER_RETHROW;
626
0
            }
627
17.6k
        }
628
23.2k
        inc_nodes(src->children(), n);
629
23.2k
        std::copy(src->children(), src->children() + noffset, dst->children());
630
23.2k
        std::copy(src->children() + noffset,
631
23.2k
                  src->children() + n,
632
23.2k
                  dst->children() + noffset + 1);
633
23.2k
        dst->children()[noffset] = node;
634
23.2k
        return dst;
635
23.2k
    }
636
637
    static node_t* move_inner_replace_merged(
638
        edit_t e, node_t* src, bitmap_t bit, count_t voffset, node_t* node)
639
7.48k
    {
640
7.48k
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
641
7.48k
        assert(!(src->nodemap() & bit));
642
7.48k
        assert(src->datamap() & bit);
643
7.48k
        assert(voffset == src->data_count(bit));
644
7.48k
        auto n                         = src->children_count();
645
7.48k
        auto nv                        = src->data_count();
646
7.48k
        auto dst                       = make_inner_n(n + 1, nv - 1);
647
7.48k
        auto noffset                   = src->children_count(bit);
648
7.48k
        dst->impl.d.data.inner.datamap = src->datamap() & ~bit;
649
7.48k
        dst->impl.d.data.inner.nodemap = src->nodemap() | bit;
650
7.48k
        if (nv > 1) {
651
5.49k
            auto mutate_values = can_mutate(src->impl.d.data.inner.values, e);
652
5.49k
            IMMER_TRY {
653
5.49k
                if (mutate_values)
654
5.03k
                    detail::uninitialized_move(
655
5.03k
                        src->values(), src->values() + voffset, dst->values());
656
466
                else
657
466
                    detail::uninitialized_copy(
658
466
                        src->values(), src->values() + voffset, dst->values());
659
5.49k
                IMMER_TRY {
660
5.49k
                    if (mutate_values)
661
5.03k
                        detail::uninitialized_move(src->values() + voffset + 1,
662
5.03k
                                                   src->values() + nv,
663
5.03k
                                                   dst->values() + voffset);
664
466
                    else
665
466
                        detail::uninitialized_copy(src->values() + voffset + 1,
666
466
                                                   src->values() + nv,
667
466
                                                   dst->values() + voffset);
668
5.49k
                }
669
5.49k
                IMMER_CATCH (...) {
670
0
                    detail::destroy_n(dst->values(), voffset);
671
0
                    IMMER_RETHROW;
672
0
                }
673
5.49k
            }
674
5.49k
            IMMER_CATCH (...) {
675
0
                deallocate_inner(dst, n + 1, nv - 1);
676
0
                IMMER_RETHROW;
677
0
            }
678
5.49k
        }
679
        // inc_nodes(src->children(), n);
680
7.48k
        std::copy(src->children(), src->children() + noffset, dst->children());
681
7.48k
        std::copy(src->children() + noffset,
682
7.48k
                  src->children() + n,
683
7.48k
                  dst->children() + noffset + 1);
684
7.48k
        dst->children()[noffset] = node;
685
7.48k
        delete_inner(src);
686
7.48k
        return dst;
687
7.48k
    }
688
689
    static node_t* copy_inner_replace_inline(node_t* src,
690
                                             bitmap_t bit,
691
                                             count_t noffset,
692
                                             T value)
693
1.66k
    {
694
1.66k
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
695
1.66k
        assert(!(src->datamap() & bit));
696
1.66k
        assert(src->nodemap() & bit);
697
1.66k
        assert(noffset == src->children_count(bit));
698
1.66k
        auto n                         = src->children_count();
699
1.66k
        auto nv                        = src->data_count();
700
1.66k
        auto dst                       = make_inner_n(n - 1, nv + 1);
701
1.66k
        auto voffset                   = src->data_count(bit);
702
1.66k
        dst->impl.d.data.inner.nodemap = src->nodemap() & ~bit;
703
1.66k
        dst->impl.d.data.inner.datamap = src->datamap() | bit;
704
1.66k
        IMMER_TRY {
705
1.66k
            if (nv)
706
793
                detail::uninitialized_copy(
707
793
                    src->values(), src->values() + voffset, dst->values());
708
1.66k
            IMMER_TRY {
709
1.66k
                new (dst->values() + voffset) T{std::move(value)};
710
1.66k
                IMMER_TRY {
711
1.66k
                    if (nv)
712
793
                        detail::uninitialized_copy(src->values() + voffset,
713
793
                                                   src->values() + nv,
714
793
                                                   dst->values() + voffset + 1);
715
1.66k
                }
716
1.66k
                IMMER_CATCH (...) {
717
0
                    dst->values()[voffset].~T();
718
0
                    IMMER_RETHROW;
719
0
                }
720
1.66k
            }
721
1.66k
            IMMER_CATCH (...) {
722
0
                detail::destroy_n(dst->values(), voffset);
723
0
                IMMER_RETHROW;
724
0
            }
725
1.66k
        }
726
1.66k
        IMMER_CATCH (...) {
727
0
            deallocate_inner(dst, n - 1, nv + 1);
728
0
            IMMER_RETHROW;
729
0
        }
730
1.66k
        inc_nodes(src->children(), noffset);
731
1.66k
        inc_nodes(src->children() + noffset + 1, n - noffset - 1);
732
1.66k
        std::copy(src->children(), src->children() + noffset, dst->children());
733
1.66k
        std::copy(src->children() + noffset + 1,
734
1.66k
                  src->children() + n,
735
1.66k
                  dst->children() + noffset);
736
1.66k
        return dst;
737
1.66k
    }
738
739
    static node_t* move_inner_replace_inline(
740
        edit_t e, node_t* src, bitmap_t bit, count_t noffset, T value)
741
2.51k
    {
742
2.51k
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
743
2.51k
        assert(!(src->datamap() & bit));
744
2.51k
        assert(src->nodemap() & bit);
745
2.51k
        assert(noffset == src->children_count(bit));
746
2.51k
        auto n                         = src->children_count();
747
2.51k
        auto nv                        = src->data_count();
748
2.51k
        auto dst                       = make_inner_n(n - 1, nv + 1);
749
2.51k
        auto voffset                   = src->data_count(bit);
750
2.51k
        dst->impl.d.data.inner.nodemap = src->nodemap() & ~bit;
751
2.51k
        dst->impl.d.data.inner.datamap = src->datamap() | bit;
752
2.51k
        IMMER_TRY {
753
2.51k
            auto mutate_values =
754
2.51k
                nv && can_mutate(src->impl.d.data.inner.values, e);
755
2.51k
            if (nv) {
756
1.20k
                if (mutate_values)
757
971
                    detail::uninitialized_move(
758
971
                        src->values(), src->values() + voffset, dst->values());
759
229
                else
760
229
                    detail::uninitialized_copy(
761
229
                        src->values(), src->values() + voffset, dst->values());
762
1.20k
            }
763
2.51k
            IMMER_TRY {
764
2.51k
                new (dst->values() + voffset) T{std::move(value)};
765
2.51k
                IMMER_TRY {
766
2.51k
                    if (nv) {
767
1.20k
                        if (mutate_values)
768
971
                            detail::uninitialized_move(src->values() + voffset,
769
971
                                                       src->values() + nv,
770
971
                                                       dst->values() + voffset +
771
971
                                                           1);
772
229
                        else
773
229
                            detail::uninitialized_copy(src->values() + voffset,
774
229
                                                       src->values() + nv,
775
229
                                                       dst->values() + voffset +
776
229
                                                           1);
777
1.20k
                    }
778
2.51k
                }
779
2.51k
                IMMER_CATCH (...) {
780
0
                    dst->values()[voffset].~T();
781
0
                    IMMER_RETHROW;
782
0
                }
783
2.51k
            }
784
2.51k
            IMMER_CATCH (...) {
785
0
                detail::destroy_n(dst->values(), voffset);
786
0
                IMMER_RETHROW;
787
0
            }
788
2.51k
        }
789
2.51k
        IMMER_CATCH (...) {
790
0
            deallocate_inner(dst, n - 1, nv + 1);
791
0
            IMMER_RETHROW;
792
0
        }
793
2.51k
        std::copy(src->children(), src->children() + noffset, dst->children());
794
2.51k
        std::copy(src->children() + noffset + 1,
795
2.51k
                  src->children() + n,
796
2.51k
                  dst->children() + noffset);
797
2.51k
        delete_inner(src);
798
2.51k
        return dst;
799
2.51k
    }
800
801
    static node_t*
802
    copy_inner_remove_value(node_t* src, bitmap_t bit, count_t voffset)
803
2.46k
    {
804
2.46k
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
805
2.46k
        assert(!(src->nodemap() & bit));
806
2.46k
        assert(src->datamap() & bit);
807
2.46k
        assert(voffset == src->data_count(bit));
808
2.46k
        auto n                         = src->children_count();
809
2.46k
        auto nv                        = src->data_count();
810
2.46k
        auto dst                       = make_inner_n(n, nv - 1);
811
2.46k
        dst->impl.d.data.inner.datamap = src->datamap() & ~bit;
812
2.46k
        dst->impl.d.data.inner.nodemap = src->nodemap();
813
2.46k
        if (nv > 1) {
814
1.71k
            IMMER_TRY {
815
1.71k
                detail::uninitialized_copy(
816
1.71k
                    src->values(), src->values() + voffset, dst->values());
817
1.71k
                IMMER_TRY {
818
1.71k
                    detail::uninitialized_copy(src->values() + voffset + 1,
819
1.71k
                                               src->values() + nv,
820
1.71k
                                               dst->values() + voffset);
821
1.71k
                }
822
1.71k
                IMMER_CATCH (...) {
823
0
                    detail::destroy_n(dst->values(), voffset);
824
0
                    IMMER_RETHROW;
825
0
                }
826
1.71k
            }
827
1.71k
            IMMER_CATCH (...) {
828
0
                deallocate_inner(dst, n, nv - 1);
829
0
                IMMER_RETHROW;
830
0
            }
831
1.71k
        }
832
2.46k
        inc_nodes(src->children(), n);
833
2.46k
        std::copy(src->children(), src->children() + n, dst->children());
834
2.46k
        return dst;
835
2.46k
    }
836
837
    static node_t* move_inner_remove_value(edit_t e,
838
                                           node_t* src,
839
                                           bitmap_t bit,
840
                                           count_t voffset)
841
1.66k
    {
842
1.66k
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
843
1.66k
        assert(!(src->nodemap() & bit));
844
1.66k
        assert(src->datamap() & bit);
845
1.66k
        assert(voffset == src->data_count(bit));
846
1.66k
        auto n                         = src->children_count();
847
1.66k
        auto nv                        = src->data_count();
848
1.66k
        auto dst                       = make_inner_n(n, nv - 1);
849
1.66k
        dst->impl.d.data.inner.datamap = src->datamap() & ~bit;
850
1.66k
        dst->impl.d.data.inner.nodemap = src->nodemap();
851
1.66k
        if (nv > 1) {
852
1.41k
            auto mutate_values = can_mutate(src->impl.d.data.inner.values, e);
853
1.41k
            if (mutate_values) {
854
1.21k
                IMMER_TRY {
855
1.21k
                    detail::uninitialized_move(
856
1.21k
                        src->values(), src->values() + voffset, dst->values());
857
1.21k
                    IMMER_TRY {
858
1.21k
                        detail::uninitialized_move(src->values() + voffset + 1,
859
1.21k
                                                   src->values() + nv,
860
1.21k
                                                   dst->values() + voffset);
861
1.21k
                    }
862
1.21k
                    IMMER_CATCH (...) {
863
0
                        detail::destroy_n(dst->values(), voffset);
864
0
                        IMMER_RETHROW;
865
0
                    }
866
1.21k
                }
867
1.21k
                IMMER_CATCH (...) {
868
0
                    deallocate_inner(dst, n, nv - 1);
869
0
                    IMMER_RETHROW;
870
0
                }
871
1.21k
            } else {
872
197
                IMMER_TRY {
873
197
                    detail::uninitialized_copy(
874
197
                        src->values(), src->values() + voffset, dst->values());
875
197
                    IMMER_TRY {
876
197
                        detail::uninitialized_copy(src->values() + voffset + 1,
877
197
                                                   src->values() + nv,
878
197
                                                   dst->values() + voffset);
879
197
                    }
880
197
                    IMMER_CATCH (...) {
881
0
                        detail::destroy_n(dst->values(), voffset);
882
0
                        IMMER_RETHROW;
883
0
                    }
884
197
                }
885
197
                IMMER_CATCH (...) {
886
0
                    deallocate_inner(dst, n, nv - 1);
887
0
                    IMMER_RETHROW;
888
0
                }
889
197
            }
890
1.41k
        }
891
454
        std::copy(src->children(), src->children() + n, dst->children());
892
454
        delete_inner(src);
893
454
        return dst;
894
1.66k
    }
895
896
    static node_t* copy_inner_insert_value(node_t* src, bitmap_t bit, T v)
897
48.3k
    {
898
48.3k
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
899
48.3k
        auto n                         = src->children_count();
900
48.3k
        auto nv                        = src->data_count();
901
48.3k
        auto offset                    = src->data_count(bit);
902
48.3k
        auto dst                       = make_inner_n(n, nv + 1);
903
48.3k
        dst->impl.d.data.inner.datamap = src->datamap() | bit;
904
48.3k
        dst->impl.d.data.inner.nodemap = src->nodemap();
905
48.3k
        IMMER_TRY {
906
48.3k
            if (nv)
907
40.4k
                detail::uninitialized_copy(
908
40.4k
                    src->values(), src->values() + offset, dst->values());
909
48.3k
            IMMER_TRY {
910
48.3k
                new (dst->values() + offset) T{std::move(v)};
911
48.3k
                IMMER_TRY {
912
48.3k
                    if (nv)
913
40.4k
                        detail::uninitialized_copy(src->values() + offset,
914
40.4k
                                                   src->values() + nv,
915
40.4k
                                                   dst->values() + offset + 1);
916
48.3k
                }
917
48.3k
                IMMER_CATCH (...) {
918
0
                    dst->values()[offset].~T();
919
0
                    IMMER_RETHROW;
920
0
                }
921
48.3k
            }
922
48.3k
            IMMER_CATCH (...) {
923
0
                detail::destroy_n(dst->values(), offset);
924
0
                IMMER_RETHROW;
925
0
            }
926
48.3k
        }
927
48.3k
        IMMER_CATCH (...) {
928
0
            deallocate_inner(dst, n, nv + 1);
929
0
            IMMER_RETHROW;
930
0
        }
931
48.3k
        inc_nodes(src->children(), n);
932
48.3k
        std::copy(src->children(), src->children() + n, dst->children());
933
48.3k
        return dst;
934
48.3k
    }
935
936
    static node_t*
937
    move_inner_insert_value(edit_t e, node_t* src, bitmap_t bit, T v)
938
14.6k
    {
939
14.6k
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
940
14.6k
        auto n                         = src->children_count();
941
14.6k
        auto nv                        = src->data_count();
942
14.6k
        auto offset                    = src->data_count(bit);
943
14.6k
        auto dst                       = make_inner_n(n, nv + 1);
944
14.6k
        dst->impl.d.data.inner.datamap = src->datamap() | bit;
945
14.6k
        dst->impl.d.data.inner.nodemap = src->nodemap();
946
14.6k
        IMMER_TRY {
947
14.6k
            auto mutate_values =
948
14.6k
                nv && can_mutate(src->impl.d.data.inner.values, e);
949
14.6k
            if (nv) {
950
13.9k
                if (mutate_values)
951
13.5k
                    detail::uninitialized_move(
952
13.5k
                        src->values(), src->values() + offset, dst->values());
953
391
                else
954
391
                    detail::uninitialized_copy(
955
391
                        src->values(), src->values() + offset, dst->values());
956
13.9k
            }
957
14.6k
            IMMER_TRY {
958
14.6k
                new (dst->values() + offset) T{std::move(v)};
959
14.6k
                IMMER_TRY {
960
14.6k
                    if (nv) {
961
13.9k
                        if (mutate_values)
962
13.5k
                            detail::uninitialized_move(src->values() + offset,
963
13.5k
                                                       src->values() + nv,
964
13.5k
                                                       dst->values() + offset +
965
13.5k
                                                           1);
966
391
                        else
967
391
                            detail::uninitialized_copy(src->values() + offset,
968
391
                                                       src->values() + nv,
969
391
                                                       dst->values() + offset +
970
391
                                                           1);
971
13.9k
                    }
972
14.6k
                }
973
14.6k
                IMMER_CATCH (...) {
974
0
                    dst->values()[offset].~T();
975
0
                    IMMER_RETHROW;
976
0
                }
977
14.6k
            }
978
14.6k
            IMMER_CATCH (...) {
979
0
                detail::destroy_n(dst->values(), offset);
980
0
                IMMER_RETHROW;
981
0
            }
982
14.6k
        }
983
14.6k
        IMMER_CATCH (...) {
984
0
            deallocate_inner(dst, n, nv + 1);
985
0
            IMMER_RETHROW;
986
0
        }
987
14.6k
        std::copy(src->children(), src->children() + n, dst->children());
988
14.6k
        delete_inner(src);
989
14.6k
        return dst;
990
14.6k
    }
991
992
    static node_t*
993
    make_merged(shift_t shift, T v1, hash_t hash1, T v2, hash_t hash2)
994
27.2k
    {
995
27.2k
        if (shift < max_shift<hash_t, B>) {
996
27.2k
            auto idx1 = hash1 & (mask<hash_t, B> << shift);
997
27.2k
            auto idx2 = hash2 & (mask<hash_t, B> << shift);
998
27.2k
            if (idx1 == idx2) {
999
4.87k
                auto merged = make_merged(
1000
4.87k
                    shift + B, std::move(v1), hash1, std::move(v2), hash2);
1001
4.87k
                IMMER_TRY {
1002
4.87k
                    return make_inner_n(
1003
4.87k
                        1, static_cast<count_t>(idx1 >> shift), merged);
1004
4.87k
                }
1005
4.87k
                IMMER_CATCH (...) {
1006
0
                    delete_deep_shift(merged, shift + B);
1007
0
                    IMMER_RETHROW;
1008
0
                }
1009
22.3k
            } else {
1010
22.3k
                return make_inner_n(0,
1011
22.3k
                                    static_cast<count_t>(idx1 >> shift),
1012
22.3k
                                    std::move(v1),
1013
22.3k
                                    static_cast<count_t>(idx2 >> shift),
1014
22.3k
                                    std::move(v2));
1015
22.3k
            }
1016
27.2k
        } else {
1017
0
            return make_collision(std::move(v1), std::move(v2));
1018
0
        }
1019
27.2k
    }
1020
1021
    static node_t* make_merged_e(
1022
        edit_t e, shift_t shift, T v1, hash_t hash1, T v2, hash_t hash2)
1023
10.0k
    {
1024
10.0k
        if (shift < max_shift<hash_t, B>) {
1025
10.0k
            auto idx1 = hash1 & (mask<hash_t, B> << shift);
1026
10.0k
            auto idx2 = hash2 & (mask<hash_t, B> << shift);
1027
10.0k
            if (idx1 == idx2) {
1028
1.78k
                auto merged = make_merged_e(
1029
1.78k
                    e, shift + B, std::move(v1), hash1, std::move(v2), hash2);
1030
1.78k
                IMMER_TRY {
1031
1.78k
                    return owned(
1032
1.78k
                        make_inner_n(
1033
1.78k
                            1, static_cast<count_t>(idx1 >> shift), merged),
1034
1.78k
                        e);
1035
1.78k
                }
1036
1.78k
                IMMER_CATCH (...) {
1037
0
                    delete_deep_shift(merged, shift + B);
1038
0
                    IMMER_RETHROW;
1039
0
                }
1040
8.29k
            } else {
1041
8.29k
                auto r = make_inner_n(0,
1042
8.29k
                                      static_cast<count_t>(idx1 >> shift),
1043
8.29k
                                      std::move(v1),
1044
8.29k
                                      static_cast<count_t>(idx2 >> shift),
1045
8.29k
                                      std::move(v2));
1046
8.29k
                return owned_values(r, e);
1047
8.29k
            }
1048
10.0k
        } else {
1049
0
            return owned(make_collision(std::move(v1), std::move(v2)), e);
1050
0
        }
1051
10.0k
    }
1052
1053
    node_t* inc()
1054
531k
    {
1055
531k
        refs(this).inc();
1056
531k
        return this;
1057
531k
    }
1058
1059
    const node_t* inc() const
1060
    {
1061
        refs(this).inc();
1062
        return this;
1063
    }
1064
1065
14.4M
    bool dec() const { return refs(this).dec(); }
1066
1067
    static void inc_nodes(node_t** p, count_t n)
1068
2.51M
    {
1069
14.8M
        for (auto i = p, e = i + n; i != e; ++i)
1070
12.3M
            refs(*i).inc();
1071
2.51M
    }
1072
1073
    static void delete_values(values_t* p, count_t n)
1074
563k
    {
1075
563k
        assert(p);
1076
563k
        detail::destroy_n((T*) &p->d.buffer, n);
1077
563k
        deallocate_values(p, n);
1078
563k
    }
1079
1080
    static void delete_inner(node_t* p)
1081
1.57M
    {
1082
1.57M
        assert(p);
1083
1.57M
        IMMER_ASSERT_TAGGED(p->kind() == kind_t::inner);
1084
1.57M
        auto vp = p->impl.d.data.inner.values;
1085
1.57M
        if (vp && refs(vp).dec())
1086
563k
            delete_values(vp, p->data_count());
1087
1.57M
        deallocate_inner(p, p->children_count());
1088
1.57M
    }
1089
1090
    static void delete_collision(node_t* p)
1091
0
    {
1092
0
        assert(p);
1093
0
        IMMER_ASSERT_TAGGED(p->kind() == kind_t::collision);
1094
0
        auto n = p->collision_count();
1095
0
        detail::destroy_n(p->collisions(), n);
1096
0
        deallocate_collision(p, n);
1097
0
    }
1098
1099
    static void delete_deep(node_t* p, shift_t s)
1100
1.54M
    {
1101
1.54M
        if (s == max_depth<hash_t, B>)
1102
0
            delete_collision(p);
1103
1.54M
        else {
1104
1.54M
            auto fst = p->children();
1105
1.54M
            auto lst = fst + p->children_count();
1106
14.9M
            for (; fst != lst; ++fst)
1107
13.4M
                if ((*fst)->dec())
1108
1.04M
                    delete_deep(*fst, s + 1);
1109
1.54M
            delete_inner(p);
1110
1.54M
        }
1111
1.54M
    }
1112
1113
    static void delete_deep_shift(node_t* p, shift_t s)
1114
0
    {
1115
0
        if (s == max_shift<hash_t, B>)
1116
0
            delete_collision(p);
1117
0
        else {
1118
0
            auto fst = p->children();
1119
0
            auto lst = fst + p->children_count();
1120
0
            for (; fst != lst; ++fst)
1121
0
                if ((*fst)->dec())
1122
0
                    delete_deep_shift(*fst, s + B);
1123
0
            delete_inner(p);
1124
0
        }
1125
0
    }
1126
1127
    static void deallocate_values(values_t* p, count_t n)
1128
563k
    {
1129
563k
        heap::deallocate(node_t::sizeof_values_n(n), p);
1130
563k
    }
1131
1132
    static void deallocate_collision(node_t* p, count_t n)
1133
0
    {
1134
0
        heap::deallocate(node_t::sizeof_collision_n(n), p);
1135
0
    }
1136
1137
    static void deallocate_inner(node_t* p, count_t n)
1138
1.57M
    {
1139
1.57M
        heap::deallocate(node_t::sizeof_inner_n(n), p);
1140
1.57M
    }
1141
1142
    static void deallocate_inner(node_t* p, count_t n, count_t nv)
1143
0
    {
1144
0
        assert(nv);
1145
0
        heap::deallocate(node_t::sizeof_values_n(nv),
1146
0
                         p->impl.d.data.inner.values);
1147
0
        heap::deallocate(node_t::sizeof_inner_n(n), p);
1148
0
    }
1149
};
1150
1151
} // namespace hamts
1152
} // namespace detail
1153
} // namespace immer