Dash Core Source Documentation (0.16.0.1)

Find detailed information regarding the Dash Core source code.

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