@@ -601,20 +601,12 @@ namespace hud
601601 {
602602 static constexpr usize COUNT_CLONED_BYTE {group_type::SLOT_PER_GROUP - 1 };
603603
604- /* * Save the H2. */
605- static constexpr void set_h2 (control_type *control_ptr, usize slot_index, control_type h2, usize max_slot_count) noexcept
606- {
607- // Save the h2 in the slot and also in the cloned byte
608- control_ptr[slot_index] = h2;
609- control_ptr[((slot_index - COUNT_CLONED_BYTE ) & max_slot_count) + (COUNT_CLONED_BYTE & max_slot_count)] = h2;
610- }
611-
612604 /* * Set the control to deleted. */
613- static constexpr void set_deleted (control_type *control_ptr, usize slot_index, usize max_slot_count) noexcept
605+ static constexpr void set (control_type *control_ptr, usize slot_index, control_type value , usize max_slot_count) noexcept
614606 {
615607 // Save the h2 in the slot and also in the cloned byte
616- control_ptr[slot_index] = deleted_byte ;
617- control_ptr[((slot_index - COUNT_CLONED_BYTE ) & max_slot_count) + (COUNT_CLONED_BYTE & max_slot_count)] = deleted_byte ;
608+ control_ptr[slot_index] = value ;
609+ control_ptr[((slot_index - COUNT_CLONED_BYTE ) & max_slot_count) + (COUNT_CLONED_BYTE & max_slot_count)] = value ;
618610 }
619611
620612 /* * Skip all empty or deleted control. */
@@ -744,6 +736,12 @@ namespace hud
744736 private:
745737 template <typename u_slot_t , bool u_is_const>
746738 friend class iterator ;
739+ template <
740+ typename storage_t ,
741+ typename hasher_t ,
742+ typename key_equal_t ,
743+ typename allocator_t >
744+ friend class hashset_impl ;
747745
748746 // The control to iterate over
749747 control_type *control_ptr_;
@@ -1046,6 +1044,7 @@ namespace hud
10461044 iterator it = find (key);
10471045 if (it != end ())
10481046 {
1047+ remove_iterator (it);
10491048 }
10501049 }
10511050
@@ -1058,7 +1057,7 @@ namespace hud
10581057 /* * Return the slack in number of elements. */
10591058 [[nodiscard]] HD_FORCEINLINE constexpr usize slack () const noexcept
10601059 {
1061- return free_slot_before_grow_ ;
1060+ return free_slot_before_grow () ;
10621061 }
10631062
10641063 /* * Checks whether the array is empty of not. */
@@ -1106,46 +1105,42 @@ namespace hud
11061105 }
11071106
11081107 private:
1109- constexpr bool was_never_full (usize index) noexcept
1108+ constexpr bool should_be_mark_as_empty_if_deleted (usize index) noexcept
11101109 {
11111110 // If map fits entirely into a probing group.
11121111 if (max_slot_count_ <= group_type::SLOT_PER_GROUP )
11131112 {
11141113 return true ;
11151114 }
11161115
1117- const usize index_before = (index - group_type:: SLOT_PER_GROUP ) & max_slot_count_;
1116+ // Mask of empty slot of the group after index
11181117 const group_type::empty_mask empty_after = group_type {control_ptr_ + index}.mask_of_empty_slot ();
1118+ // Mask of empty slot of the group before index
1119+ const usize index_before = (index - group_type::SLOT_PER_GROUP ) & max_slot_count_;
11191120 const group_type::empty_mask empty_before = group_type {control_ptr_ + index_before}.mask_of_empty_slot ();
1120-
1121- // We count how many consecutive non empties we have to the right and to the
1122- // left of `it`. If the sum is >= kWidth then there is at least one probe
1123- // window that might have seen a full group.
1124- return empty_before && empty_after && static_cast <usize>(empty_after.trailing_zeros () + empty_after.leading_zeros ()) < group_type::SLOT_PER_GROUP ;
1125- // static bool WasNeverFull(CommonFields& c, size_t index) {
1126- // if (is_single_group(c.capacity())) {
1127- // return true;
1128- // }
1129- // const size_t index_before = (index - Group::kWidth) & c.capacity();
1130- // const auto empty_after = Group(c.control() + index).MaskEmpty();
1131- // const auto empty_before = Group(c.control() + index_before).MaskEmpty();
1132-
1133- // // We count how many consecutive non empties we have to the right and to the
1134- // // left of `it`. If the sum is >= kWidth then there is at least one probe
1135- // // window that might have seen a full group.
1136- // return empty_before && empty_after &&
1137- // static_cast<size_t>(empty_after.TrailingZeros()) +
1138- // empty_before.LeadingZeros() <
1139- // Group::kWidth;
1140- // }
1121+ // If both groups are not fully empty (i.e., contain at least one empty slot each),
1122+ // and the number of consecutive empty slots before and after the index
1123+ // doesn’t span the whole group (i.e., < SLOT_PER_GROUP),
1124+ // then a probing sequence might have crossed this position → must keep as 'deleted'.
1125+ return empty_before && empty_after && static_cast <usize>(empty_after.trailing_zeros () + empty_before.leading_zeros ()) < group_type::SLOT_PER_GROUP ;
11411126 }
11421127
11431128 constexpr void remove_iterator (iterator it) noexcept
11441129 {
11451130 // Destroy the slot then mark the contral as empty if 'it' in not in probing sequence,
11461131 // else mark the control as deleted to not break the probing sequence
1132+ const usize index = it.control_ptr_ - control_ptr_;
11471133 hud::memory::destroy_object (it.slot_ptr_ );
1148-
1134+ if (should_be_mark_as_empty_if_deleted (index))
1135+ {
1136+ control::set (control_ptr_, index, empty_byte, max_slot_count_);
1137+ free_slot_before_grow_++;
1138+ }
1139+ else
1140+ {
1141+ control::set (control_ptr_, index, deleted_byte, max_slot_count_);
1142+ free_slot_before_grow_ |= ~((~usize {}) >> 1 ); // Set the sign bit that represent the presence of delete slots
1143+ }
11491144 count_--;
11501145 }
11511146
@@ -1183,7 +1178,7 @@ namespace hud
11831178 u64 h1 {H1 (hash)};
11841179 usize slot_index {find_first_empty_or_deleted (control_ptr_, max_slot_count_, h1)};
11851180 // Save h2 in control h1 index
1186- control::set_h2 (control_ptr_, slot_index, H2 (hash), max_slot_count_);
1181+ control::set (control_ptr_, slot_index, H2 (hash), max_slot_count_);
11871182 // Copy slot
11881183 hud::memory::construct_object_at (slot_ptr_ + slot_index, *slot_ptr);
11891184 };
@@ -1234,7 +1229,7 @@ namespace hud
12341229 u64 h1 {H1 (hash)};
12351230 usize slot_index {find_first_empty_or_deleted (control_ptr_, max_slot_count_, h1)};
12361231 // Save h2 in control h1 index
1237- control::set_h2 (control_ptr_, slot_index, H2 (hash), max_slot_count_);
1232+ control::set (control_ptr_, slot_index, H2 (hash), max_slot_count_);
12381233 // Copy slot
12391234 hud::memory::construct_object_at (slot_ptr_ + slot_index, hud::move (*slot_ptr));
12401235 };
@@ -1317,7 +1312,7 @@ namespace hud
13171312 u64 h1 {H1 (hash)};
13181313 usize slot_index {find_first_empty_or_deleted (control_ptr_, max_slot_count_, h1)};
13191314 // Save h2 in control h1 index
1320- control::set_h2 (control_ptr_, slot_index, H2 (hash), max_slot_count_);
1315+ control::set (control_ptr_, slot_index, H2 (hash), max_slot_count_);
13211316 // Copy slot
13221317 hud::memory::construct_object_at (slot_ptr_ + slot_index, *slot_ptr);
13231318 };
@@ -1392,7 +1387,7 @@ namespace hud
13921387 u64 h1 {H1 (hash)};
13931388 usize slot_index {find_first_empty_or_deleted (control_ptr_, max_slot_count_, h1)};
13941389 // Save h2 in control h1 index
1395- control::set_h2 (control_ptr_, slot_index, H2 (hash), max_slot_count_);
1390+ control::set (control_ptr_, slot_index, H2 (hash), max_slot_count_);
13961391 // Copy slot
13971392 hud::memory::construct_object_at (slot_ptr_ + slot_index, hud::move (*slot_ptr));
13981393 };
@@ -1420,7 +1415,7 @@ namespace hud
14201415 other.count_ = 0 ;
14211416 max_slot_count_ = other.max_slot_count_ ;
14221417 other.max_slot_count_ = 0 ;
1423- free_slot_before_grow_ = other.free_slot_before_grow_ = 0 ;
1418+ free_slot_before_grow_ = other.free_slot_before_grow_ ;
14241419 other.free_slot_before_grow_ = 0 ;
14251420 }
14261421 }
@@ -1465,7 +1460,7 @@ namespace hud
14651460 }
14661461
14671462 /* * Insert a slot index associated with the given h2 hash. */
1468- [[nodiscard]] constexpr usize insert_no_construct (u64 h1, u64 h2) noexcept
1463+ [[nodiscard]] constexpr usize insert_no_construct (u64 h1, u8 h2) noexcept
14691464 {
14701465 // If we reach the load factor grow the table and retrieves the new slot, else use the given slot
14711466 if (free_slot_before_grow () == 0 )
@@ -1476,7 +1471,7 @@ namespace hud
14761471 // Find the first empty of deleted slot that can be used for this h1 hash
14771472 usize slot_index {find_first_empty_or_deleted (control_ptr_, max_slot_count_, h1)};
14781473 count_++;
1479- control::set_h2 (control_ptr_, slot_index, h2, max_slot_count_);
1474+ control::set (control_ptr_, slot_index, h2, max_slot_count_);
14801475
14811476 free_slot_before_grow_--;
14821477
@@ -1527,7 +1522,7 @@ namespace hud
15271522 u64 h1 {H1 (hash)};
15281523 usize slot_index {find_first_empty_or_deleted (control_ptr_, max_slot_count_, h1)};
15291524 // Save h2 in control h1 index
1530- control::set_h2 (control_ptr_, slot_index, H2 (hash), max_slot_count_);
1525+ control::set (control_ptr_, slot_index, H2 (hash), max_slot_count_);
15311526 // Move old slot to new slot
15321527 hud::memory::move_or_copy_construct_object_then_destroy (slot_ptr_ + slot_index, hud::move (*slot_ptr));
15331528 };
@@ -1538,7 +1533,8 @@ namespace hud
15381533
15391534 [[nodiscard]] constexpr usize free_slot_before_grow () const noexcept
15401535 {
1541- return free_slot_before_grow_;
1536+ // Remove the sign bit that represent if the map contains deleted slots
1537+ return free_slot_before_grow_ & ((~size_t {}) >> 1 );
15421538 }
15431539
15441540 /* * Retrieves the next capacity after a grow. */
0 commit comments