Dash Core Source Documentation (0.16.0.1)

Find detailed information regarding the Dash Core source code.

dvektor_impl.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 
14 
15 #include <boost/intrusive_ptr.hpp>
16 #include <boost/iterator/iterator_facade.hpp>
17 #include <boost/smart_ptr/intrusive_ref_counter.hpp>
18 
19 #include <cassert>
20 #include <limits>
21 
22 namespace immer {
23 namespace detail {
24 namespace dvektor {
25 
26 constexpr auto fast_log2(std::size_t x)
27 {
28  return x == 0 ? 0 : sizeof(std::size_t) * 8 - 1 - __builtin_clzl(x);
29 }
30 
31 template <int B, typename T=std::size_t>
32 constexpr T branches = T{1} << B;
33 
34 template <int B, typename T=std::size_t>
35 constexpr T mask = branches<B, T> - 1;
36 
37 template <int B, typename T=std::size_t>
38 constexpr auto max_depth =
39  fast_log2(std::numeric_limits<std::size_t>::max()) / B;
40 
41 template <typename T, int B, typename MP>
42 struct node;
43 
44 template <typename T, int B, typename MP>
45 using node_ptr = boost::intrusive_ptr<node<T, B, MP> >;
46 
47 template <typename T, int B>
48 using leaf_node = std::array<T, 1 << B>;
49 
50 template <typename T, int B, typename MP>
51 using inner_node = std::array<node_ptr<T, B, MP>, 1 << B>;
52 
53 template <typename T, int B, typename MP>
54 struct node : enable_intrusive_ptr<node<T, B, MP>, typename MP::refcount>
55  , enable_optimized_heap_policy<node<T, B, MP>, typename MP::heap>
56 {
59 
60  enum
61  {
64  } kind;
65 
66  union data_t
67  {
70  data_t(leaf_node_t n) : leaf(std::move(n)) {}
71  data_t(inner_node_t n) : inner(std::move(n)) {}
72  ~data_t() {}
73  } data;
74 
76  {
77  switch (kind) {
78  case leaf_kind:
79  data.leaf.~leaf_node_t();
80  break;
81  case inner_kind:
82  data.inner.~inner_node_t();
83  break;
84  }
85  }
86 
88  : kind{leaf_kind}
89  , data{std::move(n)}
90  {}
91 
93  : kind{inner_kind}
94  , data{std::move(n)}
95  {}
96 
98  assert(kind == inner_kind);
99  return data.inner;
100  }
101  const inner_node_t& inner() const& {
102  assert(kind == inner_kind);
103  return data.inner;
104  }
106  assert(kind == inner_kind);
107  return std::move(data.inner);
108  }
109 
111  assert(kind == leaf_kind);
112  return data.leaf;
113  }
114  const leaf_node_t& leaf() const& {
115  assert(kind == leaf_kind);
116  return data.leaf;
117  }
118  leaf_node_t&& leaf() && {
119  assert(kind == leaf_kind);
120  return std::move(data.leaf);
121  }
122 };
123 
124 template <typename T, int B, typename MP,
125  typename ...Ts>
126 auto make_node(Ts&& ...xs)
127  -> boost::intrusive_ptr<node<T, B, MP>>
128 {
129  return new node<T, B, MP>(std::forward<Ts>(xs)...);
130 }
131 
132 template <typename T, int B, typename MP>
133 struct ref
134 {
139 
140  unsigned depth;
141  std::array<node_ptr_t, max_depth<B>> display;
142 
143  template <typename ...Ts>
144  static auto make_node(Ts&& ...xs)
145  {
146  return dvektor::make_node<T, B, MP>(std::forward<Ts>(xs)...);
147  }
148 
149  const T& get_elem(std::size_t index, std::size_t xr) const
150  {
151  auto display_idx = fast_log2(xr) / B;
152  auto node = display[display_idx].get();
153  auto shift = display_idx * B;
154  while (display_idx--) {
155  node = node->inner() [(index >> shift) & mask<B>].get();
156  shift -= B;
157  }
158  return node->leaf() [index & mask<B>];
159  }
160 
162  {
163  auto& n = node->inner();
164  auto x = node_ptr_t{};
165  x.swap(n[idx]);
166  return copy_of_inner(x);
167  }
168 
170  {
171  auto& n = node->inner();
172  auto x = node_ptr_t{};
173  x.swap(n[idx]);
174  return copy_of_leaf(x);
175  }
176 
178  {
179  return make_node(n->inner());
180  }
181 
183  {
184  return make_node(n->leaf());
185  }
186 
187  void stabilize(std::size_t index)
188  {
189  auto shift = B;
190  for (auto i = 1u; i < depth; ++i)
191  {
192  display[i] = copy_of_inner(display[i]);
193  display[i]->inner() [(index >> shift) & mask<B>]
194  = display[i - 1];
195  shift += B;
196  }
197  }
198 
200  std::size_t index,
201  std::size_t xr)
202  {
203  assert(depth);
204  auto d = depth - 1;
205  if (d == 0) {
206  display[0] = copy_of_leaf(display[0]);
207  } else {
209  display[d] = copy_of_inner(display[d]);
210  auto shift = B * d;
211  while (--d) {
213  display[d + 1],
214  (index >> shift) & mask<B>);
215  shift -= B;
216  }
218  display[1],
219  (index >> B) & mask<B>);
220  }
221  }
222 
224  std::size_t new_index,
225  std::size_t xr)
226  {
227  assert(depth);
228  if (xr < (1 << B)) {
229  display[0] = copy_of_leaf(display[0]);
230  } else {
231  auto display_idx = fast_log2(xr) / B;
232  auto shift = B;
233  for (auto i = 1u; i <= display_idx; ++i) {
234  display[i] = copy_of_inner(display[i]);
235  display[i]->inner() [(old_index >> shift) & mask<B>]
236  = display[i - 1];
237  shift += B;
238  }
239  for (auto i = display_idx - 1; i > 0; --i) {
240  shift -= B;
242  display[i + 1],
243  (new_index >> shift) & mask<B>);
244  }
246  display[1],
247  (new_index >> B) & mask<B>);
248  }
249  }
250 
252  std::size_t new_index,
253  std::size_t xr)
254  {
255  auto display_idx = fast_log2(xr) / B;
256  if (display_idx > 0) {
257  auto shift = display_idx * B;
258  if (display_idx == depth) {
259  display[display_idx] = make_node(inner_t{});
260  display[display_idx]->inner()
261  [(old_index >> shift) & mask<B>] =
262  display[display_idx - 1];
263  ++depth;
264  }
265  while (--display_idx) {
266  auto node = display[display_idx + 1]->inner()
267  [(new_index >> shift) & mask<B>];
268  display[display_idx] = node
269  ? std::move(node)
270  : make_node(inner_t{});
271 
272  }
273  display[0] = make_node(leaf_t{});
274  }
275  }
276 
278  std::size_t new_index,
279  std::size_t xr)
280  {
281  stabilize(old_index);
282  goto_fresh_pos_writable_from_clean(old_index, new_index, xr);
283  }
284 
286  {
287  auto display_idx = fast_log2(xr) / B;
288  auto shift = display_idx * B;
289  if (display_idx > 0) {
290  display[display_idx - 1] = display[display_idx]->inner()
291  [(index >> shift) & mask<B>];
292  while (--display_idx)
293  display[display_idx - 1] = display[display_idx]->inner()[0];
294  }
295  }
296 
298  {
299  auto display_idx = fast_log2(xr) / B;
300  auto shift = display_idx * B;
301  if (display_idx) {
302  do {
303  display[display_idx - 1] = display[display_idx]->inner()
304  [(index >> shift) & mask<B>];
305  shift -= B;
306  } while (--display_idx);
307  }
308  }
309 };
310 
311 template <typename T, int B, typename MP>
312 struct impl
313 {
319 
322  bool dirty;
324 
325  template <typename ...Ts>
326  static auto make_node(Ts&& ...xs)
327  {
328  return dvektor::make_node<T, B, MP>(std::forward<Ts>(xs)...);
329  }
330 
332  std::size_t new_index,
333  std::size_t xr)
334  {
335  if (dirty) {
336  p.goto_pos_writable_from_dirty(old_index, new_index, xr);
337  } else {
338  p.goto_pos_writable_from_clean(old_index, new_index, xr);
339  dirty = true;
340  }
341  }
342 
344  std::size_t new_index,
345  std::size_t xr)
346  {
347  if (dirty) {
348  p.goto_fresh_pos_writable_from_dirty(old_index, new_index, xr);
349  } else {
350  p.goto_fresh_pos_writable_from_clean(old_index, new_index, xr);
351  dirty = true;
352  }
353  }
354 
355  impl push_back(T value) const
356  {
357  if (size) {
358  auto block_index = size & ~mask<B>;
359  auto lo = size & mask<B>;
360  if (size != block_index) {
361  auto s = impl{ size + 1, block_index, dirty, p };
362  s.goto_pos_writable(focus, block_index, focus ^ block_index);
363  s.p.display[0]->leaf() [lo] = std::move(value);
364  return s;
365  } else {
366  auto s = impl{ size + 1, block_index, dirty, p };
367  s.goto_fresh_pos_writable(focus, block_index, focus ^ block_index);
368  s.p.display[0]->leaf() [lo] = std::move(value);
369  return s;
370  }
371  } else {
372  return impl{
373  1, 0, false,
374  { 1, {{ make_node(leaf_t{{std::move(value)}}) }} }
375  };
376  }
377  }
378 
379  const T& get(std::size_t index) const
380  {
381  return p.get_elem(index, index ^ focus);
382  }
383 
384  template <typename FnT>
385  impl update(std::size_t idx, FnT&& fn) const
386  {
387  auto s = impl{ size, idx, dirty, p };
388  s.goto_pos_writable(focus, idx, focus ^ idx);
389  auto& v = s.p.display[0]->leaf() [idx & mask<B>];
390  v = fn(std::move(v));
391  return s;
392  }
393 
394  impl assoc(std::size_t idx, T value) const
395  {
396  return update(idx, [&] (auto&&) {
397  return std::move(value);
398  });
399  }
400 };
401 
402 template <typename T, int B, typename MP>
404  0,
405  0,
406  false,
407  ref<T, B, MP> {1, {}}
408 };
409 
410 template <typename T, int B, typename MP>
411 struct iterator : boost::iterator_facade<
412  iterator<T, B, MP>,
413  T,
414  boost::random_access_traversal_tag,
415  const T&>
416 {
417  struct end_t {};
418 
419  iterator() = default;
420 
422  : p_{ v.p }
423  , i_{ 0 }
424  , base_{ 0 }
425  {
426  if (v.dirty)
427  p_.stabilize(v.focus);
428  p_.goto_pos(0, 0 ^ v.focus);
429  curr_ = p_.display[0]->leaf().begin();
430  }
431 
433  : p_{ v.p }
434  , i_{ v.size }
435  , base_{ (v.size-1) & ~mask<B> }
436  {
437  if (v.dirty)
438  p_.stabilize(v.focus);
439  p_.goto_pos(base_, base_ ^ v.focus);
440  curr_ = p_.display[0]->leaf().begin() + (i_ - base_);
441  }
442 
443 private:
444  friend class boost::iterator_core_access;
446 
451 
452  void increment()
453  {
454  ++i_;
455  if (i_ - base_ < branches<B>) {
456  ++curr_;
457  } else {
458  auto new_base = base_ + branches<B>;
459  p_.goto_next_block_start(new_base, base_ ^ new_base);
460  base_ = new_base;
461  curr_ = p_.display[0]->leaf().begin();
462  }
463  }
464 
465  void decrement()
466  {
467  assert(i_ > 0);
468  --i_;
469  if (i_ >= base_) {
470  --curr_;
471  } else {
472  auto new_base = base_ - branches<B>;
473  p_.goto_pos(new_base, base_ ^ new_base);
474  base_ = new_base;
475  curr_ = std::prev(p_.display[0]->leaf().end());
476  }
477  }
478 
479  void advance(std::ptrdiff_t n)
480  {
481  i_ += n;
482  if (i_ <= base_ && i_ - base_ < branches<B>) {
483  curr_ += n;
484  } else {
485  auto new_base = i_ & ~mask<B>;
486  p_.goto_pos(new_base, base_ ^ new_base);
487  base_ = new_base;
488  curr_ = p_.display[0]->leaf().begin() + (i_ - base_);
489  }
490  }
491 
492  bool equal(const iterator& other) const
493  {
494  return i_ == other.i_;
495  }
496 
497  std::ptrdiff_t distance_to(const iterator& other) const
498  {
499  return other.i_ > i_
500  ? static_cast<std::ptrdiff_t>(other.i_ - i_)
501  : - static_cast<std::ptrdiff_t>(i_ - other.i_);
502  }
503 
504  const T& dereference() const
505  {
506  return *curr_;
507  }
508 };
509 
510 } /* namespace dvektor */
511 } /* namespace detail */
512 } /* namespace immer */
static auto make_node(Ts &&...xs)
void goto_pos_writable(std::size_t old_index, std::size_t new_index, std::size_t xr)
void goto_fresh_pos_writable_from_clean(std::size_t old_index, std::size_t new_index, std::size_t xr)
void goto_pos_writable_from_clean(std::size_t old_index, std::size_t index, std::size_t xr)
impl assoc(std::size_t idx, T value) const
typename leaf_node< T, B >::const_iterator leaf_iterator
iterator(const impl< T, B, MP > &v, end_t)
std::array< node_ptr_t, max_depth< B > > display
inner_node_t & inner() &
void goto_pos_writable_from_dirty(std::size_t old_index, std::size_t new_index, std::size_t xr)
Definition: box.hpp:161
enum immer::detail::dvektor::node::@9 kind
static auto make_node(Ts &&...xs)
inner_node< T, B, MemoryPolicy > inner_t
const inner_node_t & inner() const &
void advance(std::ptrdiff_t n)
const impl< T, B, MP > empty
leaf_node< T, B > leaf_node_t
union immer::detail::dvektor::node::data_t data
node(leaf_node< T, B > n)
std::size_t size_t
Definition: bits.hpp:21
void goto_pos(std::size_t index, std::size_t xr)
inner_node_t && inner() &&
constexpr auto max_depth
leaf_node_t && leaf() &&
node_ptr_t copy_of_leaf(const node_ptr_t &n)
void goto_next_block_start(std::size_t index, std::size_t xr)
impl push_back(T value) const
inner_node< T, B, MP > inner_node_t
bool equal(const iterator &other) const
node_ptr_t null_slot_and_copy_leaf(node_ptr_t &node, std::size_t idx)
std::ptrdiff_t distance_to(const iterator &other) const
impl update(std::size_t idx, FnT &&fn) const
iterator(const impl< T, B, MP > &v)
node_ptr_t copy_of_inner(const node_ptr_t &n)
#define IMMER_UNREACHABLE
Definition: config.hpp:45
node_ptr_t null_slot_and_copy_inner(node_ptr_t &node, std::size_t idx)
const leaf_node_t & leaf() const &
const T & get_elem(std::size_t index, std::size_t xr) const
void goto_fresh_pos_writable_from_dirty(std::size_t old_index, std::size_t new_index, std::size_t xr)
auto make_node(Ts &&...xs) -> boost::intrusive_ptr< node< T, B, MP >>
std::array< T, 1<< B > leaf_node
void stabilize(std::size_t index)
boost::intrusive_ptr< node< T, B, MP > > node_ptr
std::array< node_ptr< T, B, MP >, 1<< B > inner_node
node(inner_node< T, B, MP > n)
void goto_fresh_pos_writable(std::size_t old_index, std::size_t new_index, std::size_t xr)
constexpr auto fast_log2(std::size_t x)
Released under the MIT license