Skip to content

Commit 89f7361

Browse files
author
Julian LALU
committed
hashset implementation
1 parent 2a33c71 commit 89f7361

File tree

6 files changed

+230
-124
lines changed

6 files changed

+230
-124
lines changed

interface/core/containers/hashmap.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ namespace hud
7171
typename key_equal_t = details::hashmap::default_equal<key_t>,
7272
typename allocator_t = details::hashmap::default_allocator<details::hashmap::slot<key_t, value_t>>>
7373
class hashmap
74-
: details::hashset::hashset_impl<details::hashmap::slot<key_t, value_t>, hasher_t, key_equal_t, allocator_t>
74+
: public details::hashset::hashset_impl<details::hashmap::slot<key_t, value_t>, hasher_t, key_equal_t, allocator_t>
7575

7676
{
7777
private:
@@ -84,10 +84,6 @@ namespace hud
8484
using typename super::key_type;
8585
/** Type of the value. */
8686
using typename super::value_type;
87-
88-
/** Import super functions. */
89-
using super::insert_to_ref;
90-
using super::super;
9187
};
9288
} // namespace hud
9389

interface/core/containers/hashset.h

Lines changed: 108 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,24 @@ namespace hud
191191
return hud::bits::trailing_zero(mask_value_) >> 3;
192192
}
193193

194+
[[nodiscard]]
195+
friend bool operator==(const mask &a, const mask &b)
196+
{
197+
return a.mask_value_ == b.mask_value_;
198+
}
199+
200+
[[nodiscard]]
201+
friend bool operator!=(const mask &a, const mask &b)
202+
{
203+
return !(a == b);
204+
}
205+
206+
[[nodiscard]]
207+
constexpr operator u64() const noexcept
208+
{
209+
return mask_value_;
210+
}
211+
194212
private:
195213
u64 mask_value_;
196214
};
@@ -227,16 +245,54 @@ namespace hud
227245
}
228246
};
229247

248+
struct full_mask
249+
: mask
250+
{
251+
using mask::mask;
252+
253+
[[nodiscard]] constexpr bool has_full_slot() const noexcept
254+
{
255+
return *this;
256+
}
257+
258+
[[nodiscard]] constexpr u32 first_full_index() const noexcept
259+
{
260+
return first_non_null_index();
261+
}
262+
};
263+
264+
struct full_or_sentinel_mask
265+
: mask
266+
{
267+
using mask::mask;
268+
269+
[[nodiscard]] constexpr bool has_full_slot() const noexcept
270+
{
271+
return *this;
272+
}
273+
274+
[[nodiscard]] constexpr u32 first_full_index() const noexcept
275+
{
276+
return first_non_null_index();
277+
}
278+
};
279+
230280
/** Load a 8 bytes metadata into the group. */
231281
constexpr portable_group(const byte_type *metadata) noexcept
232282
: value_(hud::memory::unaligned_load64(metadata))
283+
233284
{
234285
}
235286

236287
/**Retrieve a mask where H2 matching metadata byte have value 0x80 and non matching have value 0x00. */
237288
constexpr mask match(u8 h2_hash) const noexcept
238289
{
239-
return mask {hud::bits::has_value_byte(value_, h2_hash)};
290+
// Mix of From http://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
291+
// And http://graphics.stanford.edu/~seander/bithacks.html#ValueInWord
292+
constexpr uint64_t lsbs = 0x0101010101010101ULL;
293+
auto x = value_ ^ (lsbs * h2_hash);
294+
return mask {(x - lsbs) & ~x & 0x8080808080808080ULL};
295+
// return mask {hud::bits::has_value_byte(value_, h2_hash)};
240296
}
241297

242298
/** Retrieve a mask where empty metadata bytes have value 0x80 and others have value 0x00. */
@@ -296,7 +352,7 @@ namespace hud
296352
}
297353

298354
/** Retrieve a mask where full metadata bytes have value 0x80 and others have value 0x00. */
299-
constexpr u64 mask_of_full_slot() const noexcept
355+
constexpr full_mask mask_of_full_slot() const noexcept
300356
{
301357
// controls are
302358
// empty : 0b10000000
@@ -398,7 +454,7 @@ namespace hud
398454

399455
friend bool operator==(const iterator &a, const iterator &b)
400456
{
401-
return a.control_ == b.control_;
457+
return a.metadata_.data() == b.metadata_.data();
402458
}
403459

404460
friend bool operator!=(const iterator &a, const iterator &b)
@@ -500,7 +556,7 @@ namespace hud
500556
slot_type *slot_that_match_h2 = slots_ + slot_index_that_match_h2;
501557
if (key_equal_t {}(slot_that_match_h2->key(), key)) [[likely]]
502558
{
503-
return iterator_type(metadata_.metadata_start_at_slot_index(slot_index_that_match_h2), slot_that_match_h2);
559+
return iterator_type(metadata_.metadata_that_start_at_slot_index(slot_index_that_match_h2), slot_that_match_h2);
504560
}
505561
}
506562

@@ -516,11 +572,31 @@ namespace hud
516572
}
517573
}
518574

575+
/** Retrieves an iterator to the end of the array. */
576+
[[nodiscard]] constexpr iterator_type begin() noexcept
577+
{
578+
return find_first_full();
579+
}
580+
581+
/** Retrieves an iterator to the end of the array. */
582+
[[nodiscard]]
583+
constexpr const iterator_type begin() const noexcept
584+
{
585+
return find_first_full();
586+
}
587+
519588
/** Retrieves an iterator to the end of the array. */
520589
[[nodiscard]]
521590
constexpr iterator_type end() noexcept
522591
{
523-
return iterator_type(metadata_, slots_);
592+
return iterator_type(metadata_.metadata_that_start_at_slot_index(max_slot_count_), slots_);
593+
}
594+
595+
/** Retrieves an iterator to the end of the array. */
596+
[[nodiscard]]
597+
constexpr const iterator_type end() const noexcept
598+
{
599+
return iterator_type(metadata_.metadata_that_start_at_slot_index(max_slot_count_), slots_);
524600
}
525601

526602
private:
@@ -619,8 +695,11 @@ namespace hud
619695
{
620696
// Move elements to new buffer if any
621697
// Relocate slots to newly allocated buffer
698+
// for (auto &slot : *this)
699+
// {
700+
// find_first_empty_or_deleted()
701+
// }
622702
// Free old buffer
623-
624703
allocator_.template free<slot_type>({hud::bit_cast<slot_type *>(metadata_.data()), current_allocation_size()});
625704
}
626705

@@ -675,6 +754,27 @@ namespace hud
675754
}
676755
}
677756

757+
[[nodiscard]]
758+
constexpr iterator_type find_first_full() noexcept
759+
{
760+
hud::check(hud::bits::is_valid_power_of_two_mask(max_slot_count_) && "Not a mask");
761+
usize slot_index = 0;
762+
while (slot_index < max_slot_count_)
763+
{
764+
metadata::group_type group = metadata_.group_of_slot_index(slot_index);
765+
metadata::group_type::full_mask group_mask = group.mask_of_full_slot();
766+
if (group_mask.has_full_slot())
767+
{
768+
u32 first_full_index = group_mask.first_full_index();
769+
return iterator_type {metadata_.metadata_that_start_at_slot_index(first_full_index), slots_ + first_full_index};
770+
}
771+
772+
// Advance to next group (Maybe a metadata iterator that iterate over groups can be better alternative)
773+
slot_index += metadata::group_type::SLOT_PER_GROUP;
774+
}
775+
return end();
776+
}
777+
678778
/**
679779
* Compute the maximum number of slots we should put into the table before a resizing rehash.
680780
* Subtract the returned value with the number of slots `count()` to obtains the number of slots we can currently before a resizing rehash.
@@ -721,7 +821,8 @@ namespace hud
721821
typename key_equal_t = details::hashset::default_equal<value_t>,
722822
typename allocator_t = details::hashset::default_allocator<value_t>>
723823
class hashset
724-
: details::hashset::hashset_impl<details::hashset::slot<value_t>, hasher_t, key_equal_t, allocator_t>
824+
: public details::hashset::hashset_impl<details::hashset::slot<value_t>, hasher_t, key_equal_t, allocator_t>
825+
725826
{
726827
private:
727828
using super = details::hashset::hashset_impl<details::hashset::slot<value_t>, hasher_t, key_equal_t, allocator_t>;
@@ -731,10 +832,6 @@ namespace hud
731832
using hasher_type = typename super::hasher_type;
732833
/** Type of the value. */
733834
using value_type = typename super::value_type;
734-
735-
/** Import super functions. */
736-
using super::insert_to_ref;
737-
using super::super;
738835
};
739836
} // namespace hud
740837

interface/core/os_common/bits.h

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@ namespace hud::os::common
2222
* result = 0x0000008000800000
2323
* This indicates that a zero byte (0x00) is present in the word at byte index 2 and 4
2424
*/
25-
[[nodiscard]] static constexpr u64 has_zero_byte(u64 value) noexcept
26-
{
27-
// From http://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
28-
// value= 0x1213140015001617
29-
// value - 0x0101010101010101 = 0x111212FF13FF1516
30-
// ~value = 0xEDECEBFFEAFFE9E8
31-
// Final result after AND = 0x0000008000800000
32-
return ((value)-0x0101010101010101UL) & ~(value) & 0x8080808080808080UL;
33-
}
25+
// [[nodiscard]] static constexpr u64 has_zero_byte(u64 value) noexcept
26+
// {
27+
// // From http://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
28+
// // value= 0x1213140015001617
29+
// // value - 0x0101010101010101 = 0x111212FF13FF1516
30+
// // ~value = 0xEDECEBFFEAFFE9E8
31+
// // Final result after AND = 0x0000008000800000
32+
// return ((value)-0x0101010101010101UL) & ~(value) & 0x8080808080808080UL;
33+
// }
3434

3535
/**
3636
* Determines if a 64-bit word contains any byte equal to a given value
@@ -42,16 +42,16 @@ namespace hud::os::common
4242
* result = 0x8000000000008000
4343
* This indicates that `byte_value` is present in the word at byte index 1 and 7
4444
*/
45-
[[nodiscard]] static constexpr u64 has_value_byte(u64 value, u8 byte_value) noexcept
46-
{
47-
// From http://graphics.stanford.edu/~seander/bithacks.html#ValueInWord
48-
// value = 0x1213140015001217
49-
// byte_value = 0x12
50-
// 0x0101010101010101ULL * byte_value = 0x1212121212121212
51-
// value ^ (0x0101010101010101ULL * byte_value) = 0x0001061207120005
52-
// Final result after has_zero_byte = 0x8000000000008000
53-
return has_zero_byte(value ^ (0x0101010101010101ULL * byte_value));
54-
}
45+
// [[nodiscard]] static constexpr u64 has_value_byte(u64 value, u8 byte_value) noexcept
46+
// {
47+
// // From http://graphics.stanford.edu/~seander/bithacks.html#ValueInWord
48+
// // value = 0x1213140015001217
49+
// // byte_value = 0x12
50+
// // 0x0101010101010101ULL * byte_value = 0x1212121212121212
51+
// // value ^ (0x0101010101010101ULL * byte_value) = 0x0001061207120005
52+
// // Final result after has_zero_byte = 0x8000000000008000
53+
// return has_zero_byte(value ^ (0x0101010101010101ULL * byte_value));
54+
// }
5555

5656
/** Returns the number of consecutive 0 bits in the value. */
5757
[[nodiscard]] static constexpr u32 leading_zero(u8 value) noexcept

0 commit comments

Comments
 (0)