Skip to content

Commit 90c0452

Browse files
author
Julian LALU
committed
Improve Hashset
1 parent c5a9e54 commit 90c0452

2 files changed

Lines changed: 76 additions & 98 deletions

File tree

interface/core/containers/hashmap.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,11 @@ namespace hud
342342
{
343343
return super::add(hud::forward<key_type>(key), hud::forward<key_type>(value));
344344
}
345+
346+
template<typename key_tuple_t, typename value_tuple_t>
347+
constexpr iterator add(hud::tag_piecewise_construct_t, key_tuple_t key_tuple, value_tuple_t value_tuple) noexcept
348+
{
349+
}
345350
};
346351

347352
/**

interface/core/containers/hashset.h

Lines changed: 71 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@
2323
// Add hasher and equal object added in compressed_pair like compressed_pair<allocator, compressed_pair<hasher, compressed_pair<equal, common>>>
2424
// Maybe create a compressed_tuple? ;)
2525

26+
// Hashset
27+
// Difference with STL:
28+
// - Don't use is_transparent because we don't have the nessecity to keep compatibility with existing code.
29+
// Comparaison and hasher is always transparent if the user provide a custom equal or hasher type.
30+
2631
namespace hud
2732
{
2833
namespace details::hashset
@@ -281,50 +286,6 @@ namespace hud
281286
key_type element_;
282287
};
283288

284-
// /**
285-
// * A default hasher struct for hashing keys.
286-
// * This struct provides a mechanism to hash key and combine them with the current hasher value.
287-
// *
288-
// * @tparam key_t The type of the key to be hashed.
289-
// */
290-
// struct default_hasher
291-
// {
292-
// using is_transparent = void;
293-
294-
// /**
295-
// * Operator to hash the value and combine it with the current hasher value.
296-
// * This function uses variadic templates to accept multiple arguments.
297-
// * @tparam type_t Types of the arguments to hash.
298-
// * @param values Arguments to hash.
299-
// * @return A 64-bit hash value.
300-
// */
301-
// template<typename... type_t>
302-
// [[nodiscard]] constexpr u64 operator()(type_t &&...values) noexcept
303-
// {
304-
// return hud::hash_64<hud::decay_t<type_t>...> {}(hud::forward<type_t>(values)...);
305-
// }
306-
307-
// /**
308-
// * Function to hash the value and combine it with the current hasher value.
309-
// * This function uses variadic templates to accept multiple arguments.
310-
// * @tparam type_t Types of the arguments to hash.
311-
// * @param values Arguments to hash.
312-
// * @return A 64-bit hash value.
313-
// */
314-
// template<typename... type_t>
315-
// [[nodiscard]] constexpr u64 hash(type_t &&...values) noexcept
316-
// {
317-
// return (*this)(hud::forward<type_t>(values)...);
318-
// }
319-
// };
320-
321-
// template<typename key_t>
322-
// struct default_equal
323-
// : hud::equal<key_t>
324-
// {
325-
// using is_transparent = void;
326-
// };
327-
328289
using default_allocator = hud::heap_allocator;
329290

330291
/** Retrives the H1 (57 first bit) of a hash. */
@@ -824,11 +785,10 @@ namespace hud
824785
/** The type of allocation done by the allocator. */
825786
using memory_allocation_type = typename allocator_type::template memory_allocation_type<slot_type>;
826787

827-
template<typename K>
828-
using key_arg_type = typename KeyArg<hud::is_transparent_v<hasher_type> && hud::is_transparent_v<key_equal_type>>::template type<K, key_type>;
829-
830788
static_assert(hud::is_hashable_64_v<key_type>, "key_type is not hashable");
831789
static_assert(hud::is_comparable_with_equal_v<key_type, key_type>, "key_type is not comparable with equal");
790+
template<typename K>
791+
using key_arg_type = typename KeyArg<hud::is_hashable_64_v<K> && hud::is_comparable_with_equal_v<key_type, K>>::template type<K, key_type>;
832792

833793
template<typename u_storage_t, typename u_hasher_t, typename u_key_equal_t, typename u_allocator_t>
834794
friend class hashset_impl; // Friend with other hashset_impl of other types
@@ -1005,36 +965,13 @@ namespace hud
1005965
/** Find a key and return an iterator to the value. */
1006966
template<typename K>
1007967
[[nodiscard]]
1008-
constexpr iterator find(const K &key) noexcept
968+
constexpr iterator find(K &&key) noexcept
1009969
{
1010-
u64 hash {hasher_(key)};
1011-
u64 h1(H1(hash));
1012-
hud::check(hud::bits::is_valid_power_of_two_mask(max_slot_count_) && "Not a mask");
1013-
usize slot_index(h1 & max_slot_count_);
1014-
while (true)
970+
if constexpr (hud::is_hashable_64_v<K> && hud::is_comparable_with_equal_v<key_type, K>)
1015971
{
1016-
group_type group {control_ptr_ + slot_index};
1017-
group_type::mask group_mask_that_match_h2 {group.match(H2(hash))};
1018-
for (u32 group_index_that_match_h2 : group_mask_that_match_h2)
1019-
{
1020-
usize slot_index_that_match_h2 {slot_index + group_index_that_match_h2 & max_slot_count_};
1021-
slot_type *slot_that_match_h2 {slot_ptr_ + slot_index_that_match_h2};
1022-
if (key_equal_(slot_that_match_h2->key(), key)) [[likely]]
1023-
{
1024-
return {control_ptr_ + slot_index_that_match_h2, slot_that_match_h2};
1025-
}
1026-
}
1027-
1028-
// If we have free slot, we don't find it
1029-
if (group.mask_of_empty_slot().has_empty_slot())
1030-
{
1031-
return iterator {control_ptr_sentinel()};
1032-
}
1033-
1034-
// Advance to next group (Maybe a control iterator that iterate over groups can be better alternative)
1035-
slot_index += group_type::SLOT_PER_GROUP;
1036-
slot_index &= max_slot_count_;
972+
return find_impl(hud::forward<K>(key));
1037973
}
974+
return find_impl(key_type(key));
1038975
}
1039976

1040977
constexpr void rehash(i32 count) noexcept
@@ -1067,25 +1004,25 @@ namespace hud
10671004
rehash(0);
10681005
}
10691006

1070-
template<typename K = key_type>
1007+
template<typename K>
10711008
[[nodiscard]]
1072-
constexpr const_iterator find(const key_arg_type<K> &key) const noexcept
1009+
constexpr const_iterator find(K &&key) const noexcept
10731010
{
1074-
return const_cast<hashset_impl *>(this)->find(key);
1011+
return const_cast<hashset_impl *>(this)->find(hud::forward<K>(key));
10751012
}
10761013

1077-
template<typename K = key_type>
1014+
template<typename K>
10781015
[[nodiscard]]
1079-
constexpr bool contains(const key_arg_type<K> &key) noexcept
1016+
constexpr bool contains(K &&key) noexcept
10801017
{
1081-
return find(key) != end();
1018+
return find(hud::forward<K>(key)) != end();
10821019
}
10831020

1084-
template<typename K = key_type>
1021+
template<typename K>
10851022
[[nodiscard]]
1086-
constexpr bool contains(const key_arg_type<K> &key) const noexcept
1023+
constexpr bool contains(K &&key) const noexcept
10871024
{
1088-
return find(key) != end();
1025+
return const_cast<hashset_impl *>(this)->contains(hud::forward<K>(key));
10891026
}
10901027

10911028
constexpr void swap(hashset_impl &other) noexcept
@@ -1105,10 +1042,10 @@ namespace hud
11051042
hud::swap(other.free_slot_before_grow_, free_slot_before_grow_);
11061043
}
11071044

1108-
template<typename K = key_type>
1109-
constexpr void remove(const key_arg_type<K> &key) noexcept
1045+
template<typename K>
1046+
constexpr void remove(K &&key) noexcept
11101047
{
1111-
iterator it = find(key);
1048+
iterator it = find(hud::forward<K>(key));
11121049
if (it != end())
11131050
{
11141051
remove_iterator(it);
@@ -1174,10 +1111,11 @@ namespace hud
11741111

11751112
protected:
11761113
/**
1177-
* Insert a key in the hashset and pass
1178-
* @param key The key associated with the `value`
1179-
* @param args List of arguments pass to `value_type` constructor after the `key` itself
1180-
* @return Iterator to the `value`
1114+
* Finds or inserts a slot corresponding to the given key.
1115+
* If the key is not found, a new slot is created by constructing it with the key followed by `args`.
1116+
* @param key The key used to find or insert the slot.
1117+
* @param args The arguments forwarded to the `slot_type` constructor after the key.
1118+
* @return An iterator to the inserted or existing value.
11811119
*/
11821120
template<typename... args_t>
11831121
requires(hud::is_constructible_v<slot_type, key_type, args_t...>)
@@ -1193,10 +1131,11 @@ namespace hud
11931131
}
11941132

11951133
/**
1196-
* Insert a key in the hashset.
1197-
* @param key The key associated with the `value`
1198-
* @param args List of arguments pass to `value_type` constructor after the `key` itself
1199-
* @return Iterator to the `value`
1134+
* Finds or inserts a slot corresponding to the given key.
1135+
* If the key is not found, a new slot is created by constructing it with the key followed by `args`.
1136+
* @param key The key used to find or insert the slot.
1137+
* @param args The arguments forwarded to the `slot_type` constructor after the key.
1138+
* @return An iterator to the inserted or existing value.
12001139
*/
12011140
template<typename... args_t>
12021141
requires(hud::is_constructible_v<slot_type, const key_type &, args_t...>)
@@ -1212,14 +1151,48 @@ namespace hud
12121151
}
12131152

12141153
private:
1215-
template<typename u_key_type>
1216-
[[nodiscard]] constexpr u64 compute_hash(const u_key_type &key) noexcept
1154+
template<typename K>
1155+
[[nodiscard]]
1156+
constexpr iterator find_impl(K &&key) noexcept
1157+
{
1158+
u64 hash {hasher_(hud::forward<K>(key))};
1159+
u64 h1(H1(hash));
1160+
hud::check(hud::bits::is_valid_power_of_two_mask(max_slot_count_) && "Not a mask");
1161+
usize slot_index(h1 & max_slot_count_);
1162+
while (true)
1163+
{
1164+
group_type group {control_ptr_ + slot_index};
1165+
group_type::mask group_mask_that_match_h2 {group.match(H2(hash))};
1166+
for (u32 group_index_that_match_h2 : group_mask_that_match_h2)
1167+
{
1168+
usize slot_index_that_match_h2 {slot_index + group_index_that_match_h2 & max_slot_count_};
1169+
slot_type *slot_that_match_h2 {slot_ptr_ + slot_index_that_match_h2};
1170+
if (key_equal_(slot_that_match_h2->key(), hud::forward<K>(key))) [[likely]]
1171+
{
1172+
return {control_ptr_ + slot_index_that_match_h2, slot_that_match_h2};
1173+
}
1174+
}
1175+
1176+
// If we have free slot, we don't find it
1177+
if (group.mask_of_empty_slot().has_empty_slot())
1178+
{
1179+
return iterator {control_ptr_sentinel()};
1180+
}
1181+
1182+
// Advance to next group (Maybe a control iterator that iterate over groups can be better alternative)
1183+
slot_index += group_type::SLOT_PER_GROUP;
1184+
slot_index &= max_slot_count_;
1185+
}
1186+
}
1187+
1188+
template<typename K>
1189+
[[nodiscard]] constexpr u64 compute_hash(const K &key) noexcept
12171190
{
1218-
if constexpr (hud::is_same_v<key_type, u_key_type>)
1191+
if constexpr (hud::is_same_v<key_type, K>)
12191192
{
12201193
return hasher_(key);
12211194
}
1222-
return hasher_(key_type {key});
1195+
return hasher_(key_type(key));
12231196
}
12241197

12251198
constexpr bool should_be_mark_as_empty_if_deleted(usize index) const noexcept

0 commit comments

Comments
 (0)