19 #ifndef PSTORE_CORE_HAMT_MAP_TYPES_HPP 20 #define PSTORE_CORE_HAMT_MAP_TYPES_HPP 27 class transaction_base;
32 using hash_type = std::uint64_t;
36 constexpr
auto const hash_size =
sizeof (hash_type) * 8;
48 template <typename T, typename = typename std::enable_if_t<std::is_unsigned<T>::value>>
54 constexpr
unsigned hash_index_bits =
cx_pop_count (hash_size - 1);
56 constexpr
unsigned hash_index_bits = bit_count::pop_count (hash_size - 1);
57 PSTORE_STATIC_ASSERT (bit_count::pop_count (hash_size - 1) ==
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;
69 enum : std::uintptr_t {
70 internal_node_bit = 1U << 0U,
77 template <
typename S,
typename... Types>
80 struct is_any_of<S> : std::integral_constant<bool, false> {};
81 template <
typename S,
typename Head,
typename... 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> {};
97 std::array<std::uint8_t, 8> signature;
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);
111 constexpr std::size_t not_found = std::numeric_limits<std::size_t>::max ();
116 constexpr
bool depth_is_internal_node (
unsigned const shift) noexcept {
117 return shift < details::max_hash_bits;
134 : internal_{
nullptr} {
138 assert (hash_index_bits == bit_count::pop_count (
hash_size - 1));
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);
151 : addr_{a.to_address ()} {}
153 : addr_{a.to_address ()} {}
155 : internal_{tag (p)} {}
157 : linear_{tag (p)} {}
168 addr_ = a.to_address ();
172 addr_ = a.to_address ();
184 constexpr
bool operator== (
index_pointer const & other)
const noexcept {
185 return addr_ == other.addr_;
187 constexpr
bool operator!= (
index_pointer const & other)
const noexcept {
188 return !operator== (other);
191 constexpr
explicit operator bool ()
const noexcept {
return !this->is_empty (); }
193 void clear () noexcept { internal_ =
nullptr; }
199 return (reinterpret_cast<std::uintptr_t> (internal_) & internal_node_bit) != 0;
206 bool is_linear () const noexcept {
return is_internal (); }
211 bool is_leaf () const noexcept {
return !is_internal (); }
216 return (reinterpret_cast<std::uintptr_t> (internal_) &
heap_node_bit) != 0U;
224 constexpr
bool is_empty () const noexcept {
return internal_ ==
nullptr; }
226 address to_address ()
const noexcept {
227 assert (is_address ());
231 template <
typename T,
typename =
typename std::enable_if_t<
237 template <
typename Ptr,
typename =
typename std::enable_if_t<
is_any_of<
238 typename std::pointer_traits<Ptr>::element_type,
240 Ptr untag ()
const noexcept {
241 return reinterpret_cast<Ptr
> (
reinterpret_cast<std::uintptr_t
> (internal_) &
246 template <
typename Ptr,
typename =
typename std::enable_if_t<
is_any_of<
247 typename std::pointer_traits<Ptr>::element_type,
249 static Ptr tag (Ptr t) noexcept {
250 return reinterpret_cast<Ptr
> (
reinterpret_cast<std::uintptr_t
> (t) |
254 internal_node * internal_;
274 std::size_t
const pos = not_found) noexcept
278 bool operator== (
parent_type const & other)
const {
279 return position == other.position && node == other.node;
281 bool operator!= (
parent_type const & other)
const {
return !operator== (other); }
284 std::size_t position = 0;
301 using const_iterator =
address const *;
303 void *
operator new (std::size_t) =
delete;
304 void operator delete (
void * p);
326 static std::unique_ptr<linear_node> allocate_from (
linear_node const & orig_node,
327 std::size_t extra_children);
338 static std::unique_ptr<linear_node> allocate_from (
database const & db,
340 std::size_t extra_children);
348 static std::unique_ptr<linear_node> allocate (
address a,
address b);
365 -> std::pair<std::shared_ptr<linear_node const>,
linear_node const *>;
370 address operator[] (std::size_t
const i)
const noexcept {
371 PSTORE_ASSERT (i < size_);
374 address & operator[] (std::size_t
const i) noexcept {
375 PSTORE_ASSERT (i < size_);
384 const_iterator
begin ()
const {
return leaves_; }
385 const_iterator cbegin ()
const {
return this->
begin (); }
387 iterator end () {
return leaves_ + size_; }
388 const_iterator end ()
const {
return leaves_ + size_; }
389 const_iterator cend ()
const {
return this->end (); }
397 bool empty ()
const {
return size_ == 0; }
399 std::size_t
size ()
const {
return size_; }
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;
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>;
443 using signature_type = std::array<std::uint8_t, 8>;
444 static signature_type
const node_signature_;
448 void *
operator new (std::size_t s,
nchildren size);
450 void *
operator new (std::size_t
const size,
void *
const ptr) noexcept {
451 return ::operator
new (size, ptr);
454 void operator delete (
void * p,
nchildren size);
455 void operator delete (
void *
const p,
void *
const ptr) noexcept {
456 ::operator
delete (p, ptr);
460 explicit linear_node (std::size_t size);
461 linear_node (linear_node
const & rhs);
472 static std::unique_ptr<linear_node> allocate (std::size_t num_children,
473 linear_node
const & from_node);
475 signature_type signature_ = node_signature_;
482 template <
typename KeyType,
typename OtherKeyType,
typename KeyEqual,
typename>
484 KeyEqual equal)
const 485 -> std::pair<index_pointer const, std::size_t> {
488 std::size_t cnum = 0;
489 for (
auto const & child : *
this) {
490 KeyType
const existing_key =
492 if (equal (existing_key, key)) {
517 hash_type existing_hash, hash_type new_hash);
538 template <
typename SequenceContainer,
539 typename =
typename std::enable_if<std::is_same<
540 typename SequenceContainer::value_type,
internal_node>::value>::type>
543 container->emplace_back (other);
545 return &container->back ();
557 template <
typename SequenceContainer,
558 typename =
typename std::enable_if<std::is_same<
559 typename SequenceContainer::value_type,
internal_node>::value>::type>
562 container->emplace_back (leaf, hash);
564 return &container->back ();
578 template <
typename SequenceContainer,
579 typename =
typename std::enable_if<std::is_same<
580 typename SequenceContainer::value_type,
internal_node>::value>::type>
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);
587 return &container->back ();
601 -> std::pair<std::shared_ptr<internal_node const>,
internal_node const *>;
605 -> std::shared_ptr<internal_node const>;
623 template <
typename SequenceContainer,
624 typename =
typename std::enable_if<std::is_same<
625 typename SequenceContainer::value_type, internal_node>::value>::type>
628 internal_node
const &
internal) {
630 auto *
const inode = node.untag<internal_node *> ();
631 PSTORE_ASSERT (inode->signature_ == node_signature_);
635 return allocate (container,
internal);
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;
653 unsigned size () const noexcept {
654 PSTORE_ASSERT (this->bitmap_ != hash_type{0});
655 return bit_count::pop_count (this->bitmap_);
660 hash_type
const existing_hash) noexcept {
661 return static_cast<unsigned> (new_hash >= existing_hash);
664 std::pair<index_pointer, std::size_t> lookup (hash_type hash_index)
const;
667 void insert_child (hash_type
const hash,
index_pointer const leaf,
674 index_pointer const & operator[] (std::size_t
const i)
const {
675 PSTORE_ASSERT (i < size ());
680 PSTORE_ASSERT (i < size ());
684 hash_type get_bitmap ()
const noexcept {
return bitmap_; }
687 void set_bitmap (hash_type
const bm) noexcept { bitmap_ = bm; }
693 const_iterator
begin ()
const {
return &children_[0]; }
694 const_iterator cbegin ()
const {
return &children_[0]; }
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 (); }
702 static bool validate_after_load (internal_node
const &
internal,
709 using signature_type = std::array<std::uint8_t, 8>;
710 static signature_type
const node_signature_;
714 signature_type signature_ = node_signature_;
719 hash_type bitmap_ = 0;
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};
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 'size' 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'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
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
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
An index pointer is either a database address or a pointer to volatile RAM.
Definition: hamt_map_types.hpp:132
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