Coverage Report

Created: 2026-10-17 06:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/immer/immer/detail/rbts/node.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/combine_standard_layout.hpp>
13
#include <immer/detail/rbts/bits.hpp>
14
#include <immer/detail/util.hpp>
15
#include <immer/heap/tags.hpp>
16
17
#include <cassert>
18
#include <cstddef>
19
#include <memory>
20
#include <type_traits>
21
22
// Disable some warnings for this file as it seems to be causing various
23
// false positives when compiling with various versions of GCC.
24
#if !defined(_MSC_VER)
25
#if defined(__GNUC__) && !defined(__clang__)
26
#pragma GCC diagnostic push
27
#pragma GCC diagnostic ignored "-Warray-bounds"
28
#pragma GCC diagnostic ignored "-Wstringop-overflow"
29
#pragma GCC diagnostic ignored "-Wnonnull"
30
#endif
31
#endif
32
33
namespace immer {
34
namespace detail {
35
namespace rbts {
36
37
template <typename T, typename MemoryPolicy, bits_t B, bits_t BL>
38
struct node
39
{
40
    static constexpr auto bits      = B;
41
    static constexpr auto bits_leaf = BL;
42
43
    using node_t      = node;
44
    using memory      = MemoryPolicy;
45
    using heap_policy = typename memory::heap;
46
    using transience  = typename memory::transience_t;
47
    using refs_t      = typename memory::refcount;
48
    using ownee_t     = typename transience::ownee;
49
    using edit_t      = typename transience::edit;
50
    using value_t     = T;
51
52
    static constexpr bool embed_relaxed = memory::prefer_fewer_bigger_objects;
53
54
    enum class kind_t
55
    {
56
        leaf,
57
        inner
58
    };
59
60
    struct relaxed_data_t
61
    {
62
        count_t count;
63
        size_t sizes[branches<B>];
64
    };
65
66
    using relaxed_data_with_meta_t =
67
        combine_standard_layout_t<relaxed_data_t, refs_t, ownee_t>;
68
69
    using relaxed_data_no_meta_t = combine_standard_layout_t<relaxed_data_t>;
70
71
    using relaxed_t = std::conditional_t<embed_relaxed,
72
                                         relaxed_data_no_meta_t,
73
                                         relaxed_data_with_meta_t>;
74
75
    struct leaf_t : public with_trailing_storage<leaf_t, T, true>
76
    {};
77
78
    struct inner_t : public with_trailing_storage<inner_t, node_t*>
79
    {
80
        relaxed_t* relaxed;
81
    };
82
83
    union data_t
84
    {
85
        inner_t inner;
86
        leaf_t leaf;
87
    };
88
89
    struct impl_data_t
90
    {
91
#if IMMER_TAGGED_NODE
92
        kind_t kind;
93
#endif
94
        data_t data;
95
    };
96
97
    using impl_t = combine_standard_layout_t<impl_data_t, refs_t, ownee_t>;
98
99
    impl_t impl;
100
101
    // assume that we need to keep headroom space in the node when we
102
    // are doing reference counting, since any node may become
103
    // transient when it has only one reference
104
    constexpr static bool keep_headroom = !std::is_empty<refs_t>{};
105
106
    constexpr static std::size_t sizeof_packed_leaf_n(count_t count)
107
0
    {
108
0
        return immer_offsetof(impl_t, d.data.leaf) +
109
0
               leaf_t::get_storage_offset() +
110
0
               sizeof(typename leaf_t::storage_type) * count;
111
0
    }
Unexecuted instantiation: immer::detail::rbts::node<int, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true>, 5u, 5u>::sizeof_packed_leaf_n(unsigned int)
Unexecuted instantiation: immer::detail::rbts::node<int, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true>, 5u, 6u>::sizeof_packed_leaf_n(unsigned int)
Unexecuted instantiation: immer::detail::rbts::node<int, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u, 3u>::sizeof_packed_leaf_n(unsigned int)
112
113
    constexpr static std::size_t sizeof_packed_inner_n(count_t count)
114
0
    {
115
0
        return immer_offsetof(impl_t, d.data.inner) +
116
0
               inner_t::get_storage_offset() +
117
0
               sizeof(typename inner_t::storage_type) * count;
118
0
    }
Unexecuted instantiation: immer::detail::rbts::node<int, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true>, 5u, 5u>::sizeof_packed_inner_n(unsigned int)
Unexecuted instantiation: immer::detail::rbts::node<int, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true>, 5u, 6u>::sizeof_packed_inner_n(unsigned int)
Unexecuted instantiation: immer::detail::rbts::node<int, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u, 3u>::sizeof_packed_inner_n(unsigned int)
119
120
    constexpr static std::size_t sizeof_packed_relaxed_n(count_t count)
121
0
    {
122
0
        return immer_offsetof(relaxed_t, d.sizes) + sizeof(size_t) * count;
123
0
    }
Unexecuted instantiation: immer::detail::rbts::node<int, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true>, 5u, 5u>::sizeof_packed_relaxed_n(unsigned int)
Unexecuted instantiation: immer::detail::rbts::node<int, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true>, 5u, 6u>::sizeof_packed_relaxed_n(unsigned int)
Unexecuted instantiation: immer::detail::rbts::node<int, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u, 3u>::sizeof_packed_relaxed_n(unsigned int)
124
125
    constexpr static std::size_t sizeof_packed_inner_r_n(count_t count)
126
0
    {
127
0
        return embed_relaxed ? sizeof_packed_inner_n(count) +
128
0
                                   sizeof_packed_relaxed_n(count)
129
0
                             : sizeof_packed_inner_n(count);
130
0
    }
Unexecuted instantiation: immer::detail::rbts::node<int, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true>, 5u, 5u>::sizeof_packed_inner_r_n(unsigned int)
Unexecuted instantiation: immer::detail::rbts::node<int, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true>, 5u, 6u>::sizeof_packed_inner_r_n(unsigned int)
Unexecuted instantiation: immer::detail::rbts::node<int, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u, 3u>::sizeof_packed_inner_r_n(unsigned int)
131
132
    constexpr static std::size_t max_sizeof_leaf =
133
        sizeof_packed_leaf_n(branches<BL>);
134
135
    constexpr static std::size_t max_sizeof_inner =
136
        sizeof_packed_inner_n(branches<B>);
137
138
    constexpr static std::size_t max_sizeof_relaxed =
139
        sizeof_packed_relaxed_n(branches<B>);
140
141
    constexpr static std::size_t max_sizeof_inner_r =
142
        sizeof_packed_inner_r_n(branches<B>);
143
144
    constexpr static std::size_t sizeof_inner_n(count_t n)
145
21.2M
    {
146
21.2M
        return keep_headroom ? max_sizeof_inner : sizeof_packed_inner_n(n);
147
21.2M
    }
148
149
    constexpr static std::size_t sizeof_inner_r_n(count_t n)
150
104M
    {
151
104M
        return keep_headroom ? max_sizeof_inner_r : sizeof_packed_inner_r_n(n);
152
104M
    }
153
154
    constexpr static std::size_t sizeof_relaxed_n(count_t n)
155
104M
    {
156
104M
        return keep_headroom ? max_sizeof_relaxed : sizeof_packed_relaxed_n(n);
157
104M
    }
158
159
    constexpr static std::size_t sizeof_leaf_n(count_t n)
160
10.9M
    {
161
10.9M
        return keep_headroom ? max_sizeof_leaf : sizeof_packed_leaf_n(n);
162
10.9M
    }
163
164
    using heap =
165
        typename heap_policy::template optimized<max_sizeof_inner>::type;
166
167
#if IMMER_TAGGED_NODE
168
1.62G
    kind_t kind() const { return impl.d.kind; }
169
#endif
170
171
    relaxed_t* relaxed()
172
1.04G
    {
173
1.04G
        IMMER_ASSERT_TAGGED(kind() == kind_t::inner);
174
1.04G
        return impl.d.data.inner.relaxed;
175
1.04G
    }
176
177
    const relaxed_t* relaxed() const
178
0
    {
179
0
        IMMER_ASSERT_TAGGED(kind() == kind_t::inner);
180
0
        return impl.d.data.inner.relaxed;
181
0
    }
182
183
    node_t** inner()
184
469M
    {
185
469M
        IMMER_ASSERT_TAGGED(kind() == kind_t::inner);
186
469M
        return impl.d.data.inner.get_storage_ptr();
187
469M
    }
188
189
    T* leaf()
190
18.8M
    {
191
18.8M
        IMMER_ASSERT_TAGGED(kind() == kind_t::leaf);
192
18.8M
        return impl.d.data.leaf.get_storage_ptr();
193
18.8M
    }
194
195
    static refs_t& refs(const relaxed_t* x)
196
53.3M
    {
197
53.3M
        return auto_const_cast(get<refs_t>(*x));
198
53.3M
    }
199
    static const ownee_t& ownee(const relaxed_t* x) { return get<ownee_t>(*x); }
200
52.4M
    static ownee_t& ownee(relaxed_t* x) { return get<ownee_t>(*x); }
201
202
    static refs_t& refs(const node_t* x)
203
752M
    {
204
752M
        return auto_const_cast(get<refs_t>(x->impl));
205
752M
    }
206
    static const ownee_t& ownee(const node_t* x)
207
173k
    {
208
173k
        return get<ownee_t>(x->impl);
209
173k
    }
210
61.5M
    static ownee_t& ownee(node_t* x) { return get<ownee_t>(x->impl); }
211
212
    static node_t* make_inner_n_into(void* buffer, std::size_t size, count_t n)
213
5.29M
    {
214
5.29M
        assert(n <= branches<B>);
215
5.29M
        assert(size >= sizeof_inner_n(n));
216
5.29M
        auto p                       = new (buffer) node_t;
217
5.29M
        p->impl.d.data.inner.relaxed = nullptr;
218
5.29M
#if IMMER_TAGGED_NODE
219
5.29M
        p->impl.d.kind = node_t::kind_t::inner;
220
5.29M
#endif
221
5.29M
        return p;
222
5.29M
    }
223
    static node_t* make_inner_n(count_t n)
224
5.29M
    {
225
5.29M
        assert(n <= branches<B>);
226
5.29M
        auto m = heap::allocate(sizeof_inner_n(n));
227
5.29M
        return make_inner_n_into(m, sizeof_inner_n(n), n);
228
5.29M
    }
229
230
    static node_t* make_inner_e(edit_t e)
231
79.5k
    {
232
79.5k
        auto m                       = heap::allocate(max_sizeof_inner);
233
79.5k
        auto p                       = new (m) node_t;
234
79.5k
        ownee(p)                     = e;
235
79.5k
        p->impl.d.data.inner.relaxed = nullptr;
236
79.5k
#if IMMER_TAGGED_NODE
237
79.5k
        p->impl.d.kind = node_t::kind_t::inner;
238
79.5k
#endif
239
79.5k
        return p;
240
79.5k
    }
241
242
    static node_t* make_inner_r_n(count_t n)
243
51.9M
    {
244
51.9M
        assert(n <= branches<B>);
245
51.9M
        auto mp = heap::allocate(sizeof_inner_r_n(n));
246
51.9M
        auto mr = static_cast<void*>(nullptr);
247
51.9M
        if (embed_relaxed) {
248
0
            mr = reinterpret_cast<unsigned char*>(mp) + sizeof_inner_n(n);
249
51.9M
        } else {
250
51.9M
            IMMER_TRY {
251
51.9M
                mr = heap::allocate(sizeof_relaxed_n(n), norefs_tag{});
252
51.9M
            }
253
51.9M
            IMMER_CATCH (...) {
254
0
                heap::deallocate(sizeof_inner_r_n(n), mp);
255
0
                IMMER_RETHROW;
256
0
            }
257
51.9M
        }
258
51.9M
        auto p                       = new (mp) node_t;
259
51.9M
        auto r                       = new (mr) relaxed_t;
260
51.9M
        r->d.count                   = 0;
261
51.9M
        p->impl.d.data.inner.relaxed = r;
262
51.9M
#if IMMER_TAGGED_NODE
263
51.9M
        p->impl.d.kind = node_t::kind_t::inner;
264
51.9M
#endif
265
51.9M
        return p;
266
51.9M
    }
267
268
    static node_t* make_inner_sr_n(count_t n, relaxed_t* r)
269
355k
    {
270
355k
        return static_if<embed_relaxed, node_t*>(
271
355k
            [&](auto) { return node_t::make_inner_r_n(n); },
272
355k
            [&](auto) {
273
355k
                auto p =
274
355k
                    new (heap::allocate(node_t::sizeof_inner_r_n(n))) node_t;
275
355k
                assert(r->d.count >= n);
276
355k
                node_t::refs(r).inc();
277
355k
                p->impl.d.data.inner.relaxed = r;
278
355k
#if IMMER_TAGGED_NODE
279
355k
                p->impl.d.kind = node_t::kind_t::inner;
280
355k
#endif
281
355k
                return p;
282
355k
            });
283
355k
    }
284
285
    static node_t* make_inner_r_e(edit_t e)
286
170k
    {
287
170k
        auto mp = heap::allocate(max_sizeof_inner_r);
288
170k
        auto mr = static_cast<void*>(nullptr);
289
170k
        if (embed_relaxed) {
290
0
            mr = reinterpret_cast<unsigned char*>(mp) + max_sizeof_inner;
291
170k
        } else {
292
170k
            IMMER_TRY {
293
170k
                mr = heap::allocate(max_sizeof_relaxed, norefs_tag{});
294
170k
            }
295
170k
            IMMER_CATCH (...) {
296
0
                heap::deallocate(max_sizeof_inner_r, mp);
297
0
                IMMER_RETHROW;
298
0
            }
299
170k
        }
300
170k
        auto p   = new (mp) node_t;
301
170k
        auto r   = new (mr) relaxed_t;
302
170k
        ownee(p) = e;
303
170k
        static_if<!embed_relaxed>([&](auto) { node_t::ownee(r) = e; });
304
170k
        r->d.count                   = 0;
305
170k
        p->impl.d.data.inner.relaxed = r;
306
170k
#if IMMER_TAGGED_NODE
307
170k
        p->impl.d.kind = node_t::kind_t::inner;
308
170k
#endif
309
170k
        return p;
310
170k
    }
311
312
    static node_t* make_inner_sr_e(edit_t e, relaxed_t* r)
313
21.4k
    {
314
21.4k
        return static_if<embed_relaxed, node_t*>(
315
21.4k
            [&](auto) { return node_t::make_inner_r_e(e); },
316
21.4k
            [&](auto) {
317
21.4k
                auto p =
318
21.4k
                    new (heap::allocate(node_t::max_sizeof_inner_r)) node_t;
319
21.4k
                node_t::refs(r).inc();
320
21.4k
                p->impl.d.data.inner.relaxed = r;
321
21.4k
                node_t::ownee(p)             = e;
322
21.4k
#if IMMER_TAGGED_NODE
323
21.4k
                p->impl.d.kind = node_t::kind_t::inner;
324
21.4k
#endif
325
21.4k
                return p;
326
21.4k
            });
327
21.4k
    }
328
329
    static node_t* make_leaf_n_into(void* buffer, std::size_t size, count_t n)
330
2.62M
    {
331
2.62M
        assert(n <= branches<BL>);
332
2.62M
        assert(size >= sizeof_leaf_n(n));
333
2.62M
        auto p = new (buffer) node_t;
334
2.62M
#if IMMER_TAGGED_NODE
335
2.62M
        p->impl.d.kind = node_t::kind_t::leaf;
336
2.62M
#endif
337
2.62M
        return p;
338
2.62M
    }
339
340
    static node_t* make_leaf_n(count_t n)
341
2.62M
    {
342
2.62M
        assert(n <= branches<BL>);
343
2.62M
        auto m = heap::allocate(sizeof_leaf_n(n));
344
2.62M
        return make_leaf_n_into(m, sizeof_leaf_n(n), n);
345
2.62M
    }
346
347
    static node_t* make_leaf_e(edit_t e)
348
385k
    {
349
385k
        auto p   = new (heap::allocate(max_sizeof_leaf)) node_t;
350
385k
        ownee(p) = e;
351
385k
#if IMMER_TAGGED_NODE
352
385k
        p->impl.d.kind = node_t::kind_t::leaf;
353
385k
#endif
354
385k
        return p;
355
385k
    }
356
357
    static node_t* make_inner_n(count_t n, node_t* x)
358
    {
359
        assert(n >= 1);
360
        auto p        = make_inner_n(n);
361
        p->inner()[0] = x;
362
        return p;
363
    }
364
365
    static node_t* make_inner_n(edit_t n, node_t* x)
366
    {
367
        assert(n >= 1);
368
        auto p        = make_inner_n(n);
369
        p->inner()[0] = x;
370
        return p;
371
    }
372
373
    static node_t* make_inner_n(count_t n, node_t* x, node_t* y)
374
    {
375
        assert(n >= 2);
376
        auto p        = make_inner_n(n);
377
        p->inner()[0] = x;
378
        p->inner()[1] = y;
379
        return p;
380
    }
381
382
    static node_t* make_inner_r_n(count_t n, node_t* x)
383
    {
384
        assert(n >= 1);
385
        auto p        = make_inner_r_n(n);
386
        auto r        = p->relaxed();
387
        p->inner()[0] = x;
388
        r->d.count    = 1;
389
        return p;
390
    }
391
392
    static node_t* make_inner_r_n(count_t n, node_t* x, size_t xs)
393
    {
394
        assert(n >= 1);
395
        assert(xs);
396
        auto p        = make_inner_r_n(n);
397
        auto r        = p->relaxed();
398
        p->inner()[0] = x;
399
        r->d.sizes[0] = xs;
400
        r->d.count    = 1;
401
        return p;
402
    }
403
404
    static node_t* make_inner_r_n(count_t n, node_t* x, node_t* y)
405
    {
406
        assert(n >= 2);
407
        auto p        = make_inner_r_n(n);
408
        auto r        = p->relaxed();
409
        p->inner()[0] = x;
410
        p->inner()[1] = y;
411
        r->d.count    = 2;
412
        return p;
413
    }
414
415
    static node_t* make_inner_r_n(count_t n, node_t* x, size_t xs, node_t* y)
416
    {
417
        assert(n >= 2);
418
        assert(xs);
419
        auto p        = make_inner_r_n(n);
420
        auto r        = p->relaxed();
421
        p->inner()[0] = x;
422
        p->inner()[1] = y;
423
        r->d.sizes[0] = xs;
424
        r->d.count    = 2;
425
        return p;
426
    }
427
428
    static node_t*
429
    make_inner_r_n(count_t n, node_t* x, size_t xs, node_t* y, size_t ys)
430
    {
431
        assert(n >= 2);
432
        assert(xs);
433
        assert(ys);
434
        auto p        = make_inner_r_n(n);
435
        auto r        = p->relaxed();
436
        p->inner()[0] = x;
437
        p->inner()[1] = y;
438
        r->d.sizes[0] = xs;
439
        r->d.sizes[1] = xs + ys;
440
        r->d.count    = 2;
441
        return p;
442
    }
443
444
    static node_t* make_inner_r_n(count_t n,
445
                                  node_t* x,
446
                                  size_t xs,
447
                                  node_t* y,
448
                                  size_t ys,
449
                                  node_t* z,
450
                                  size_t zs)
451
    {
452
        assert(n >= 3);
453
        assert(xs);
454
        assert(ys);
455
        assert(zs);
456
        auto p        = make_inner_r_n(n);
457
        auto r        = p->relaxed();
458
        p->inner()[0] = x;
459
        p->inner()[1] = y;
460
        p->inner()[2] = z;
461
        r->d.sizes[0] = xs;
462
        r->d.sizes[1] = xs + ys;
463
        r->d.sizes[2] = xs + ys + zs;
464
        r->d.count    = 3;
465
        return p;
466
    }
467
468
    template <typename U>
469
    static node_t* make_leaf_n(count_t n, U&& x)
470
45.8k
    {
471
45.8k
        assert(n >= 1);
472
45.8k
        auto p = make_leaf_n(n);
473
45.8k
        IMMER_TRY {
474
45.8k
            new (p->leaf()) T(std::forward<U>(x));
475
45.8k
        }
476
45.8k
        IMMER_CATCH (...) {
477
0
            heap::deallocate(node_t::sizeof_leaf_n(n), p);
478
0
            IMMER_RETHROW;
479
0
        }
480
45.8k
        return p;
481
45.8k
    }
482
483
    template <typename U>
484
    static node_t* make_leaf_e(edit_t e, U&& x)
485
7.10k
    {
486
7.10k
        auto p = make_leaf_e(e);
487
7.10k
        IMMER_TRY {
488
7.10k
            new (p->leaf()) T(std::forward<U>(x));
489
7.10k
        }
490
7.10k
        IMMER_CATCH (...) {
491
0
            heap::deallocate(node_t::max_sizeof_leaf, p);
492
0
            IMMER_RETHROW;
493
0
        }
494
7.10k
        return p;
495
7.10k
    }
496
497
    static node_t* make_path(shift_t shift, node_t* node)
498
1.33M
    {
499
1.33M
        IMMER_ASSERT_TAGGED(node->kind() == kind_t::leaf);
500
1.33M
        if (shift == endshift<B, BL>)
501
1.13M
            return node;
502
194k
        else {
503
194k
            auto n = node_t::make_inner_n(1);
504
194k
            IMMER_TRY {
505
194k
                n->inner()[0] = make_path(shift - B, node);
506
194k
            }
507
194k
            IMMER_CATCH (...) {
508
0
                heap::deallocate(node_t::sizeof_inner_n(1), n);
509
0
                IMMER_RETHROW;
510
0
            }
511
194k
            return n;
512
194k
        }
513
1.33M
    }
514
515
    static node_t* make_path_e(edit_t e, shift_t shift, node_t* node)
516
373k
    {
517
373k
        IMMER_ASSERT_TAGGED(node->kind() == kind_t::leaf);
518
373k
        if (shift == endshift<B, BL>)
519
322k
            return node;
520
50.6k
        else {
521
50.6k
            auto n = node_t::make_inner_e(e);
522
50.6k
            IMMER_TRY {
523
50.6k
                n->inner()[0] = make_path_e(e, shift - B, node);
524
50.6k
            }
525
50.6k
            IMMER_CATCH (...) {
526
0
                heap::deallocate(node_t::max_sizeof_inner, n);
527
0
                IMMER_RETHROW;
528
0
            }
529
50.6k
            return n;
530
50.6k
        }
531
373k
    }
532
533
    static node_t* copy_inner(node_t* src, count_t n)
534
    {
535
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
536
        auto dst = make_inner_n(n);
537
        inc_nodes(src->inner(), n);
538
        std::copy(src->inner(), src->inner() + n, dst->inner());
539
        return dst;
540
    }
541
542
    static node_t* copy_inner_n(count_t allocn, node_t* src, count_t n)
543
8.60k
    {
544
8.60k
        assert(allocn >= n);
545
8.60k
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
546
8.60k
        auto dst = make_inner_n(allocn);
547
8.60k
        return do_copy_inner(dst, src, n);
548
8.60k
    }
549
550
    static node_t* copy_inner_e(edit_t e, node_t* src, count_t n)
551
19.6k
    {
552
19.6k
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
553
19.6k
        auto dst = make_inner_e(e);
554
19.6k
        return do_copy_inner(dst, src, n);
555
19.6k
    }
556
557
    static node_t* do_copy_inner(node_t* dst, node_t* src, count_t n)
558
5.07M
    {
559
5.07M
        IMMER_ASSERT_TAGGED(dst->kind() == kind_t::inner);
560
5.07M
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
561
5.07M
        auto p = src->inner();
562
5.07M
        inc_nodes(p, n);
563
5.07M
        std::copy(p, p + n, dst->inner());
564
5.07M
        return dst;
565
5.07M
    }
566
567
    static node_t* do_copy_inner_replace(
568
        node_t* dst, node_t* src, count_t n, count_t offset, node_t* child)
569
40.1k
    {
570
40.1k
        IMMER_ASSERT_TAGGED(dst->kind() == kind_t::inner);
571
40.1k
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
572
40.1k
        auto p = src->inner();
573
40.1k
        inc_nodes(p, offset);
574
40.1k
        inc_nodes(p + offset + 1, n - offset - 1);
575
40.1k
        std::copy(p, p + n, dst->inner());
576
40.1k
        dst->inner()[offset] = child;
577
40.1k
        return dst;
578
40.1k
    }
579
580
    static node_t* copy_inner_r(node_t* src, count_t n)
581
3.17k
    {
582
3.17k
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
583
3.17k
        auto dst = make_inner_r_n(n);
584
3.17k
        return do_copy_inner_r(dst, src, n);
585
3.17k
    }
586
587
    static node_t* copy_inner_r_n(count_t allocn, node_t* src, count_t n)
588
504k
    {
589
504k
        assert(allocn >= n);
590
504k
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
591
504k
        auto dst = make_inner_r_n(allocn);
592
504k
        return do_copy_inner_r(dst, src, n);
593
504k
    }
594
595
    static node_t* copy_inner_r_e(edit_t e, node_t* src, count_t n)
596
15.4k
    {
597
15.4k
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
598
15.4k
        auto dst = make_inner_r_e(e);
599
15.4k
        return do_copy_inner_r(dst, src, n);
600
15.4k
    }
601
602
    static node_t* copy_inner_sr_e(edit_t e, node_t* src, count_t n)
603
21.4k
    {
604
21.4k
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
605
21.4k
        auto dst = make_inner_sr_e(e, src->relaxed());
606
21.4k
        return do_copy_inner_sr(dst, src, n);
607
21.4k
    }
608
609
    static node_t* do_copy_inner_r(node_t* dst, node_t* src, count_t n)
610
522k
    {
611
522k
        IMMER_ASSERT_TAGGED(dst->kind() == kind_t::inner);
612
522k
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
613
522k
        auto src_r = src->relaxed();
614
522k
        auto dst_r = dst->relaxed();
615
522k
        inc_nodes(src->inner(), n);
616
522k
        std::copy(src->inner(), src->inner() + n, dst->inner());
617
522k
        std::copy(src_r->d.sizes, src_r->d.sizes + n, dst_r->d.sizes);
618
522k
        dst_r->d.count = n;
619
522k
        return dst;
620
522k
    }
621
622
    static node_t* do_copy_inner_replace_r(
623
        node_t* dst, node_t* src, count_t n, count_t offset, node_t* child)
624
0
    {
625
0
        IMMER_ASSERT_TAGGED(dst->kind() == kind_t::inner);
626
0
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
627
0
        auto src_r = src->relaxed();
628
0
        auto dst_r = dst->relaxed();
629
0
        auto p     = src->inner();
630
0
        inc_nodes(p, offset);
631
0
        inc_nodes(p + offset + 1, n - offset - 1);
632
0
        std::copy(src->inner(), src->inner() + n, dst->inner());
633
0
        std::copy(src_r->d.sizes, src_r->d.sizes + n, dst_r->d.sizes);
634
0
        dst_r->d.count       = n;
635
0
        dst->inner()[offset] = child;
636
0
        return dst;
637
0
    }
638
639
    static node_t* do_copy_inner_sr(node_t* dst, node_t* src, count_t n)
640
21.4k
    {
641
21.4k
        if (embed_relaxed)
642
0
            return do_copy_inner_r(dst, src, n);
643
21.4k
        else {
644
21.4k
            inc_nodes(src->inner(), n);
645
21.4k
            std::copy(src->inner(), src->inner() + n, dst->inner());
646
21.4k
            return dst;
647
21.4k
        }
648
21.4k
    }
649
650
    static node_t* do_copy_inner_replace_sr(
651
        node_t* dst, node_t* src, count_t n, count_t offset, node_t* child)
652
355k
    {
653
355k
        if (embed_relaxed)
654
0
            return do_copy_inner_replace_r(dst, src, n, offset, child);
655
355k
        else {
656
355k
            auto p = src->inner();
657
355k
            inc_nodes(p, offset);
658
355k
            inc_nodes(p + offset + 1, n - offset - 1);
659
355k
            std::copy(p, p + n, dst->inner());
660
355k
            dst->inner()[offset] = child;
661
355k
            return dst;
662
355k
        }
663
355k
    }
664
665
    static node_t* copy_leaf(node_t* src, count_t n)
666
202k
    {
667
202k
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::leaf);
668
202k
        auto dst = make_leaf_n(n);
669
202k
        IMMER_TRY {
670
202k
            detail::uninitialized_copy(
671
202k
                src->leaf(), src->leaf() + n, dst->leaf());
672
202k
        }
673
202k
        IMMER_CATCH (...) {
674
0
            heap::deallocate(node_t::sizeof_leaf_n(n), dst);
675
0
            IMMER_RETHROW;
676
0
        }
677
202k
        return dst;
678
202k
    }
679
680
    static node_t* copy_leaf_e(edit_t e, node_t* src, count_t n)
681
41.4k
    {
682
41.4k
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::leaf);
683
41.4k
        auto dst = make_leaf_e(e);
684
41.4k
        IMMER_TRY {
685
41.4k
            detail::uninitialized_copy(
686
41.4k
                src->leaf(), src->leaf() + n, dst->leaf());
687
41.4k
        }
688
41.4k
        IMMER_CATCH (...) {
689
0
            heap::deallocate(node_t::max_sizeof_leaf, dst);
690
0
            IMMER_RETHROW;
691
0
        }
692
41.4k
        return dst;
693
41.4k
    }
694
695
    static node_t* copy_leaf_n(count_t allocn, node_t* src, count_t n)
696
242k
    {
697
242k
        assert(allocn >= n);
698
242k
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::leaf);
699
242k
        auto dst = make_leaf_n(allocn);
700
242k
        IMMER_TRY {
701
242k
            detail::uninitialized_copy(
702
242k
                src->leaf(), src->leaf() + n, dst->leaf());
703
242k
        }
704
242k
        IMMER_CATCH (...) {
705
0
            heap::deallocate(node_t::sizeof_leaf_n(allocn), dst);
706
0
            IMMER_RETHROW;
707
0
        }
708
242k
        return dst;
709
242k
    }
710
711
    static node_t* copy_leaf(node_t* src1, count_t n1, node_t* src2, count_t n2)
712
964k
    {
713
964k
        IMMER_ASSERT_TAGGED(src1->kind() == kind_t::leaf);
714
964k
        IMMER_ASSERT_TAGGED(src2->kind() == kind_t::leaf);
715
964k
        auto dst = make_leaf_n(n1 + n2);
716
964k
        IMMER_TRY {
717
964k
            detail::uninitialized_copy(
718
964k
                src1->leaf(), src1->leaf() + n1, dst->leaf());
719
964k
        }
720
964k
        IMMER_CATCH (...) {
721
0
            heap::deallocate(node_t::sizeof_leaf_n(n1 + n2), dst);
722
0
            IMMER_RETHROW;
723
0
        }
724
964k
        IMMER_TRY {
725
964k
            detail::uninitialized_copy(
726
964k
                src2->leaf(), src2->leaf() + n2, dst->leaf() + n1);
727
964k
        }
728
964k
        IMMER_CATCH (...) {
729
0
            detail::destroy_n(dst->leaf(), n1);
730
0
            heap::deallocate(node_t::sizeof_leaf_n(n1 + n2), dst);
731
0
            IMMER_RETHROW;
732
0
        }
733
964k
        return dst;
734
964k
    }
735
736
    static node_t*
737
    copy_leaf_e(edit_t e, node_t* src1, count_t n1, node_t* src2, count_t n2)
738
243
    {
739
243
        IMMER_ASSERT_TAGGED(src1->kind() == kind_t::leaf);
740
243
        IMMER_ASSERT_TAGGED(src2->kind() == kind_t::leaf);
741
243
        auto dst = make_leaf_e(e);
742
243
        IMMER_TRY {
743
243
            detail::uninitialized_copy(
744
243
                src1->leaf(), src1->leaf() + n1, dst->leaf());
745
243
        }
746
243
        IMMER_CATCH (...) {
747
0
            heap::deallocate(max_sizeof_leaf, dst);
748
0
            IMMER_RETHROW;
749
0
        }
750
243
        IMMER_TRY {
751
243
            detail::uninitialized_copy(
752
243
                src2->leaf(), src2->leaf() + n2, dst->leaf() + n1);
753
243
        }
754
243
        IMMER_CATCH (...) {
755
0
            detail::destroy_n(dst->leaf(), n1);
756
0
            heap::deallocate(max_sizeof_leaf, dst);
757
0
            IMMER_RETHROW;
758
0
        }
759
243
        return dst;
760
243
    }
761
762
    static node_t* copy_leaf_e(edit_t e, node_t* src, count_t idx, count_t last)
763
336k
    {
764
336k
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::leaf);
765
336k
        auto dst = make_leaf_e(e);
766
336k
        IMMER_TRY {
767
336k
            detail::uninitialized_copy(
768
336k
                src->leaf() + idx, src->leaf() + last, dst->leaf());
769
336k
        }
770
336k
        IMMER_CATCH (...) {
771
0
            heap::deallocate(max_sizeof_leaf, dst);
772
0
            IMMER_RETHROW;
773
0
        }
774
336k
        return dst;
775
336k
    }
776
777
    static node_t* copy_leaf(node_t* src, count_t idx, count_t last)
778
946k
    {
779
946k
        IMMER_ASSERT_TAGGED(src->kind() == kind_t::leaf);
780
946k
        auto dst = make_leaf_n(last - idx);
781
946k
        IMMER_TRY {
782
946k
            detail::uninitialized_copy(
783
946k
                src->leaf() + idx, src->leaf() + last, dst->leaf());
784
946k
        }
785
946k
        IMMER_CATCH (...) {
786
0
            heap::deallocate(node_t::sizeof_leaf_n(last - idx), dst);
787
0
            IMMER_RETHROW;
788
0
        }
789
946k
        return dst;
790
946k
    }
791
792
    template <typename U>
793
    static node_t* copy_leaf_emplace(node_t* src, count_t n, U&& x)
794
242k
    {
795
242k
        auto dst = copy_leaf_n(n + 1, src, n);
796
242k
        IMMER_TRY {
797
242k
            new (dst->leaf() + n) T(std::forward<U>(x));
798
242k
        }
799
242k
        IMMER_CATCH (...) {
800
0
            detail::destroy_n(dst->leaf(), n);
801
0
            heap::deallocate(node_t::sizeof_leaf_n(n + 1), dst);
802
0
            IMMER_RETHROW;
803
0
        }
804
242k
        return dst;
805
242k
    }
806
807
    static void delete_inner(node_t* p, count_t n)
808
5.36M
    {
809
5.36M
        IMMER_ASSERT_TAGGED(p->kind() == kind_t::inner);
810
5.36M
        assert(!p->relaxed());
811
5.36M
        heap::deallocate(ownee(p).owned() ? node_t::max_sizeof_inner
812
5.36M
                                          : node_t::sizeof_inner_n(n),
813
5.36M
                         p);
814
5.36M
    }
815
816
    static void delete_inner_e(node_t* p)
817
0
    {
818
0
        IMMER_ASSERT_TAGGED(p->kind() == kind_t::inner);
819
0
        assert(!p->relaxed());
820
0
        heap::deallocate(node_t::max_sizeof_inner, p);
821
0
    }
822
823
    static void delete_inner_any(node_t* p, count_t n)
824
    {
825
        if (p->relaxed())
826
            delete_inner_r(p, n);
827
        else
828
            delete_inner(p, n);
829
    }
830
831
    static void delete_inner_r(node_t* p, count_t n)
832
52.5M
    {
833
52.5M
        IMMER_ASSERT_TAGGED(p->kind() == kind_t::inner);
834
52.5M
        auto r = p->relaxed();
835
52.5M
        assert(r);
836
52.5M
        static_if<!embed_relaxed>([&](auto) {
837
52.5M
            if (node_t::refs(r).dec())
838
52.1M
                heap::deallocate(node_t::ownee(r).owned()
839
52.1M
                                     ? node_t::max_sizeof_relaxed
840
52.1M
                                     : node_t::sizeof_relaxed_n(n),
841
52.1M
                                 r);
842
52.5M
        });
843
52.5M
        heap::deallocate(ownee(p).owned() ? node_t::max_sizeof_inner_r
844
52.5M
                                          : node_t::sizeof_inner_r_n(n),
845
52.5M
                         p);
846
52.5M
    }
847
848
    static void delete_inner_r_e(node_t* p)
849
0
    {
850
0
        IMMER_ASSERT_TAGGED(p->kind() == kind_t::inner);
851
0
        auto r = p->relaxed();
852
0
        assert(r);
853
0
        static_if<!embed_relaxed>([&](auto) {
854
0
            if (node_t::refs(r).dec())
855
0
                heap::deallocate(node_t::max_sizeof_relaxed, r);
856
0
        });
857
0
        heap::deallocate(node_t::max_sizeof_inner_r, p);
858
0
    }
859
860
    static void delete_leaf(node_t* p, count_t n)
861
3.01M
    {
862
3.01M
        IMMER_ASSERT_TAGGED(p->kind() == kind_t::leaf);
863
3.01M
        detail::destroy_n(p->leaf(), n);
864
3.01M
        heap::deallocate(ownee(p).owned() ? node_t::max_sizeof_leaf
865
3.01M
                                          : node_t::sizeof_leaf_n(n),
866
3.01M
                         p);
867
3.01M
    }
868
869
    bool can_mutate(edit_t e) const
870
2.56M
    {
871
2.56M
        return refs(this).unique() || ownee(this).can_mutate(e);
872
2.56M
    }
873
874
0
    bool can_relax() const { return !embed_relaxed || relaxed(); }
875
876
    relaxed_t* ensure_mutable_relaxed(edit_t e)
877
181k
    {
878
181k
        auto src_r = relaxed();
879
181k
        return static_if<embed_relaxed, relaxed_t*>(
880
181k
            [&](auto) { return src_r; },
881
181k
            [&](auto) {
882
181k
                if (node_t::refs(src_r).unique() ||
883
20.5k
                    node_t::ownee(src_r).can_mutate(e))
884
160k
                    return src_r;
885
20.5k
                else {
886
20.5k
                    auto dst_r = impl.d.data.inner.relaxed =
887
20.5k
                        new (heap::allocate(max_sizeof_relaxed)) relaxed_t;
888
20.5k
                    if (src_r) {
889
20.5k
                        auto n = dst_r->d.count = src_r->d.count;
890
20.5k
                        std::copy(
891
20.5k
                            src_r->d.sizes, src_r->d.sizes + n, dst_r->d.sizes);
892
20.5k
                        if (node_t::refs(src_r).dec())
893
0
                            heap::deallocate(node_t::sizeof_inner_r_n(n),
894
0
                                             src_r);
895
20.5k
                    }
896
20.5k
                    node_t::ownee(dst_r) = e;
897
20.5k
                    return dst_r;
898
20.5k
                }
899
181k
            });
900
181k
    }
901
902
    relaxed_t* ensure_mutable_relaxed_e(edit_t e, edit_t ec)
903
0
    {
904
0
        auto src_r = relaxed();
905
0
        return static_if<embed_relaxed, relaxed_t*>(
906
0
            [&](auto) { return src_r; },
907
0
            [&](auto) {
908
0
                if (src_r && (node_t::refs(src_r).unique() ||
909
0
                              node_t::ownee(src_r).can_mutate(e))) {
910
0
                    node_t::ownee(src_r) = ec;
911
0
                    return src_r;
912
0
                } else {
913
0
                    auto dst_r = impl.d.data.inner.relaxed =
914
0
                        new (heap::allocate(max_sizeof_relaxed)) relaxed_t;
915
0
                    if (src_r) {
916
0
                        auto n = dst_r->d.count = src_r->d.count;
917
0
                        std::copy(
918
0
                            src_r->d.sizes, src_r->d.sizes + n, dst_r->d.sizes);
919
0
                        if (node_t::refs(src_r).dec())
920
0
                            heap::deallocate(node_t::sizeof_inner_r_n(n),
921
0
                                             src_r);
922
0
                    }
923
0
                    node_t::ownee(dst_r) = ec;
924
0
                    return dst_r;
925
0
                }
926
0
            });
927
0
    }
928
929
    relaxed_t* ensure_mutable_relaxed_n(edit_t e, count_t n)
930
182k
    {
931
182k
        auto src_r = relaxed();
932
182k
        return static_if<embed_relaxed, relaxed_t*>(
933
182k
            [&](auto) { return src_r; },
934
182k
            [&](auto) {
935
182k
                if (node_t::refs(src_r).unique() ||
936
4.71k
                    node_t::ownee(src_r).can_mutate(e))
937
177k
                    return src_r;
938
4.71k
                else {
939
4.71k
                    auto dst_r =
940
4.71k
                        new (heap::allocate(max_sizeof_relaxed)) relaxed_t;
941
4.71k
                    if (src_r) {
942
4.71k
                        std::copy(
943
4.71k
                            src_r->d.sizes, src_r->d.sizes + n, dst_r->d.sizes);
944
4.71k
                        if (node_t::refs(src_r).dec())
945
0
                            heap::deallocate(node_t::sizeof_inner_r_n(n),
946
0
                                             src_r);
947
4.71k
                    }
948
4.71k
                    dst_r->d.count                   = n;
949
4.71k
                    node_t::ownee(dst_r)             = e;
950
4.71k
                    return impl.d.data.inner.relaxed = dst_r;
951
4.71k
                }
952
182k
            });
953
182k
    }
954
955
    node_t* inc()
956
191M
    {
957
191M
        refs(this).inc();
958
191M
        return this;
959
191M
    }
960
961
    const node_t* inc() const
962
    {
963
        refs(this).inc();
964
        return this;
965
    }
966
967
405M
    bool dec() const { return refs(this).dec(); }
968
969
    static void inc_nodes(node_t** p, count_t n)
970
43.9M
    {
971
197M
        for (auto i = p, e = i + n; i != e; ++i)
972
153M
            refs(*i).inc();
973
43.9M
    }
974
975
#if IMMER_TAGGED_NODE
976
    shift_t compute_shift()
977
15.5M
    {
978
15.5M
        if (kind() == kind_t::leaf)
979
1.16M
            return endshift<B, BL>;
980
14.3M
        else
981
14.3M
            return B + inner()[0]->compute_shift();
982
15.5M
    }
983
#endif
984
985
    bool check(shift_t shift, size_t size)
986
1.16M
    {
987
#if IMMER_DEBUG_DEEP_CHECK
988
        assert(size > 0);
989
        if (shift == endshift<B, BL>) {
990
            IMMER_ASSERT_TAGGED(kind() == kind_t::leaf);
991
            assert(size <= branches<BL>);
992
        } else if (auto r = relaxed()) {
993
            auto count = r->d.count;
994
            assert(count > 0);
995
            assert(count <= branches<B>);
996
            if (r->d.sizes[count - 1] != size) {
997
                IMMER_TRACE_F("check");
998
                IMMER_TRACE_E(r->d.sizes[count - 1]);
999
                IMMER_TRACE_E(size);
1000
            }
1001
            assert(r->d.sizes[count - 1] == size);
1002
            for (auto i = 1u; i < count; ++i)
1003
                assert(r->d.sizes[i - 1] < r->d.sizes[i]);
1004
            auto last_size = size_t{};
1005
            for (auto i = 0u; i < count; ++i) {
1006
                assert(inner()[i]->check(shift - B, r->d.sizes[i] - last_size));
1007
                last_size = r->d.sizes[i];
1008
            }
1009
        } else {
1010
            assert(size <= branches<B> << shift);
1011
            auto count =
1012
                (size >> shift) + (size - ((size >> shift) << shift) > 0);
1013
            assert(count <= branches<B>);
1014
            if (count) {
1015
                for (auto i = 1u; i < count - 1; ++i)
1016
                    assert(inner()[i]->check(shift - B, 1 << shift));
1017
                assert(inner()[count - 1]->check(
1018
                    shift - B, size - ((count - 1) << shift)));
1019
            }
1020
        }
1021
#endif // IMMER_DEBUG_DEEP_CHECK
1022
1.16M
        return true;
1023
1.16M
    }
1024
};
1025
1026
template <typename T, typename MP, bits_t B>
1027
constexpr bits_t derive_bits_leaf_aux()
1028
0
{
1029
0
    using node_t               = node<T, MP, B, B>;
1030
0
    constexpr auto sizeof_elem = sizeof(T);
1031
0
    constexpr auto space =
1032
0
        node_t::max_sizeof_inner - node_t::sizeof_packed_leaf_n(0);
1033
0
    constexpr auto full_elems = space / sizeof_elem;
1034
0
    constexpr auto BL         = log2(full_elems);
1035
0
    return BL;
1036
0
}
1037
1038
template <typename T, typename MP, bits_t B>
1039
constexpr bits_t derive_bits_leaf = derive_bits_leaf_aux<T, MP, B>();
1040
1041
} // namespace rbts
1042
} // namespace detail
1043
} // namespace immer
1044
1045
#if !defined(_MSC_VER)
1046
#if defined(__GNUC__) && !defined(__clang__)
1047
#pragma GCC diagnostic pop
1048
#endif
1049
#endif