pstore2
hamt_map_types.hpp
Go to the documentation of this file.
1 //===- include/pstore/core/hamt_map_types.hpp -------------*- mode: C++ -*-===//
2 //* _ _ _ *
3 //* | |__ __ _ _ __ ___ | |_ _ __ ___ __ _ _ __ | |_ _ _ _ __ ___ ___ *
4 //* | '_ \ / _` | '_ ` _ \| __| | '_ ` _ \ / _` | '_ \ | __| | | | '_ \ / _ \/ __| *
5 //* | | | | (_| | | | | | | |_ | | | | | | (_| | |_) | | |_| |_| | |_) | __/\__ \ *
6 //* |_| |_|\__,_|_| |_| |_|\__| |_| |_| |_|\__,_| .__/ \__|\__, | .__/ \___||___/ *
7 //* |_| |___/|_| *
8 //===----------------------------------------------------------------------===//
9 //
10 // Part of the pstore project, under the Apache License v2.0 with LLVM Exceptions.
11 // See https://github.com/SNSystems/pstore/blob/master/LICENSE.txt for license
12 // information.
13 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
14 //
15 //===----------------------------------------------------------------------===//
18 
19 #ifndef PSTORE_CORE_HAMT_MAP_TYPES_HPP
20 #define PSTORE_CORE_HAMT_MAP_TYPES_HPP
21 
25 
26 namespace pstore {
27  class transaction_base;
28 
29  namespace index {
30  namespace details {
31 
32  using hash_type = std::uint64_t;
33 
36  constexpr auto const hash_size = sizeof (hash_type) * 8;
37 
38  // TODO: Visual Studio won't allow pop_count to be constexpr. This forces us to have a
39  // second implementation that doesn't use the intrinsic.
40 
48  template <typename T, typename = typename std::enable_if_t<std::is_unsigned<T>::value>>
49  constexpr unsigned cx_pop_count (T const x) noexcept {
50  return x == 0U ? 0U : (x & 1U) + cx_pop_count (x >> 1U);
51  }
52 
53 #ifdef _MSC_VER
54  constexpr unsigned hash_index_bits = cx_pop_count (hash_size - 1);
55 #else
56  constexpr unsigned hash_index_bits = bit_count::pop_count (hash_size - 1);
57  PSTORE_STATIC_ASSERT (bit_count::pop_count (hash_size - 1) ==
58  cx_pop_count (hash_size - 1));
59 #endif
60 
61  constexpr unsigned max_hash_bits = (hash_size + 7) / hash_index_bits * hash_index_bits;
62  constexpr unsigned hash_index_mask = (1U << hash_index_bits) - 1U;
63  constexpr unsigned max_internal_depth = max_hash_bits / hash_index_bits;
64 
67  constexpr unsigned max_tree_depth = max_internal_depth + 2U;
68 
69  enum : std::uintptr_t {
70  internal_node_bit = 1U << 0U,
71  heap_node_bit = 1U << 1U,
72  };
73 
77  template <typename S, typename... Types>
78  struct is_any_of;
79  template <typename S>
80  struct is_any_of<S> : std::integral_constant<bool, false> {};
81  template <typename S, typename Head, typename... Tail>
82  struct is_any_of<S, Head, Tail...>
83  : std::integral_constant<
84  bool, std::is_same<std::remove_cv_t<S>, std::remove_cv_t<Head>>::value ||
85  is_any_of<S, Tail...>::value> {};
86 
87  } // end namespace details
88 
89  //* _ _ _ _ _ *
90  //* | |_ ___ __ _ __| |___ _ _ | |__| |___ __| |__ *
91  //* | ' \/ -_) _` / _` / -_) '_| | '_ \ / _ \/ _| / / *
92  //* |_||_\___\__,_\__,_\___|_| |_.__/_\___/\__|_\_\ *
93  //* *
96  struct header_block {
97  std::array<std::uint8_t, 8> signature;
99  std::uint64_t size;
102  };
103 
104  PSTORE_STATIC_ASSERT (sizeof (header_block) == 24);
105  PSTORE_STATIC_ASSERT (offsetof (header_block, signature) == 0);
106  PSTORE_STATIC_ASSERT (offsetof (header_block, size) == 8);
107  PSTORE_STATIC_ASSERT (offsetof (header_block, root) == 16);
108 
109  namespace details {
110 
111  constexpr std::size_t not_found = std::numeric_limits<std::size_t>::max ();
112 
113  class internal_node;
114  class linear_node;
115 
116  constexpr bool depth_is_internal_node (unsigned const shift) noexcept {
117  return shift < details::max_hash_bits;
118  }
119 
120  struct nchildren {
121  std::size_t n;
122  };
123 
124  //* _ _ _ _ *
125  //* (_)_ _ __| |_____ __ _ __ ___(_)_ _| |_ ___ _ _ *
126  //* | | ' \/ _` / -_) \ / | '_ \/ _ \ | ' \ _/ -_) '_| *
127  //* |_|_||_\__,_\___/_\_\ | .__/\___/_|_||_\__\___|_| *
128  //* |_| *
133  index_pointer () noexcept
134  : internal_{nullptr} {
135 
136  // A belt-and-braces runtime check for cases where pop_count() can't be
137  // constexpr.
138  assert (hash_index_bits == bit_count::pop_count (hash_size - 1));
139 
140  PSTORE_STATIC_ASSERT (sizeof (index_pointer) == 8);
141  PSTORE_STATIC_ASSERT (alignof (index_pointer) == 8);
142  PSTORE_STATIC_ASSERT (offsetof (index_pointer, addr_) == 0);
143  PSTORE_STATIC_ASSERT (sizeof (internal_) == sizeof (addr_));
144  PSTORE_STATIC_ASSERT (offsetof (index_pointer, internal_) == 0);
145  PSTORE_STATIC_ASSERT (sizeof (linear_) == sizeof (addr_));
146  PSTORE_STATIC_ASSERT (offsetof (index_pointer, linear_) == 0);
147  }
148  constexpr explicit index_pointer (address const a) noexcept
149  : addr_{a} {}
150  constexpr explicit index_pointer (typed_address<internal_node> const a) noexcept
151  : addr_{a.to_address ()} {}
152  constexpr explicit index_pointer (typed_address<linear_node> const a) noexcept
153  : addr_{a.to_address ()} {}
154  explicit index_pointer (internal_node * const p) noexcept
155  : internal_{tag (p)} {}
156  explicit index_pointer (linear_node * const p) noexcept
157  : linear_{tag (p)} {}
158  index_pointer (index_pointer const &) noexcept = default;
159  index_pointer (index_pointer &&) noexcept = default;
160 
161  index_pointer & operator= (index_pointer const &) = default;
162  index_pointer & operator= (index_pointer &&) noexcept = default;
163  index_pointer & operator= (address const & a) noexcept {
164  addr_ = a;
165  return *this;
166  }
167  index_pointer & operator= (typed_address<internal_node> const & a) noexcept {
168  addr_ = a.to_address ();
169  return *this;
170  }
171  index_pointer & operator= (typed_address<linear_node> const & a) noexcept {
172  addr_ = a.to_address ();
173  return *this;
174  }
175  index_pointer & operator= (internal_node * const p) noexcept {
176  internal_ = tag (p);
177  return *this;
178  }
179  index_pointer & operator= (linear_node * const l) noexcept {
180  linear_ = tag (l);
181  return *this;
182  }
183 
184  constexpr bool operator== (index_pointer const & other) const noexcept {
185  return addr_ == other.addr_;
186  }
187  constexpr bool operator!= (index_pointer const & other) const noexcept {
188  return !operator== (other);
189  }
190 
191  constexpr explicit operator bool () const noexcept { return !this->is_empty (); }
192 
193  void clear () noexcept { internal_ = nullptr; }
194 
198  bool is_internal () const noexcept {
199  return (reinterpret_cast<std::uintptr_t> (internal_) & internal_node_bit) != 0;
200  }
201 
206  bool is_linear () const noexcept { return is_internal (); }
207 
211  bool is_leaf () const noexcept { return !is_internal (); }
212 
215  bool is_heap () const noexcept {
216  return (reinterpret_cast<std::uintptr_t> (internal_) & heap_node_bit) != 0U;
217  }
218 
221  bool is_address () const noexcept { return !is_heap (); }
222 
224  constexpr bool is_empty () const noexcept { return internal_ == nullptr; }
225 
226  address to_address () const noexcept {
227  assert (is_address ());
228  return addr_;
229  }
230 
231  template <typename T, typename = typename std::enable_if_t<
233  typed_address<T> untag_address () const noexcept {
234  return typed_address<T>::make (to_address ().absolute () & ~internal_node_bit);
235  }
236 
237  template <typename Ptr, typename = typename std::enable_if_t<is_any_of<
238  typename std::pointer_traits<Ptr>::element_type,
239  internal_node, linear_node>::value>>
240  Ptr untag () const noexcept {
241  return reinterpret_cast<Ptr> (reinterpret_cast<std::uintptr_t> (internal_) &
242  ~internal_node_bit & ~heap_node_bit);
243  }
244 
245  private:
246  template <typename Ptr, typename = typename std::enable_if_t<is_any_of<
247  typename std::pointer_traits<Ptr>::element_type,
248  internal_node, linear_node>::value>>
249  static Ptr tag (Ptr t) noexcept {
250  return reinterpret_cast<Ptr> (reinterpret_cast<std::uintptr_t> (t) |
251  internal_node_bit | heap_node_bit);
252  }
253  address addr_;
254  internal_node * internal_;
255  linear_node * linear_;
256  };
257 
258  //* _ _ *
259  //* _ __ __ _ _ _ ___ _ _| |_ | |_ _ _ _ __ ___ *
260  //* | '_ \/ _` | '_/ -_) ' \ _| | _| || | '_ \/ -_) *
261  //* | .__/\__,_|_| \___|_||_\__| \__|\_, | .__/\___| *
262  //* |_| |__/|_| *
264  class parent_type {
265  public:
266  parent_type () noexcept = default;
267 
273  explicit parent_type (index_pointer const idx,
274  std::size_t const pos = not_found) noexcept
275  : node (idx)
276  , position (pos) {}
277 
278  bool operator== (parent_type const & other) const {
279  return position == other.position && node == other.node;
280  }
281  bool operator!= (parent_type const & other) const { return !operator== (other); }
282 
283  index_pointer node;
284  std::size_t position = 0;
285  };
286 
288 
289 
290  //* _ _ _ *
291  //* | (_)_ _ ___ __ _ _ _ _ _ ___ __| |___ *
292  //* | | | ' \/ -_) _` | '_| | ' \/ _ \/ _` / -_) *
293  //* |_|_|_||_\___\__,_|_| |_||_\___/\__,_\___| *
294  //* *
298  class linear_node {
299  public:
300  using iterator = address *;
301  using const_iterator = address const *;
302 
303  void * operator new (std::size_t) = delete;
304  void operator delete (void * p);
305 
306  linear_node (linear_node && rhs) noexcept = delete;
307 
308  ~linear_node () noexcept = default;
309  linear_node & operator= (linear_node const & rhs) = delete;
310  linear_node & operator= (linear_node && rhs) noexcept = delete;
311 
314 
326  static std::unique_ptr<linear_node> allocate_from (linear_node const & orig_node,
327  std::size_t extra_children);
328 
338  static std::unique_ptr<linear_node> allocate_from (database const & db,
339  index_pointer const node,
340  std::size_t extra_children);
341 
348  static std::unique_ptr<linear_node> allocate (address a, address b);
349 
364  static auto get_node (database const & db, index_pointer const node)
365  -> std::pair<std::shared_ptr<linear_node const>, linear_node const *>;
367 
370  address operator[] (std::size_t const i) const noexcept {
371  PSTORE_ASSERT (i < size_);
372  return leaves_[i];
373  }
374  address & operator[] (std::size_t const i) noexcept {
375  PSTORE_ASSERT (i < size_);
376  return leaves_[i];
377  }
379 
382 
383  iterator begin () { return leaves_; }
384  const_iterator begin () const { return leaves_; }
385  const_iterator cbegin () const { return this->begin (); }
386 
387  iterator end () { return leaves_ + size_; }
388  const_iterator end () const { return leaves_ + size_; }
389  const_iterator cend () const { return this->end (); }
391 
392 
395 
397  bool empty () const { return size_ == 0; }
399  std::size_t size () const { return size_; }
401 
404 
406  std::size_t size_bytes () const { return linear_node::size_bytes (this->size ()); }
407 
410  static constexpr std::size_t size_bytes (std::uint64_t const size) {
411  return sizeof (linear_node) - sizeof (linear_node::leaves_) +
412  sizeof (linear_node::leaves_[0]) * size;
413  }
415 
420  address flush (transaction_base & transaction) const;
421 
435 
436  template <typename KeyType, typename OtherKeyType, typename KeyEqual,
437  typename = typename std::enable_if<
439  auto lookup (database const & db, OtherKeyType const & key, KeyEqual equal) const
440  -> std::pair<index_pointer const, std::size_t>;
441 
442  private:
443  using signature_type = std::array<std::uint8_t, 8>;
444  static signature_type const node_signature_;
445 
448  void * operator new (std::size_t s, nchildren size);
449  // Non-allocating placement allocation functions.
450  void * operator new (std::size_t const size, void * const ptr) noexcept {
451  return ::operator new (size, ptr);
452  }
453 
454  void operator delete (void * p, nchildren size);
455  void operator delete (void * const p, void * const ptr) noexcept {
456  ::operator delete (p, ptr);
457  }
458 
460  explicit linear_node (std::size_t size);
461  linear_node (linear_node const & rhs);
462 
472  static std::unique_ptr<linear_node> allocate (std::size_t num_children,
473  linear_node const & from_node);
474 
475  signature_type signature_ = node_signature_;
476  std::uint64_t size_;
477  address leaves_[1];
478  };
479 
480  // lookup
481  // ~~~~~~
482  template <typename KeyType, typename OtherKeyType, typename KeyEqual, typename>
483  auto linear_node::lookup (database const & db, OtherKeyType const & key,
484  KeyEqual equal) const
485  -> std::pair<index_pointer const, std::size_t> {
486  // Linear search. TODO: perhaps we should sort the nodes and use a binary
487  // search? This would require a template compare method.
488  std::size_t cnum = 0;
489  for (auto const & child : *this) {
490  KeyType const existing_key =
491  serialize::read<KeyType> (serialize::archive::database_reader{db, child});
492  if (equal (existing_key, key)) {
493  return {index_pointer{child}, cnum};
494  }
495  ++cnum;
496  }
497  // Not found
498  return {index_pointer (), details::not_found};
499  }
500 
501 
502  //* _ _ _ _ *
503  //* (_)_ _| |_ ___ _ _ _ _ __ _| | ___ ___ __| |___ *
504  //* | | ' \ _/ -_) '_| ' \/ _` | | | \/ _ \/ _` / -_) *
505  //* |_|_||_\__\___|_| |_||_\__,_|_| |_|\_\___/\__,_\___| *
506  //* *
509  public:
510  using iterator = index_pointer *;
511  using const_iterator = index_pointer const *;
512 
514  internal_node (index_pointer const & leaf, hash_type hash);
516  internal_node (index_pointer const & existing_leaf, index_pointer const & new_leaf,
517  hash_type existing_hash, hash_type new_hash);
518 
519  internal_node (internal_node const & rhs);
520  internal_node (internal_node && rhs) = delete;
521 
522  ~internal_node () noexcept = default;
523 
524  internal_node & operator= (internal_node const & rhs) = delete;
525  internal_node & operator= (internal_node && rhs) = delete;
526 
538  template <typename SequenceContainer,
539  typename = typename std::enable_if<std::is_same<
540  typename SequenceContainer::value_type, internal_node>::value>::type>
541  static internal_node * allocate (SequenceContainer * const container,
542  internal_node const & other) {
543  container->emplace_back (other);
544  // TODO: in C++17 we can use the emplace_back return value.
545  return &container->back ();
546  }
547 
557  template <typename SequenceContainer,
558  typename = typename std::enable_if<std::is_same<
559  typename SequenceContainer::value_type, internal_node>::value>::type>
560  static internal_node * allocate (SequenceContainer * container,
561  index_pointer const & leaf, hash_type const hash) {
562  container->emplace_back (leaf, hash);
563  // TODO: in C++17 we can use the emplace_back return value.
564  return &container->back ();
565  }
566 
578  template <typename SequenceContainer,
579  typename = typename std::enable_if<std::is_same<
580  typename SequenceContainer::value_type, internal_node>::value>::type>
581  static internal_node *
582  allocate (SequenceContainer * container, index_pointer const & existing_leaf,
583  index_pointer const & new_leaf, hash_type const existing_hash,
584  hash_type const new_hash) {
585  container->emplace_back (existing_leaf, new_leaf, existing_hash, new_hash);
586  // TODO: in C++17 we can use the emplace_back return value.
587  return &container->back ();
588  }
589 
600  static auto get_node (database const & db, index_pointer node)
601  -> std::pair<std::shared_ptr<internal_node const>, internal_node const *>;
602 
604  static auto read_node (database const & db, typed_address<internal_node> addr)
605  -> std::shared_ptr<internal_node const>;
606 
623  template <typename SequenceContainer,
624  typename = typename std::enable_if<std::is_same<
625  typename SequenceContainer::value_type, internal_node>::value>::type>
626  static internal_node * make_writable (SequenceContainer * const container,
627  index_pointer const node,
628  internal_node const & internal) {
629  if (node.is_heap ()) {
630  auto * const inode = node.untag<internal_node *> ();
631  PSTORE_ASSERT (inode->signature_ == node_signature_);
632  return inode;
633  }
634 
635  return allocate (container, internal);
636  }
637 
646  static constexpr std::size_t size_bytes (std::size_t const num_children) noexcept {
647  PSTORE_ASSERT (num_children > 0 && num_children <= hash_size);
648  return sizeof (internal_node) - sizeof (internal_node::children_) +
649  sizeof (decltype (internal_node::children_[0])) * num_children;
650  }
651 
653  unsigned size () const noexcept {
654  PSTORE_ASSERT (this->bitmap_ != hash_type{0});
655  return bit_count::pop_count (this->bitmap_);
656  }
657 
659  static unsigned get_new_index (hash_type const new_hash,
660  hash_type const existing_hash) noexcept {
661  return static_cast<unsigned> (new_hash >= existing_hash);
662  }
663 
664  std::pair<index_pointer, std::size_t> lookup (hash_type hash_index) const;
665 
667  void insert_child (hash_type const hash, index_pointer const leaf,
669 
671  address flush (transaction_base & transaction, unsigned shifts);
672 
673 
674  index_pointer const & operator[] (std::size_t const i) const {
675  PSTORE_ASSERT (i < size ());
676  return children_[i];
677  }
678 
679  index_pointer & operator[] (std::size_t const i) {
680  PSTORE_ASSERT (i < size ());
681  return children_[i];
682  }
683 
684  hash_type get_bitmap () const noexcept { return bitmap_; }
687  void set_bitmap (hash_type const bm) noexcept { bitmap_ = bm; }
688 
691 
692  iterator begin () noexcept { return &children_[0]; }
693  const_iterator begin () const { return &children_[0]; }
694  const_iterator cbegin () const { return &children_[0]; }
695 
696  iterator end () noexcept { return this->begin () + this->size (); }
697  const_iterator end () const { return this->begin () + this->size (); }
698  const_iterator cend () const { return this->cbegin () + this->size (); }
700 
701  private:
702  static bool validate_after_load (internal_node const & internal,
703  typed_address<internal_node> const addr);
704 
707  address store_node (transaction_base & transaction) const;
708 
709  using signature_type = std::array<std::uint8_t, 8>;
710  static signature_type const node_signature_;
711 
714  signature_type signature_ = node_signature_;
715 
719  hash_type bitmap_ = 0;
720 
723  index_pointer children_[1U];
724  };
725 
726  // lookup
727  // ~~~~~~
728  inline auto internal_node::lookup (hash_type const hash_index) const
729  -> std::pair<index_pointer, std::size_t> {
730  PSTORE_ASSERT (hash_index < (hash_type{1} << hash_index_bits));
731  auto const bit_pos = hash_type{1} << hash_index;
732  if ((bitmap_ & bit_pos) != 0) {
733  std::size_t const index = bit_count::pop_count (bitmap_ & (bit_pos - 1U));
734  return {children_[index], index};
735  }
736  return {index_pointer{}, not_found};
737  }
738 
739 
740  } // namespace details
741  } // namespace index
742 } // namespace pstore
743 
744 #endif // PSTORE_CORE_HAMT_MAP_TYPES_HPP
Provides the database_reader and database_writer class which enable the serializer to read and write ...
std::size_t size_bytes() const
Returns the number of bytes of storage required for the node.
Definition: hamt_map_types.hpp:406
static constexpr std::size_t size_bytes(std::uint64_t const size)
Returns the number of bytes of storage required for a linear node with &#39;size&#39; children.
Definition: hamt_map_types.hpp:410
Using LSB for marking internal nodes.
Definition: hamt_map_types.hpp:71
An archive-reader which reads data from a database.
Definition: db_archive.hpp:102
bool is_internal() const noexcept
Returns true if the index_pointer is pointing to an internal node, false otherwise.
Definition: hamt_map_types.hpp:198
Definition: address.hpp:81
Provides the member constant value which is equal to true, if S the same as any of the types (after r...
Definition: hamt_map_types.hpp:78
Definition: hamt_map_types.hpp:120
parent_type(index_pointer const idx, std::size_t const pos=not_found) noexcept
Constructs a parent type object.
Definition: hamt_map_types.hpp:273
bool empty() const
Checks whether the container is empty.
Definition: hamt_map_types.hpp:397
transaction< transaction_lock > begin(database &db, transaction_lock &lock)
Creates a new transaction. Every operation performed on a transaction instance can be potentially und...
Definition: transaction.hpp:311
auto index(gsl::czstring str, std::size_t pos) -> gsl::czstring
Returns a pointer to the beginning of the pos&#39;th UTF-8 codepoint in the buffer at str or nullptr if e...
Definition: utf.cpp:49
A linear node.
Definition: hamt_map_types.hpp:298
constexpr unsigned cx_pop_count(T const x) noexcept
A function to compute the number of set bits in a value.
Definition: hamt_map_types.hpp:49
static constexpr std::size_t size_bytes(std::size_t const num_children) noexcept
Returns the number of bytes occupied by an in-store internal node with the given number of child node...
Definition: hamt_map_types.hpp:646
A class used to keep the pointer to parent node and the child slot.
Definition: hamt_map_types.hpp:264
constexpr bool is_empty() const noexcept
Returns true if the pointer is equivalent to "null".
Definition: hamt_map_types.hpp:224
Definition: transaction.hpp:191
Definition: address.hpp:231
constexpr auto const hash_size
The number of bits in hash_type.
Definition: hamt_map_types.hpp:36
A simple wrapper for std::array which provides the functionality of a stack, specifically a FILO (fir...
Definition: array_stack.hpp:39
Definition: gsl.hpp:589
static internal_node * make_writable(SequenceContainer *const container, index_pointer const node, internal_node const &internal)
Returns a writable reference to an internal node.
Definition: hamt_map_types.hpp:626
bool is_address() const noexcept
Returns true if the index_pointer is pointing to a store node, false otherwise.
Definition: hamt_map_types.hpp:221
bool is_heap() const noexcept
Returns true if the index_pointer is pointing to a heap node, false otherwise.
Definition: hamt_map_types.hpp:215
bool is_leaf() const noexcept
Returns true if the index_pointer contains the address of a value in the store, false otherwise...
Definition: hamt_map_types.hpp:211
Definition: print.cpp:18
The address of an instance of this type is passed to the hamt_map ctor to load an existing index...
Definition: hamt_map_types.hpp:96
Defines the chunked_sequence<> container.
static internal_node * allocate(SequenceContainer *container, index_pointer const &existing_leaf, index_pointer const &new_leaf, hash_type const existing_hash, hash_type const new_hash)
Construct an internal node with two children.
Definition: hamt_map_types.hpp:582
void set_bitmap(hash_type const bm) noexcept
A function for deliberately creating illegal internal nodes in the unit test.
Definition: hamt_map_types.hpp:687
An internal trie node.
Definition: hamt_map_types.hpp:508
static internal_node * allocate(SequenceContainer *container, index_pointer const &leaf, hash_type const hash)
Construct an internal node with a single child.
Definition: hamt_map_types.hpp:560
Definition: nonpod2.cpp:40
Definition: database.hpp:40
bool is_linear() const noexcept
Returns true if the index_pointer is pointing to a linear node, false otherwise.
Definition: hamt_map_types.hpp:206
array_stack is a simple container which provides an interface very similar to std::stack, but based on std::array.
std::size_t size() const
Returns the number of elements.
Definition: hamt_map_types.hpp:399
std::pair< index_pointer, std::size_t > lookup(hash_type hash_index) const
Definition: hamt_map_types.hpp:728
auto lookup(database const &db, OtherKeyType const &key, KeyEqual equal) const -> std::pair< index_pointer const, std::size_t >
Search the linear node and return the child slot if the key exists.
Definition: hamt_map_types.hpp:483
constexpr unsigned max_tree_depth
The max depth of the hash trees include several levels internal nodes (max_internal_depth), one linear node and one leaf node.
Definition: hamt_map_types.hpp:67
If the two types T1 and T2 have a compatible representation when serialized, provides the member cons...
Definition: types.hpp:321
static unsigned get_new_index(hash_type const new_hash, hash_type const existing_hash) noexcept
Return the new leaf child index number.
Definition: hamt_map_types.hpp:659
static internal_node * allocate(SequenceContainer *const container, internal_node const &other)
Construct an internal node from existing internal-node instance.
Definition: hamt_map_types.hpp:541
std::uint64_t size
The number of keys stored in the tree.
Definition: hamt_map_types.hpp:99
An index pointer is either a database address or a pointer to volatile RAM.
Definition: hamt_map_types.hpp:132
address root
The store address of the tree&#39;s root node.
Definition: hamt_map_types.hpp:101
unsigned size() const noexcept
Returns the number of children contained by this node.
Definition: hamt_map_types.hpp:653
The database transaction class.
Definition: transaction.hpp:43