Skip to content

Commit 9cbb799

Browse files
author
Julian LALU
committed
Improve hashmap
1 parent cbe692d commit 9cbb799

4 files changed

Lines changed: 364 additions & 46 deletions

File tree

core.vscode.code-workspace

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
"cmake.options.statusBarVisibility": "compact",
2727
"cmake.outputLogEncoding": "utf8",
2828
"debug.showVariableTypes": true,
29-
"rust-analyzer.checkOnSave": false,
29+
"rust-analyzer.checkOnSave": true,
3030
},
3131
"extensions": {
3232
"recommendations": [

interface/core/containers/hashset.h

Lines changed: 41 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -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. */

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ set( src
7777
hashmap/hashmap_misc.cpp
7878
hashmap/hashmap_move_assign_operator.cpp
7979
hashmap/hashmap_move_constructors.cpp
80+
hashmap/hashmap_remove.cpp
8081
hashset/hashset_add.cpp
8182
hashset/hashset_constructors.cpp
8283
hashset/hashset_iterator.cpp

0 commit comments

Comments
 (0)