Skip to content

Commit fedb90c

Browse files
author
Julian LALU
committed
Update hashset_implt
1 parent f19507f commit fedb90c

File tree

2 files changed

+86
-45
lines changed

2 files changed

+86
-45
lines changed

interface/core/containers/hashset.h

Lines changed: 56 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -200,14 +200,14 @@ namespace hud
200200
}
201201
};
202202

203-
/** Load a 8 bytes metadata into the group. */
204-
constexpr portable_group(const control_type *metadata) noexcept
205-
: value_(hud::memory::unaligned_load64(metadata))
203+
/** Load a 8 bytes control into the group. */
204+
constexpr portable_group(const control_type *control) noexcept
205+
: value_(hud::memory::unaligned_load64(control))
206206

207207
{
208208
}
209209

210-
/**Retrieve a mask where H2 matching metadata byte have value 0x80 and non matching have value 0x00. */
210+
/**Retrieve a mask where H2 matching control byte have value 0x80 and non matching have value 0x00. */
211211
constexpr mask match(u8 h2_hash) const noexcept
212212
{
213213
// Mix of From http://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
@@ -217,7 +217,7 @@ namespace hud
217217
return mask {(x - lsbs) & ~x & 0x8080808080808080ULL};
218218
}
219219

220-
/** Retrieve a mask where empty metadata bytes have value 0x80 and others have value 0x00. */
220+
/** Retrieve a mask where empty control bytes have value 0x80 and others have value 0x00. */
221221
constexpr empty_mask mask_of_empty_slot() const noexcept
222222
{
223223
// controls are
@@ -246,7 +246,7 @@ namespace hud
246246
return (value_ & ~(value_ << 6)) & 0x8080808080808080UL;
247247
}
248248

249-
/** Retrieve a mask where empty and deleted metadata bytes have value 0x80 and others have value 0x00. */
249+
/** Retrieve a mask where empty and deleted control bytes have value 0x80 and others have value 0x00. */
250250
constexpr empty_or_deleted_mask mask_of_empty_or_deleted_slot() const noexcept
251251
{
252252
// controls are
@@ -273,7 +273,7 @@ namespace hud
273273
return (value_ & ~(value_ << 7)) & 0x8080808080808080UL;
274274
}
275275

276-
/** Retrieve a mask where full metadata bytes have value 0x80 and others have value 0x00. */
276+
/** Retrieve a mask where full control bytes have value 0x80 and others have value 0x00. */
277277
constexpr full_mask mask_of_full_slot() const noexcept
278278
{
279279
// controls are
@@ -309,7 +309,7 @@ namespace hud
309309
u64 value_;
310310
};
311311

312-
/** Group type used to iterate over the metadata. */
312+
/** Group type used to iterate over the control. */
313313
using group_type = portable_group;
314314

315315
alignas(16) constexpr const control_type INIT_GROUP[32] {
@@ -361,33 +361,40 @@ namespace hud
361361
control_ptr[((slot_index - COUNT_CLONED_BYTE) & max_slot_count) + (COUNT_CLONED_BYTE & max_slot_count)] = h2;
362362
}
363363

364-
/** Check if the metadata byte is empty. */
364+
/** Check if the control byte is empty. */
365365
[[nodiscard]]
366366
static constexpr bool is_byte_empty(control_type byte_value) noexcept
367367
{
368368
return byte_value == empty_byte;
369369
}
370370

371-
/** Check if the metadata byte is deleted. */
371+
/** Check if the control byte is deleted. */
372372
[[nodiscard]]
373373
static constexpr bool is_byte_deleted(control_type byte_value) noexcept
374374
{
375375
return byte_value == deleted_byte;
376376
}
377377

378-
/** Check if the metadata byte is empty or deleted. */
378+
/** Check if the control byte is empty or deleted. */
379379
[[nodiscard]]
380380
static constexpr bool is_byte_empty_or_deleted(control_type byte_value) noexcept
381381
{
382382
return byte_value < sentinel_byte;
383383
}
384384

385-
/** Check if the metadata byte is full. */
385+
/** Check if the control byte is full. */
386386
[[nodiscard]]
387387
static constexpr bool is_byte_full(control_type byte_value) noexcept
388388
{
389389
return byte_value >= 0;
390390
}
391+
392+
/** Check if the control byte is deleted. */
393+
[[nodiscard]]
394+
static constexpr bool is_byte_sentinel(control_type byte_value) noexcept
395+
{
396+
return byte_value == sentinel_byte;
397+
}
391398
};
392399

393400
/** The hashmap iterator that iterate over elements. */
@@ -466,7 +473,7 @@ namespace hud
466473
}
467474

468475
private:
469-
// The metadata to iterate over
476+
// The control to iterate over
470477
control_type *control_ptr_;
471478
// The current slot we are iterating. Keep uninitialized.
472479
slot_type *slot_ptr_;
@@ -620,7 +627,7 @@ namespace hud
620627
return end();
621628
}
622629

623-
// Advance to next group (Maybe a metadata iterator taht iterate over groups can be better alternative)
630+
// Advance to next group (Maybe a control iterator taht iterate over groups can be better alternative)
624631
slot_index += group_type::SLOT_PER_GROUP;
625632
slot_index &= max_slot_count_;
626633
}
@@ -664,7 +671,7 @@ namespace hud
664671

665672
/** Retrieves an iterator to the end of the array. */
666673
[[nodiscard]]
667-
constexpr const iterator begin() const noexcept
674+
constexpr const_iterator begin() const noexcept
668675
{
669676
return find_first_full();
670677
}
@@ -673,14 +680,14 @@ namespace hud
673680
[[nodiscard]]
674681
constexpr iterator end() noexcept
675682
{
676-
return iterator(control_ptr_ + max_slot_count_);
683+
return iterator(control_ptr_sentinel());
677684
}
678685

679686
/** Retrieves an iterator to the end of the array. */
680687
[[nodiscard]]
681-
constexpr const iterator end() const noexcept
688+
constexpr const_iterator end() const noexcept
682689
{
683-
return iterator(control_ptr_ + max_slot_count_);
690+
return iterator(control_ptr_sentinel());
684691
}
685692

686693
private:
@@ -750,53 +757,52 @@ namespace hud
750757

751758
// Create the buffer with control and slots
752759
// Slots are aligned on alignof(slot_type)
760+
control_type *old_control_ptr = control_ptr_;
761+
slot_type *old_slot_ptr = slot_ptr_;
762+
usize old_max_slot_count = max_slot_count_;
763+
max_slot_count_ = new_max_slot_count;
753764

754765
// We cloned size of a group - 1 because we never reach the last cloned bytes
755766
constexpr const usize num_cloned_bytes = control::COUNT_CLONED_BYTE;
756767
// Control size is the number of slot + sentinel + number of cloned bytes
757-
const usize control_size = new_max_slot_count + 1 + num_cloned_bytes;
768+
const usize control_size = max_slot_count_ + 1 + num_cloned_bytes;
758769
const uptr aligned_control_size = hud::memory::align_address(control_size, sizeof(slot_type));
759-
const usize aligned_allocation_size = aligned_control_size + new_max_slot_count * sizeof(slot_type);
760-
761-
// Allocate the buffer that will contains controls and aligned slots
762-
memory_allocation_type allocation = allocator_.template allocate<slot_type>(aligned_allocation_size);
770+
const usize aligned_allocation_size = aligned_control_size + max_slot_count_ * sizeof(slot_type);
763771

764-
// Save control and slot pointers
765-
control_type *new_control_ptr = hud::bit_cast<control_type *>(allocation.data());
766-
slot_type *new_slot_ptr = hud::bit_cast<slot_type *>(new_control_ptr + aligned_control_size);
767-
hud::check(hud::memory::is_pointer_aligned(new_slot_ptr, alignof(slot_type)));
772+
// Allocate the buffer that will contains controls and aligned slots
773+
control_ptr_ = hud::bit_cast<control_type *>(allocator_.template allocate<slot_type>(aligned_allocation_size).data());
774+
slot_ptr_ = hud::bit_cast<slot_type *>(control_ptr_ + aligned_control_size);
775+
hud::check(hud::memory::is_pointer_aligned(slot_ptr_, alignof(slot_type)));
768776

769777
// Update number of slot we should put into the table before a resizing rehash
770-
free_slot_before_grow_ = max_slot_before_grow(new_max_slot_count) - count_;
778+
free_slot_before_grow_ = max_slot_before_grow(max_slot_count_) - count_;
771779

772-
// Reset control metadata
773-
hud::memory::set(new_control_ptr, control_size, empty_byte);
774-
new_control_ptr[new_max_slot_count] = sentinel_byte;
780+
// Set control to empty ending with sentinel
781+
hud::memory::set(control_ptr_, control_size, empty_byte);
782+
control_ptr_[max_slot_count_] = sentinel_byte;
775783

776784
// If we have elements, insert them to the new buffer
777785
if (count_ > 0)
778786
{
779787
// Move elements to new buffer if any
780788
// Relocate slots to newly allocated buffer
781-
for (auto &slot : *this)
789+
for (auto it = const_iterator {old_control_ptr, old_slot_ptr};
790+
it != const_iterator(old_control_ptr + old_max_slot_count);
791+
++it)
782792
{
783793
// Compute the hash
784-
u64 hash = hasher_type {}(slot.key());
794+
u64 hash = hasher_type {}(it->key());
785795
// Find H1 slot index
786796
u64 h1 = H1(hash);
787-
usize slot_index = find_first_empty_or_deleted(new_control_ptr, new_max_slot_count, h1);
797+
usize slot_index = find_first_empty_or_deleted(control_ptr_, old_max_slot_count, h1);
788798
// Save h2 in control h1 index
789-
control::set_h2(new_control_ptr, slot_index, H2(hash), new_max_slot_count);
799+
control::set_h2(control_ptr_, slot_index, H2(hash), old_max_slot_count);
790800
// Move old slot to new slot
791-
hud::memory::move_or_copy_construct_then_destroy(new_slot_ptr + slot_index, hud::move(slot));
801+
hud::memory::move_or_copy_construct_then_destroy(slot_ptr_ + slot_index, hud::move(*it));
792802
}
793803
// Free old buffer
794-
allocator_.template free<slot_type>({hud::bit_cast<slot_type *>(control_ptr_), current_allocation_size()});
804+
allocator_.template free<slot_type>({hud::bit_cast<slot_type *>(old_control_ptr), current_allocation_size()});
795805
}
796-
797-
control_ptr_ = new_control_ptr;
798-
slot_ptr_ = new_slot_ptr;
799-
max_slot_count_ = new_max_slot_count;
800806
}
801807

802808
[[nodiscard]] constexpr usize free_slot_before_grow() const noexcept
@@ -860,7 +866,7 @@ namespace hud
860866
return {control_ptr_ + first_full_index, slot_ptr_ + first_full_index};
861867
}
862868

863-
// Advance to next group (Maybe a metadata iterator that iterate over groups can be better alternative)
869+
// Advance to next group (Maybe a control iterator that iterate over groups can be better alternative)
864870
slot_index += group_type::SLOT_PER_GROUP;
865871
}
866872
return end();
@@ -884,8 +890,15 @@ namespace hud
884890
return group_type::SLOT_PER_GROUP == 8 && capacity == 7 ? 6 : capacity - capacity / 8;
885891
}
886892

893+
[[nodiscard]]
894+
constexpr control_type *control_ptr_sentinel() const noexcept
895+
{
896+
hud::check(control::is_byte_sentinel(control_ptr_[max_slot_count_]));
897+
return control_ptr_ + max_slot_count_;
898+
}
899+
887900
private:
888-
/** The metadata of the hashmap. */
901+
/** The control of the hashmap. */
889902
control_type *control_ptr_ {const_cast<control_type *>(&INIT_GROUP[16])};
890903

891904
/** Pointer to the slot segment. */

test/hashmap/hashmap_insert.cpp

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,36 @@ GTEST_TEST(hashmap, add_by_copy_construct_bitwise_copy_constructible_type)
8484
hud_assert_eq(std::get<4>(second_element_result), 1u);
8585
}
8686
// Constant
87-
{
88-
}
87+
// {
88+
// constexpr auto result = test();
89+
90+
// // First element is correctly added
91+
// const auto first_element_result = std::get<0>(result);
92+
// hud_assert_eq(std::get<0>(first_element_result).key(), 1u);
93+
// hud_assert_eq(std::get<0>(first_element_result).value(), 11u);
94+
// hud_assert_eq(std::get<1>(first_element_result), 1u);
95+
// hud_assert_eq(std::get<2>(first_element_result), 1u);
96+
// hud_assert_eq(std::get<3>(first_element_result), 1u);
97+
// hud_assert_eq(std::get<4>(first_element_result), 0u);
98+
99+
// // Same element
100+
// const auto same_element_result = std::get<1>(result);
101+
// hud_assert_eq(std::get<0>(same_element_result).key(), 1u);
102+
// hud_assert_eq(std::get<0>(same_element_result).value(), 11u);
103+
// hud_assert_eq(std::get<1>(same_element_result), 1u);
104+
// hud_assert_eq(std::get<2>(same_element_result), 1u);
105+
// hud_assert_eq(std::get<3>(same_element_result), 1u);
106+
// hud_assert_eq(std::get<4>(same_element_result), 0u);
107+
108+
// // 2nd element
109+
// const auto second_element_result = std::get<2>(result);
110+
// hud_assert_eq(std::get<0>(second_element_result).key(), 2u);
111+
// hud_assert_eq(std::get<0>(second_element_result).value(), 22u);
112+
// hud_assert_eq(std::get<1>(second_element_result), 2u);
113+
// hud_assert_eq(std::get<2>(second_element_result), 3u);
114+
// hud_assert_eq(std::get<3>(second_element_result), 2u);
115+
// hud_assert_eq(std::get<4>(second_element_result), 1u);
116+
// }
89117
// hud::hashmap<i32, u64> map;
90118
// hud_assert_eq(map.insert_to_ref(1, 11), 11);
91119
// u64 res1 = map.insert_to_ref(2, 22);

0 commit comments

Comments
 (0)