/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 | 497k | { |
99 | 497k | return std::max(sizeof(values_t), |
100 | 497k | immer_offsetof(values_t, d.buffer) + |
101 | 497k | sizeof(values_data_t::buffer) * count); |
102 | 497k | } |
103 | | |
104 | | constexpr static std::size_t sizeof_collision_n(count_t count) |
105 | 12.1k | { |
106 | 12.1k | return immer_offsetof(impl_t, d.data.collision.buffer) + |
107 | 12.1k | sizeof(collision_t::buffer) * count; |
108 | 12.1k | } |
109 | | |
110 | | constexpr static std::size_t sizeof_inner_n(count_t count) |
111 | 9.18M | { |
112 | 9.18M | return immer_offsetof(impl_t, d.data.inner.buffer) + |
113 | 9.18M | sizeof(inner_t::buffer) * count; |
114 | 9.18M | } |
115 | | |
116 | | #if IMMER_TAGGED_NODE |
117 | 85.4M | kind_t kind() const { return impl.d.kind; } |
118 | | #endif |
119 | | |
120 | | auto values() |
121 | 2.84M | { |
122 | 2.84M | IMMER_ASSERT_TAGGED(kind() == kind_t::inner); |
123 | 2.84M | assert(impl.d.data.inner.values); |
124 | 2.84M | return (T*) &impl.d.data.inner.values->d.buffer; |
125 | 2.84M | } |
126 | | |
127 | | auto values() const |
128 | 4.36M | { |
129 | 4.36M | IMMER_ASSERT_TAGGED(kind() == kind_t::inner); |
130 | 4.36M | assert(impl.d.data.inner.values); |
131 | 4.36M | return (const T*) &impl.d.data.inner.values->d.buffer; |
132 | 4.36M | } |
133 | | |
134 | | auto children() |
135 | 14.4M | { |
136 | 14.4M | IMMER_ASSERT_TAGGED(kind() == kind_t::inner); |
137 | 14.4M | return (node_t**) &impl.d.data.inner.buffer; |
138 | 14.4M | } |
139 | | |
140 | | auto children() const |
141 | 4.17M | { |
142 | 4.17M | IMMER_ASSERT_TAGGED(kind() == kind_t::inner); |
143 | 4.17M | return (const node_t* const*) &impl.d.data.inner.buffer; |
144 | 4.17M | } |
145 | | |
146 | | auto datamap() const |
147 | 13.6M | { |
148 | 13.6M | IMMER_ASSERT_TAGGED(kind() == kind_t::inner); |
149 | 13.6M | return impl.d.data.inner.datamap; |
150 | 13.6M | } |
151 | | |
152 | | auto nodemap() const |
153 | 24.7M | { |
154 | 24.7M | IMMER_ASSERT_TAGGED(kind() == kind_t::inner); |
155 | 24.7M | return impl.d.data.inner.nodemap; |
156 | 24.7M | } |
157 | | |
158 | | auto data_count() const |
159 | 1.13M | { |
160 | 1.13M | IMMER_ASSERT_TAGGED(kind() == kind_t::inner); |
161 | 1.13M | return popcount(datamap()); |
162 | 1.13M | } |
163 | | |
164 | | auto data_count(bitmap_t bit) const |
165 | 4.71M | { |
166 | 4.71M | IMMER_ASSERT_TAGGED(kind() == kind_t::inner); |
167 | 4.71M | return popcount(static_cast<bitmap_t>(datamap() & (bit - 1))); |
168 | 4.71M | } |
169 | | |
170 | | auto children_count() const |
171 | 3.44M | { |
172 | 3.44M | IMMER_ASSERT_TAGGED(kind() == kind_t::inner); |
173 | 3.44M | return popcount(nodemap()); |
174 | 3.44M | } |
175 | | |
176 | | auto children_count(bitmap_t bit) const |
177 | 8.64M | { |
178 | 8.64M | IMMER_ASSERT_TAGGED(kind() == kind_t::inner); |
179 | 8.64M | return popcount(static_cast<bitmap_t>(nodemap() & (bit - 1))); |
180 | 8.64M | } |
181 | | |
182 | | auto collision_count() const |
183 | 81.2k | { |
184 | 81.2k | IMMER_ASSERT_TAGGED(kind() == kind_t::collision); |
185 | 81.2k | return impl.d.data.collision.count; |
186 | 81.2k | } |
187 | | |
188 | | T* collisions() |
189 | 50.1k | { |
190 | 50.1k | IMMER_ASSERT_TAGGED(kind() == kind_t::collision); |
191 | 50.1k | return (T*) &impl.d.data.collision.buffer; |
192 | 50.1k | } |
193 | | |
194 | | const T* collisions() const |
195 | 80.1k | { |
196 | 80.1k | IMMER_ASSERT_TAGGED(kind() == kind_t::collision); |
197 | 80.1k | return (const T*) &impl.d.data.collision.buffer; |
198 | 80.1k | } |
199 | | |
200 | | static refs_t& refs(const values_t* x) |
201 | 1.26M | { |
202 | 1.26M | return auto_const_cast(get<refs_t>(*x)); |
203 | 1.26M | } |
204 | | static const ownee_t& ownee(const values_t* x) { return get<ownee_t>(*x); } |
205 | | static ownee_t& ownee(values_t* x) { return get<ownee_t>(*x); } |
206 | | static bool can_mutate(values_t* x, edit_t e) |
207 | | { |
208 | | return refs(x).unique() || ownee(x).can_mutate(e); |
209 | | } |
210 | | |
211 | | static refs_t& refs(const node_t* x) |
212 | 12.5M | { |
213 | 12.5M | return auto_const_cast(get<refs_t>(x->impl)); |
214 | 12.5M | } |
215 | | static const ownee_t& ownee(const node_t* x) |
216 | | { |
217 | | return get<ownee_t>(x->impl); |
218 | | } |
219 | | static ownee_t& ownee(node_t* x) { return get<ownee_t>(x->impl); } |
220 | | |
221 | | bool can_mutate(edit_t e) const |
222 | | { |
223 | | return refs(this).unique() || ownee(this).can_mutate(e); |
224 | | } |
225 | | bool can_mutate_values(edit_t e) const |
226 | | { |
227 | | return can_mutate(impl.d.data.inner.values, e); |
228 | | } |
229 | | |
230 | | static node_t* make_inner_n_into(void* buffer, std::size_t size, count_t n) |
231 | 3.06M | { |
232 | 3.06M | assert(n <= branches<B>); |
233 | 3.06M | assert(size >= sizeof_inner_n(n)); |
234 | 3.06M | auto p = new (buffer) node_t; |
235 | 3.06M | #if IMMER_TAGGED_NODE |
236 | 3.06M | p->impl.d.kind = node_t::kind_t::inner; |
237 | 3.06M | #endif |
238 | 3.06M | p->impl.d.data.inner.nodemap = 0; |
239 | 3.06M | p->impl.d.data.inner.datamap = 0; |
240 | 3.06M | p->impl.d.data.inner.values = nullptr; |
241 | 3.06M | return p; |
242 | 3.06M | } |
243 | | |
244 | | static node_t* make_inner_n(count_t n) |
245 | 3.06M | { |
246 | 3.06M | assert(n <= branches<B>); |
247 | 3.06M | auto m = heap::allocate(sizeof_inner_n(n)); |
248 | 3.06M | return make_inner_n_into(m, sizeof_inner_n(n), n); |
249 | 3.06M | } |
250 | | |
251 | | static node_t* make_inner_n(count_t n, values_t* values) |
252 | 2.50M | { |
253 | 2.50M | auto p = make_inner_n(n); |
254 | 2.50M | if (values) { |
255 | 1.26M | p->impl.d.data.inner.values = values; |
256 | 1.26M | refs(values).inc(); |
257 | 1.26M | } |
258 | 2.50M | return p; |
259 | 2.50M | } |
260 | | |
261 | | static node_t* make_inner_n(count_t n, count_t nv) |
262 | 504k | { |
263 | 504k | assert(nv <= branches<B>); |
264 | 504k | auto p = make_inner_n(n); |
265 | 504k | if (nv) { |
266 | 497k | IMMER_TRY { |
267 | 497k | p->impl.d.data.inner.values = |
268 | 497k | new (heap::allocate(sizeof_values_n(nv))) values_t{}; |
269 | 497k | } |
270 | 497k | IMMER_CATCH (...) { |
271 | 0 | deallocate_inner(p, n); |
272 | 0 | IMMER_RETHROW; |
273 | 0 | } |
274 | 497k | } |
275 | 504k | return p; |
276 | 504k | } |
277 | | |
278 | | static node_t* make_inner_n(count_t n, count_t idx, node_t* child) |
279 | 48.2k | { |
280 | 48.2k | assert(n >= 1); |
281 | 48.2k | auto p = make_inner_n(n); |
282 | 48.2k | p->impl.d.data.inner.nodemap = bitmap_t{1u} << idx; |
283 | 48.2k | p->children()[0] = child; |
284 | 48.2k | return p; |
285 | 48.2k | } |
286 | | |
287 | | static node_t* make_inner_n(count_t n, bitmap_t bitmap, T x) |
288 | 195 | { |
289 | 195 | auto p = make_inner_n(n, 1); |
290 | 195 | p->impl.d.data.inner.datamap = bitmap; |
291 | 195 | IMMER_TRY { |
292 | 195 | new (p->values()) T{std::move(x)}; |
293 | 195 | } |
294 | 195 | IMMER_CATCH (...) { |
295 | 0 | deallocate_inner(p, n, 1); |
296 | 0 | IMMER_RETHROW; |
297 | 0 | } |
298 | 0 | return p; |
299 | 195 | } |
300 | | |
301 | | static node_t* |
302 | | make_inner_n(count_t n, count_t idx1, T x1, count_t idx2, T x2) |
303 | 29.8k | { |
304 | 29.8k | assert(idx1 != idx2); |
305 | 29.8k | auto p = make_inner_n(n, 2); |
306 | 29.8k | p->impl.d.data.inner.datamap = |
307 | 29.8k | (bitmap_t{1u} << idx1) | (bitmap_t{1u} << idx2); |
308 | 29.8k | auto assign = [&](auto&& x1, auto&& x2) { |
309 | 29.8k | auto vp = p->values(); |
310 | 29.8k | IMMER_TRY { |
311 | 29.8k | new (vp) T{std::move(x1)}; |
312 | 29.8k | IMMER_TRY { |
313 | 29.8k | new (vp + 1) T{std::move(x2)}; |
314 | 29.8k | } |
315 | 29.8k | IMMER_CATCH (...) { |
316 | 0 | immer::detail::hamts::destroy_at(vp); |
317 | 0 | IMMER_RETHROW; |
318 | 0 | } |
319 | 29.8k | } |
320 | 29.8k | IMMER_CATCH (...) { |
321 | 0 | deallocate_inner(p, n, 2); |
322 | 0 | IMMER_RETHROW; |
323 | 0 | } |
324 | 29.8k | }; |
325 | 29.8k | if (idx1 < idx2) |
326 | 10.6k | assign(x1, x2); |
327 | 19.2k | else |
328 | 19.2k | assign(x2, x1); |
329 | 29.8k | return p; |
330 | 29.8k | } |
331 | | |
332 | | static node_t* make_collision_n(count_t n) |
333 | 10.4k | { |
334 | 10.4k | auto m = heap::allocate(sizeof_collision_n(n)); |
335 | 10.4k | auto p = new (m) node_t; |
336 | 10.4k | #if IMMER_TAGGED_NODE |
337 | 10.4k | p->impl.d.kind = node_t::kind_t::collision; |
338 | 10.4k | #endif |
339 | 10.4k | p->impl.d.data.collision.count = n; |
340 | 10.4k | return p; |
341 | 10.4k | } |
342 | | |
343 | | static node_t* make_collision(T v1, T v2) |
344 | 1.72k | { |
345 | 1.72k | auto m = heap::allocate(sizeof_collision_n(2)); |
346 | 1.72k | auto p = new (m) node_t; |
347 | 1.72k | #if IMMER_TAGGED_NODE |
348 | 1.72k | p->impl.d.kind = node_t::kind_t::collision; |
349 | 1.72k | #endif |
350 | 1.72k | p->impl.d.data.collision.count = 2; |
351 | 1.72k | auto cols = p->collisions(); |
352 | 1.72k | IMMER_TRY { |
353 | 1.72k | new (cols) T{std::move(v1)}; |
354 | 1.72k | IMMER_TRY { |
355 | 1.72k | new (cols + 1) T{std::move(v2)}; |
356 | 1.72k | } |
357 | 1.72k | IMMER_CATCH (...) { |
358 | 0 | cols->~T(); |
359 | 0 | IMMER_RETHROW; |
360 | 0 | } |
361 | 1.72k | } |
362 | 1.72k | IMMER_CATCH (...) { |
363 | 0 | deallocate_collision(p, 2); |
364 | 0 | IMMER_RETHROW; |
365 | 0 | } |
366 | 0 | return p; |
367 | 1.72k | } |
368 | | |
369 | | T* ensure_mutable_values(edit_t e) |
370 | | { |
371 | | assert(can_mutate(e)); |
372 | | auto old = impl.d.data.inner.values; |
373 | | if (node_t::can_mutate(old, e)) |
374 | | return values(); |
375 | | else { |
376 | | auto nv = data_count(); |
377 | | auto nxt = new (heap::allocate(sizeof_values_n(nv))) values_t{}; |
378 | | auto dst = (T*) &nxt->d.buffer; |
379 | | auto src = values(); |
380 | | ownee(nxt) = e; |
381 | | IMMER_TRY { |
382 | | detail::uninitialized_copy(src, src + nv, dst); |
383 | | } |
384 | | IMMER_CATCH (...) { |
385 | | deallocate_values(nxt, nv); |
386 | | IMMER_RETHROW; |
387 | | } |
388 | | impl.d.data.inner.values = nxt; |
389 | | if (refs(old).dec()) |
390 | | delete_values(old, nv); |
391 | | return dst; |
392 | | } |
393 | | } |
394 | | |
395 | | static node_t* copy_collision_insert(node_t* src, T v) |
396 | 703 | { |
397 | 703 | IMMER_ASSERT_TAGGED(src->kind() == kind_t::collision); |
398 | 703 | auto n = src->collision_count(); |
399 | 703 | auto dst = make_collision_n(n + 1); |
400 | 703 | auto srcp = src->collisions(); |
401 | 703 | auto dstp = dst->collisions(); |
402 | 703 | IMMER_TRY { |
403 | 703 | new (dstp) T{std::move(v)}; |
404 | 703 | IMMER_TRY { |
405 | 703 | detail::uninitialized_copy(srcp, srcp + n, dstp + 1); |
406 | 703 | } |
407 | 703 | IMMER_CATCH (...) { |
408 | 0 | dstp->~T(); |
409 | 0 | IMMER_RETHROW; |
410 | 0 | } |
411 | 703 | } |
412 | 703 | IMMER_CATCH (...) { |
413 | 0 | deallocate_collision(dst, n + 1); |
414 | 0 | IMMER_RETHROW; |
415 | 0 | } |
416 | 0 | return dst; |
417 | 703 | } |
418 | | |
419 | | static node_t* move_collision_insert(node_t* src, T v) |
420 | | { |
421 | | IMMER_ASSERT_TAGGED(src->kind() == kind_t::collision); |
422 | | auto n = src->collision_count(); |
423 | | auto dst = make_collision_n(n + 1); |
424 | | auto srcp = src->collisions(); |
425 | | auto dstp = dst->collisions(); |
426 | | IMMER_TRY { |
427 | | new (dstp) T{std::move(v)}; |
428 | | IMMER_TRY { |
429 | | detail::uninitialized_move(srcp, srcp + n, dstp + 1); |
430 | | } |
431 | | IMMER_CATCH (...) { |
432 | | dstp->~T(); |
433 | | IMMER_RETHROW; |
434 | | } |
435 | | } |
436 | | IMMER_CATCH (...) { |
437 | | deallocate_collision(dst, n + 1); |
438 | | IMMER_RETHROW; |
439 | | } |
440 | | delete_collision(src); |
441 | | return dst; |
442 | | } |
443 | | |
444 | | static node_t* copy_collision_remove(node_t* src, T* v) |
445 | 1.21k | { |
446 | 1.21k | IMMER_ASSERT_TAGGED(src->kind() == kind_t::collision); |
447 | 1.21k | assert(src->collision_count() > 1); |
448 | 1.21k | auto n = src->collision_count(); |
449 | 1.21k | auto dst = make_collision_n(n - 1); |
450 | 1.21k | auto srcp = src->collisions(); |
451 | 1.21k | auto dstp = dst->collisions(); |
452 | 1.21k | IMMER_TRY { |
453 | 1.21k | dstp = detail::uninitialized_copy(srcp, v, dstp); |
454 | 1.21k | IMMER_TRY { |
455 | 1.21k | detail::uninitialized_copy(v + 1, srcp + n, dstp); |
456 | 1.21k | } |
457 | 1.21k | IMMER_CATCH (...) { |
458 | 0 | detail::destroy(dst->collisions(), dstp); |
459 | 0 | IMMER_RETHROW; |
460 | 0 | } |
461 | 1.21k | } |
462 | 1.21k | IMMER_CATCH (...) { |
463 | 0 | deallocate_collision(dst, n - 1); |
464 | 0 | IMMER_RETHROW; |
465 | 0 | } |
466 | 0 | return dst; |
467 | 1.21k | } |
468 | | |
469 | | static node_t* move_collision_remove(node_t* src, T* v) |
470 | | { |
471 | | IMMER_ASSERT_TAGGED(src->kind() == kind_t::collision); |
472 | | assert(src->collision_count() > 1); |
473 | | auto n = src->collision_count(); |
474 | | auto dst = make_collision_n(n - 1); |
475 | | auto srcp = src->collisions(); |
476 | | auto dstp = dst->collisions(); |
477 | | IMMER_TRY { |
478 | | dstp = detail::uninitialized_move(srcp, v, dstp); |
479 | | IMMER_TRY { |
480 | | detail::uninitialized_move(v + 1, srcp + n, dstp); |
481 | | } |
482 | | IMMER_CATCH (...) { |
483 | | detail::destroy(dst->collisions(), dstp); |
484 | | IMMER_RETHROW; |
485 | | } |
486 | | } |
487 | | IMMER_CATCH (...) { |
488 | | deallocate_collision(dst, n - 1); |
489 | | IMMER_RETHROW; |
490 | | } |
491 | | delete_collision(src); |
492 | | return dst; |
493 | | } |
494 | | |
495 | | static node_t* copy_collision_replace(node_t* src, T* pos, T v) |
496 | 8.53k | { |
497 | 8.53k | IMMER_ASSERT_TAGGED(src->kind() == kind_t::collision); |
498 | 8.53k | auto n = src->collision_count(); |
499 | 8.53k | auto dst = make_collision_n(n); |
500 | 8.53k | auto srcp = src->collisions(); |
501 | 8.53k | auto dstp = dst->collisions(); |
502 | 8.53k | assert(pos >= srcp && pos < srcp + n); |
503 | 8.53k | IMMER_TRY { |
504 | 8.53k | new (dstp) T{std::move(v)}; |
505 | 8.53k | IMMER_TRY { |
506 | 8.53k | dstp = detail::uninitialized_copy(srcp, pos, dstp + 1); |
507 | 8.53k | IMMER_TRY { |
508 | 8.53k | detail::uninitialized_copy(pos + 1, srcp + n, dstp); |
509 | 8.53k | } |
510 | 8.53k | IMMER_CATCH (...) { |
511 | 0 | detail::destroy(dst->collisions(), dstp); |
512 | 0 | IMMER_RETHROW; |
513 | 0 | } |
514 | 8.53k | } |
515 | 8.53k | IMMER_CATCH (...) { |
516 | 0 | dst->collisions()->~T(); |
517 | 0 | IMMER_RETHROW; |
518 | 0 | } |
519 | 8.53k | } |
520 | 8.53k | IMMER_CATCH (...) { |
521 | 0 | deallocate_collision(dst, n); |
522 | 0 | IMMER_RETHROW; |
523 | 0 | } |
524 | 0 | return dst; |
525 | 8.53k | } |
526 | | |
527 | | static node_t* |
528 | | copy_inner_replace(node_t* src, count_t offset, node_t* child) |
529 | 2.50M | { |
530 | 2.50M | IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner); |
531 | 2.50M | auto n = src->children_count(); |
532 | 2.50M | auto dst = make_inner_n(n, src->impl.d.data.inner.values); |
533 | 2.50M | auto srcp = src->children(); |
534 | 2.50M | auto dstp = dst->children(); |
535 | 2.50M | dst->impl.d.data.inner.datamap = src->datamap(); |
536 | 2.50M | dst->impl.d.data.inner.nodemap = src->nodemap(); |
537 | 2.50M | std::copy(srcp, srcp + n, dstp); |
538 | 2.50M | inc_nodes(srcp, offset); |
539 | 2.50M | inc_nodes(srcp + offset + 1, n - offset - 1); |
540 | 2.50M | dstp[offset] = child; |
541 | 2.50M | return dst; |
542 | 2.50M | } |
543 | | |
544 | | static node_t* owned(node_t* n, edit_t e) |
545 | | { |
546 | | ownee(n) = e; |
547 | | return n; |
548 | | } |
549 | | |
550 | | static node_t* owned_values(node_t* n, edit_t e) |
551 | | { |
552 | | ownee(n) = e; |
553 | | ownee(n->impl.d.data.inner.values) = e; |
554 | | return n; |
555 | | } |
556 | | |
557 | | static node_t* owned_values_safe(node_t* n, edit_t e) |
558 | | { |
559 | | ownee(n) = e; |
560 | | if (n->impl.d.data.inner.values) |
561 | | ownee(n->impl.d.data.inner.values) = e; |
562 | | return n; |
563 | | } |
564 | | |
565 | | static node_t* copy_inner_replace_value(node_t* src, count_t offset, T v) |
566 | 390k | { |
567 | 390k | IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner); |
568 | 390k | assert(offset < src->data_count()); |
569 | 390k | auto n = src->children_count(); |
570 | 390k | auto nv = src->data_count(); |
571 | 390k | auto dst = make_inner_n(n, nv); |
572 | 390k | dst->impl.d.data.inner.datamap = src->datamap(); |
573 | 390k | dst->impl.d.data.inner.nodemap = src->nodemap(); |
574 | 390k | IMMER_TRY { |
575 | 390k | detail::uninitialized_copy( |
576 | 390k | src->values(), src->values() + nv, dst->values()); |
577 | 390k | IMMER_TRY { |
578 | 390k | dst->values()[offset] = std::move(v); |
579 | 390k | } |
580 | 390k | IMMER_CATCH (...) { |
581 | 0 | detail::destroy_n(dst->values(), nv); |
582 | 0 | IMMER_RETHROW; |
583 | 0 | } |
584 | 390k | } |
585 | 390k | IMMER_CATCH (...) { |
586 | 0 | deallocate_inner(dst, n, nv); |
587 | 0 | IMMER_RETHROW; |
588 | 0 | } |
589 | 0 | inc_nodes(src->children(), n); |
590 | 0 | std::copy(src->children(), src->children() + n, dst->children()); |
591 | 0 | return dst; |
592 | 390k | } |
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 | 31.5k | { |
599 | 31.5k | IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner); |
600 | 31.5k | assert(!(src->nodemap() & bit)); |
601 | 31.5k | assert(src->datamap() & bit); |
602 | 31.5k | assert(voffset == src->data_count(bit)); |
603 | 31.5k | auto n = src->children_count(); |
604 | 31.5k | auto nv = src->data_count(); |
605 | 31.5k | auto dst = make_inner_n(n + 1, nv - 1); |
606 | 31.5k | auto noffset = src->children_count(bit); |
607 | 31.5k | dst->impl.d.data.inner.datamap = src->datamap() & ~bit; |
608 | 31.5k | dst->impl.d.data.inner.nodemap = src->nodemap() | bit; |
609 | 31.5k | if (nv > 1) { |
610 | 24.5k | IMMER_TRY { |
611 | 24.5k | detail::uninitialized_copy( |
612 | 24.5k | src->values(), src->values() + voffset, dst->values()); |
613 | 24.5k | IMMER_TRY { |
614 | 24.5k | detail::uninitialized_copy(src->values() + voffset + 1, |
615 | 24.5k | src->values() + nv, |
616 | 24.5k | dst->values() + voffset); |
617 | 24.5k | } |
618 | 24.5k | IMMER_CATCH (...) { |
619 | 0 | detail::destroy_n(dst->values(), voffset); |
620 | 0 | IMMER_RETHROW; |
621 | 0 | } |
622 | 24.5k | } |
623 | 24.5k | IMMER_CATCH (...) { |
624 | 0 | deallocate_inner(dst, n + 1, nv - 1); |
625 | 0 | IMMER_RETHROW; |
626 | 0 | } |
627 | 24.5k | } |
628 | 7.03k | inc_nodes(src->children(), n); |
629 | 7.03k | std::copy(src->children(), src->children() + noffset, dst->children()); |
630 | 7.03k | std::copy(src->children() + noffset, |
631 | 7.03k | src->children() + n, |
632 | 7.03k | dst->children() + noffset + 1); |
633 | 7.03k | dst->children()[noffset] = node; |
634 | 7.03k | return dst; |
635 | 31.5k | } |
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 | | { |
640 | | IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner); |
641 | | assert(!(src->nodemap() & bit)); |
642 | | assert(src->datamap() & bit); |
643 | | assert(voffset == src->data_count(bit)); |
644 | | auto n = src->children_count(); |
645 | | auto nv = src->data_count(); |
646 | | auto dst = make_inner_n(n + 1, nv - 1); |
647 | | auto noffset = src->children_count(bit); |
648 | | dst->impl.d.data.inner.datamap = src->datamap() & ~bit; |
649 | | dst->impl.d.data.inner.nodemap = src->nodemap() | bit; |
650 | | if (nv > 1) { |
651 | | auto mutate_values = can_mutate(src->impl.d.data.inner.values, e); |
652 | | IMMER_TRY { |
653 | | if (mutate_values) |
654 | | detail::uninitialized_move( |
655 | | src->values(), src->values() + voffset, dst->values()); |
656 | | else |
657 | | detail::uninitialized_copy( |
658 | | src->values(), src->values() + voffset, dst->values()); |
659 | | IMMER_TRY { |
660 | | if (mutate_values) |
661 | | detail::uninitialized_move(src->values() + voffset + 1, |
662 | | src->values() + nv, |
663 | | dst->values() + voffset); |
664 | | else |
665 | | detail::uninitialized_copy(src->values() + voffset + 1, |
666 | | src->values() + nv, |
667 | | dst->values() + voffset); |
668 | | } |
669 | | IMMER_CATCH (...) { |
670 | | detail::destroy_n(dst->values(), voffset); |
671 | | IMMER_RETHROW; |
672 | | } |
673 | | } |
674 | | IMMER_CATCH (...) { |
675 | | deallocate_inner(dst, n + 1, nv - 1); |
676 | | IMMER_RETHROW; |
677 | | } |
678 | | } |
679 | | // inc_nodes(src->children(), n); |
680 | | std::copy(src->children(), src->children() + noffset, dst->children()); |
681 | | std::copy(src->children() + noffset, |
682 | | src->children() + n, |
683 | | dst->children() + noffset + 1); |
684 | | dst->children()[noffset] = node; |
685 | | delete_inner(src); |
686 | | return dst; |
687 | | } |
688 | | |
689 | | static node_t* copy_inner_replace_inline(node_t* src, |
690 | | bitmap_t bit, |
691 | | count_t noffset, |
692 | | T value) |
693 | 2.16k | { |
694 | 2.16k | IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner); |
695 | 2.16k | assert(!(src->datamap() & bit)); |
696 | 2.16k | assert(src->nodemap() & bit); |
697 | 2.16k | assert(noffset == src->children_count(bit)); |
698 | 2.16k | auto n = src->children_count(); |
699 | 2.16k | auto nv = src->data_count(); |
700 | 2.16k | auto dst = make_inner_n(n - 1, nv + 1); |
701 | 2.16k | auto voffset = src->data_count(bit); |
702 | 2.16k | dst->impl.d.data.inner.nodemap = src->nodemap() & ~bit; |
703 | 2.16k | dst->impl.d.data.inner.datamap = src->datamap() | bit; |
704 | 2.16k | IMMER_TRY { |
705 | 2.16k | if (nv) |
706 | 1.15k | detail::uninitialized_copy( |
707 | 1.15k | src->values(), src->values() + voffset, dst->values()); |
708 | 2.16k | IMMER_TRY { |
709 | 2.16k | new (dst->values() + voffset) T{std::move(value)}; |
710 | 2.16k | IMMER_TRY { |
711 | 2.16k | if (nv) |
712 | 1.15k | detail::uninitialized_copy(src->values() + voffset, |
713 | 1.15k | src->values() + nv, |
714 | 1.15k | dst->values() + voffset + 1); |
715 | 2.16k | } |
716 | 2.16k | IMMER_CATCH (...) { |
717 | 0 | dst->values()[voffset].~T(); |
718 | 0 | IMMER_RETHROW; |
719 | 0 | } |
720 | 2.16k | } |
721 | 2.16k | IMMER_CATCH (...) { |
722 | 0 | detail::destroy_n(dst->values(), voffset); |
723 | 0 | IMMER_RETHROW; |
724 | 0 | } |
725 | 2.16k | } |
726 | 2.16k | IMMER_CATCH (...) { |
727 | 0 | deallocate_inner(dst, n - 1, nv + 1); |
728 | 0 | IMMER_RETHROW; |
729 | 0 | } |
730 | 0 | inc_nodes(src->children(), noffset); |
731 | 0 | inc_nodes(src->children() + noffset + 1, n - noffset - 1); |
732 | 0 | std::copy(src->children(), src->children() + noffset, dst->children()); |
733 | 0 | std::copy(src->children() + noffset + 1, |
734 | 0 | src->children() + n, |
735 | 0 | dst->children() + noffset); |
736 | 0 | return dst; |
737 | 2.16k | } |
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 | | { |
742 | | IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner); |
743 | | assert(!(src->datamap() & bit)); |
744 | | assert(src->nodemap() & bit); |
745 | | assert(noffset == src->children_count(bit)); |
746 | | auto n = src->children_count(); |
747 | | auto nv = src->data_count(); |
748 | | auto dst = make_inner_n(n - 1, nv + 1); |
749 | | auto voffset = src->data_count(bit); |
750 | | dst->impl.d.data.inner.nodemap = src->nodemap() & ~bit; |
751 | | dst->impl.d.data.inner.datamap = src->datamap() | bit; |
752 | | IMMER_TRY { |
753 | | auto mutate_values = |
754 | | nv && can_mutate(src->impl.d.data.inner.values, e); |
755 | | if (nv) { |
756 | | if (mutate_values) |
757 | | detail::uninitialized_move( |
758 | | src->values(), src->values() + voffset, dst->values()); |
759 | | else |
760 | | detail::uninitialized_copy( |
761 | | src->values(), src->values() + voffset, dst->values()); |
762 | | } |
763 | | IMMER_TRY { |
764 | | new (dst->values() + voffset) T{std::move(value)}; |
765 | | IMMER_TRY { |
766 | | if (nv) { |
767 | | if (mutate_values) |
768 | | detail::uninitialized_move(src->values() + voffset, |
769 | | src->values() + nv, |
770 | | dst->values() + voffset + |
771 | | 1); |
772 | | else |
773 | | detail::uninitialized_copy(src->values() + voffset, |
774 | | src->values() + nv, |
775 | | dst->values() + voffset + |
776 | | 1); |
777 | | } |
778 | | } |
779 | | IMMER_CATCH (...) { |
780 | | dst->values()[voffset].~T(); |
781 | | IMMER_RETHROW; |
782 | | } |
783 | | } |
784 | | IMMER_CATCH (...) { |
785 | | detail::destroy_n(dst->values(), voffset); |
786 | | IMMER_RETHROW; |
787 | | } |
788 | | } |
789 | | IMMER_CATCH (...) { |
790 | | deallocate_inner(dst, n - 1, nv + 1); |
791 | | IMMER_RETHROW; |
792 | | } |
793 | | std::copy(src->children(), src->children() + noffset, dst->children()); |
794 | | std::copy(src->children() + noffset + 1, |
795 | | src->children() + n, |
796 | | dst->children() + noffset); |
797 | | delete_inner(src); |
798 | | return dst; |
799 | | } |
800 | | |
801 | | static node_t* |
802 | | copy_inner_remove_value(node_t* src, bitmap_t bit, count_t voffset) |
803 | 979 | { |
804 | 979 | IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner); |
805 | 979 | assert(!(src->nodemap() & bit)); |
806 | 979 | assert(src->datamap() & bit); |
807 | 979 | assert(voffset == src->data_count(bit)); |
808 | 979 | auto n = src->children_count(); |
809 | 979 | auto nv = src->data_count(); |
810 | 979 | auto dst = make_inner_n(n, nv - 1); |
811 | 979 | dst->impl.d.data.inner.datamap = src->datamap() & ~bit; |
812 | 979 | dst->impl.d.data.inner.nodemap = src->nodemap(); |
813 | 979 | if (nv > 1) { |
814 | 726 | IMMER_TRY { |
815 | 726 | detail::uninitialized_copy( |
816 | 726 | src->values(), src->values() + voffset, dst->values()); |
817 | 726 | IMMER_TRY { |
818 | 726 | detail::uninitialized_copy(src->values() + voffset + 1, |
819 | 726 | src->values() + nv, |
820 | 726 | dst->values() + voffset); |
821 | 726 | } |
822 | 726 | IMMER_CATCH (...) { |
823 | 0 | detail::destroy_n(dst->values(), voffset); |
824 | 0 | IMMER_RETHROW; |
825 | 0 | } |
826 | 726 | } |
827 | 726 | IMMER_CATCH (...) { |
828 | 0 | deallocate_inner(dst, n, nv - 1); |
829 | 0 | IMMER_RETHROW; |
830 | 0 | } |
831 | 726 | } |
832 | 253 | inc_nodes(src->children(), n); |
833 | 253 | std::copy(src->children(), src->children() + n, dst->children()); |
834 | 253 | return dst; |
835 | 979 | } |
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 | | { |
842 | | IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner); |
843 | | assert(!(src->nodemap() & bit)); |
844 | | assert(src->datamap() & bit); |
845 | | assert(voffset == src->data_count(bit)); |
846 | | auto n = src->children_count(); |
847 | | auto nv = src->data_count(); |
848 | | auto dst = make_inner_n(n, nv - 1); |
849 | | dst->impl.d.data.inner.datamap = src->datamap() & ~bit; |
850 | | dst->impl.d.data.inner.nodemap = src->nodemap(); |
851 | | if (nv > 1) { |
852 | | auto mutate_values = can_mutate(src->impl.d.data.inner.values, e); |
853 | | if (mutate_values) { |
854 | | IMMER_TRY { |
855 | | detail::uninitialized_move( |
856 | | src->values(), src->values() + voffset, dst->values()); |
857 | | IMMER_TRY { |
858 | | detail::uninitialized_move(src->values() + voffset + 1, |
859 | | src->values() + nv, |
860 | | dst->values() + voffset); |
861 | | } |
862 | | IMMER_CATCH (...) { |
863 | | detail::destroy_n(dst->values(), voffset); |
864 | | IMMER_RETHROW; |
865 | | } |
866 | | } |
867 | | IMMER_CATCH (...) { |
868 | | deallocate_inner(dst, n, nv - 1); |
869 | | IMMER_RETHROW; |
870 | | } |
871 | | } else { |
872 | | IMMER_TRY { |
873 | | detail::uninitialized_copy( |
874 | | src->values(), src->values() + voffset, dst->values()); |
875 | | IMMER_TRY { |
876 | | detail::uninitialized_copy(src->values() + voffset + 1, |
877 | | src->values() + nv, |
878 | | dst->values() + voffset); |
879 | | } |
880 | | IMMER_CATCH (...) { |
881 | | detail::destroy_n(dst->values(), voffset); |
882 | | IMMER_RETHROW; |
883 | | } |
884 | | } |
885 | | IMMER_CATCH (...) { |
886 | | deallocate_inner(dst, n, nv - 1); |
887 | | IMMER_RETHROW; |
888 | | } |
889 | | } |
890 | | } |
891 | | std::copy(src->children(), src->children() + n, dst->children()); |
892 | | delete_inner(src); |
893 | | return dst; |
894 | | } |
895 | | |
896 | | static node_t* copy_inner_insert_value(node_t* src, bitmap_t bit, T v) |
897 | 49.8k | { |
898 | 49.8k | IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner); |
899 | 49.8k | auto n = src->children_count(); |
900 | 49.8k | auto nv = src->data_count(); |
901 | 49.8k | auto offset = src->data_count(bit); |
902 | 49.8k | auto dst = make_inner_n(n, nv + 1); |
903 | 49.8k | dst->impl.d.data.inner.datamap = src->datamap() | bit; |
904 | 49.8k | dst->impl.d.data.inner.nodemap = src->nodemap(); |
905 | 49.8k | IMMER_TRY { |
906 | 49.8k | if (nv) |
907 | 39.9k | detail::uninitialized_copy( |
908 | 39.9k | src->values(), src->values() + offset, dst->values()); |
909 | 49.8k | IMMER_TRY { |
910 | 49.8k | new (dst->values() + offset) T{std::move(v)}; |
911 | 49.8k | IMMER_TRY { |
912 | 49.8k | if (nv) |
913 | 39.9k | detail::uninitialized_copy(src->values() + offset, |
914 | 39.9k | src->values() + nv, |
915 | 39.9k | dst->values() + offset + 1); |
916 | 49.8k | } |
917 | 49.8k | IMMER_CATCH (...) { |
918 | 0 | dst->values()[offset].~T(); |
919 | 0 | IMMER_RETHROW; |
920 | 0 | } |
921 | 49.8k | } |
922 | 49.8k | IMMER_CATCH (...) { |
923 | 0 | detail::destroy_n(dst->values(), offset); |
924 | 0 | IMMER_RETHROW; |
925 | 0 | } |
926 | 49.8k | } |
927 | 49.8k | IMMER_CATCH (...) { |
928 | 0 | deallocate_inner(dst, n, nv + 1); |
929 | 0 | IMMER_RETHROW; |
930 | 0 | } |
931 | 0 | inc_nodes(src->children(), n); |
932 | 0 | std::copy(src->children(), src->children() + n, dst->children()); |
933 | 0 | return dst; |
934 | 49.8k | } |
935 | | |
936 | | static node_t* |
937 | | move_inner_insert_value(edit_t e, node_t* src, bitmap_t bit, T v) |
938 | | { |
939 | | IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner); |
940 | | auto n = src->children_count(); |
941 | | auto nv = src->data_count(); |
942 | | auto offset = src->data_count(bit); |
943 | | auto dst = make_inner_n(n, nv + 1); |
944 | | dst->impl.d.data.inner.datamap = src->datamap() | bit; |
945 | | dst->impl.d.data.inner.nodemap = src->nodemap(); |
946 | | IMMER_TRY { |
947 | | auto mutate_values = |
948 | | nv && can_mutate(src->impl.d.data.inner.values, e); |
949 | | if (nv) { |
950 | | if (mutate_values) |
951 | | detail::uninitialized_move( |
952 | | src->values(), src->values() + offset, dst->values()); |
953 | | else |
954 | | detail::uninitialized_copy( |
955 | | src->values(), src->values() + offset, dst->values()); |
956 | | } |
957 | | IMMER_TRY { |
958 | | new (dst->values() + offset) T{std::move(v)}; |
959 | | IMMER_TRY { |
960 | | if (nv) { |
961 | | if (mutate_values) |
962 | | detail::uninitialized_move(src->values() + offset, |
963 | | src->values() + nv, |
964 | | dst->values() + offset + |
965 | | 1); |
966 | | else |
967 | | detail::uninitialized_copy(src->values() + offset, |
968 | | src->values() + nv, |
969 | | dst->values() + offset + |
970 | | 1); |
971 | | } |
972 | | } |
973 | | IMMER_CATCH (...) { |
974 | | dst->values()[offset].~T(); |
975 | | IMMER_RETHROW; |
976 | | } |
977 | | } |
978 | | IMMER_CATCH (...) { |
979 | | detail::destroy_n(dst->values(), offset); |
980 | | IMMER_RETHROW; |
981 | | } |
982 | | } |
983 | | IMMER_CATCH (...) { |
984 | | deallocate_inner(dst, n, nv + 1); |
985 | | IMMER_RETHROW; |
986 | | } |
987 | | std::copy(src->children(), src->children() + n, dst->children()); |
988 | | delete_inner(src); |
989 | | return dst; |
990 | | } |
991 | | |
992 | | static node_t* |
993 | | make_merged(shift_t shift, T v1, hash_t hash1, T v2, hash_t hash2) |
994 | 79.8k | { |
995 | 79.8k | if (shift < max_shift<hash_t, B>) { |
996 | 78.1k | auto idx1 = hash1 & (mask<hash_t, B> << shift); |
997 | 78.1k | auto idx2 = hash2 & (mask<hash_t, B> << shift); |
998 | 78.1k | if (idx1 == idx2) { |
999 | 48.2k | auto merged = make_merged( |
1000 | 48.2k | shift + B, std::move(v1), hash1, std::move(v2), hash2); |
1001 | 48.2k | IMMER_TRY { |
1002 | 48.2k | return make_inner_n( |
1003 | 48.2k | 1, static_cast<count_t>(idx1 >> shift), merged); |
1004 | 48.2k | } |
1005 | 48.2k | IMMER_CATCH (...) { |
1006 | 0 | delete_deep_shift(merged, shift + B); |
1007 | 0 | IMMER_RETHROW; |
1008 | 0 | } |
1009 | 48.2k | } else { |
1010 | 29.8k | return make_inner_n(0, |
1011 | 29.8k | static_cast<count_t>(idx1 >> shift), |
1012 | 29.8k | std::move(v1), |
1013 | 29.8k | static_cast<count_t>(idx2 >> shift), |
1014 | 29.8k | std::move(v2)); |
1015 | 29.8k | } |
1016 | 78.1k | } else { |
1017 | 1.72k | return make_collision(std::move(v1), std::move(v2)); |
1018 | 1.72k | } |
1019 | 79.8k | } |
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 | | { |
1024 | | if (shift < max_shift<hash_t, B>) { |
1025 | | auto idx1 = hash1 & (mask<hash_t, B> << shift); |
1026 | | auto idx2 = hash2 & (mask<hash_t, B> << shift); |
1027 | | if (idx1 == idx2) { |
1028 | | auto merged = make_merged_e( |
1029 | | e, shift + B, std::move(v1), hash1, std::move(v2), hash2); |
1030 | | IMMER_TRY { |
1031 | | return owned( |
1032 | | make_inner_n( |
1033 | | 1, static_cast<count_t>(idx1 >> shift), merged), |
1034 | | e); |
1035 | | } |
1036 | | IMMER_CATCH (...) { |
1037 | | delete_deep_shift(merged, shift + B); |
1038 | | IMMER_RETHROW; |
1039 | | } |
1040 | | } else { |
1041 | | auto r = make_inner_n(0, |
1042 | | static_cast<count_t>(idx1 >> shift), |
1043 | | std::move(v1), |
1044 | | static_cast<count_t>(idx2 >> shift), |
1045 | | std::move(v2)); |
1046 | | return owned_values(r, e); |
1047 | | } |
1048 | | } else { |
1049 | | return owned(make_collision(std::move(v1), std::move(v2)), e); |
1050 | | } |
1051 | | } |
1052 | | |
1053 | | node_t* inc() |
1054 | 508k | { |
1055 | 508k | refs(this).inc(); |
1056 | 508k | return this; |
1057 | 508k | } |
1058 | | |
1059 | | const node_t* inc() const |
1060 | | { |
1061 | | refs(this).inc(); |
1062 | | return this; |
1063 | | } |
1064 | | |
1065 | 993k | bool dec() const { return refs(this).dec(); } |
1066 | | |
1067 | | static void inc_nodes(node_t** p, count_t n) |
1068 | 5.49M | { |
1069 | 16.5M | for (auto i = p, e = i + n; i != e; ++i) |
1070 | 11.0M | refs(*i).inc(); |
1071 | 5.49M | } |
1072 | | |
1073 | | static void delete_values(values_t* p, count_t n) |
1074 | 0 | { |
1075 | 0 | assert(p); |
1076 | 0 | detail::destroy_n((T*) &p->d.buffer, n); |
1077 | 0 | deallocate_values(p, n); |
1078 | 0 | } |
1079 | | |
1080 | | static void delete_inner(node_t* p) |
1081 | 0 | { |
1082 | 0 | assert(p); |
1083 | 0 | IMMER_ASSERT_TAGGED(p->kind() == kind_t::inner); |
1084 | 0 | auto vp = p->impl.d.data.inner.values; |
1085 | 0 | if (vp && refs(vp).dec()) |
1086 | 0 | delete_values(vp, p->data_count()); |
1087 | 0 | deallocate_inner(p, p->children_count()); |
1088 | 0 | } |
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 | 0 | { |
1101 | 0 | if (s == max_depth<hash_t, B>) |
1102 | 0 | delete_collision(p); |
1103 | 0 | else { |
1104 | 0 | auto fst = p->children(); |
1105 | 0 | auto lst = fst + p->children_count(); |
1106 | 0 | for (; fst != lst; ++fst) |
1107 | 0 | if ((*fst)->dec()) |
1108 | 0 | delete_deep(*fst, s + 1); |
1109 | 0 | delete_inner(p); |
1110 | 0 | } |
1111 | 0 | } |
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 | 0 | { |
1129 | 0 | heap::deallocate(node_t::sizeof_values_n(n), p); |
1130 | 0 | } |
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 | 0 | { |
1139 | 0 | heap::deallocate(node_t::sizeof_inner_n(n), p); |
1140 | 0 | } |
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 |