/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 |