Skip to content

Commit 01d88af

Browse files
author
Julian LALU
committed
Imporve bits memory and hashmap
1 parent 53afe2e commit 01d88af

File tree

5 files changed

+85
-62
lines changed

5 files changed

+85
-62
lines changed

interface/core/containers/hashmap.h

Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,13 @@ namespace hud
3737
{
3838
};
3939

40-
enum class control_e : u8
41-
{
42-
empty = 0b10000000, // The slot is empty
43-
deleted = 0b11111110, // The slot is deleted
44-
sentinel = 0b11111111 // The slot is a sentinel, A sentinel is a special caracter that mark the end of the control for iteration
45-
// full: 0b0hhhhhhh where h represents the H2 hash bits.
46-
};
40+
using control_type = u8;
41+
static constexpr control_type control_empty = 0b10000000; // The slot is empty
42+
static constexpr control_type control_deleted = 0b11111110; // The slot is deleted
43+
static constexpr control_type control_sentinel = 0b11111111; // The slot is a sentinel, A sentinel is a special caracter that mark the end of the control for iteration
44+
// full: 0b0hhhhhhh where h represents the H2 hash bits.
4745

48-
extern const control_e EMPTY_GROUP[32];
46+
extern const control_type EMPTY_GROUP[32];
4947

5048
template<typename key_t, typename value_t>
5149
struct slot
@@ -55,16 +53,12 @@ namespace hud
5553
using value_type = typename hud::pair<key_t, value_t>::second_type;
5654
};
5755

58-
class bitmask
59-
{
60-
};
61-
6256
struct group_portable
6357
{
6458
static constexpr u64 slot_per_group_ = 8;
6559

66-
constexpr group_portable(const control_e *control) noexcept
67-
: value_(hud::memory::unaligned_load64(control))
60+
constexpr group_portable(const control_type *control) noexcept
61+
: value_(hud::memory::unaligned_load64(static_cast<const u8 *>(control)))
6862
{
6963
}
7064

@@ -75,7 +69,7 @@ namespace hud
7569

7670
u64 mask_of_empty_slot()
7771
{
78-
return hud::bits::has_zero_byte(hud::bits::has_value_byte(value_, static_cast<u8>(control_e::empty)));
72+
return hud::bits::has_zero_byte(hud::bits::has_value_byte(value_, control_empty));
7973
}
8074

8175
private:
@@ -105,15 +99,15 @@ namespace hud
10599
return (offset_ + i) & mask_;
106100
}
107101

108-
void next()
102+
void next_group()
109103
{
110-
index_ += Width;
104+
index_ += group::slot_per_group_;
111105
offset_ += index_;
112106
offset_ &= mask_;
113107
}
114108

115109
// 0-based probe index, a multiple of `Width`.
116-
u64 index() const
110+
u64 index_() const
117111
{
118112
return index_;
119113
}
@@ -123,7 +117,7 @@ namespace hud
123117
u64 mask_;
124118
/** */
125119
u64 offset_;
126-
u64 index_ = 0;
120+
u64 index_ {0};
127121
};
128122

129123
/** The hashmap iterator that iterate over elements. */
@@ -178,7 +172,7 @@ namespace hud
178172

179173
private:
180174
// The current control we are iterating. For the moment set to the global init control
181-
control_e *control_ {const_cast<control_e *>(&EMPTY_GROUP[32])};
175+
control_type *control_ {const_cast<control_type *>(&EMPTY_GROUP[32])};
182176
// The current slot we are iterating. Keep uninitialized.
183177
value_type *slot_;
184178
};
@@ -218,7 +212,7 @@ namespace hud
218212

219213
public:
220214
constexpr hashmap_impl() noexcept
221-
: control_(const_cast<control_e *>(&EMPTY_GROUP[32])) // Point to the sentinel in the empty group, const_cast is ok, EMPTY_GROUP is used only when the table is empty
215+
: control_(const_cast<control_type *>(&EMPTY_GROUP[32])) // Point to the sentinel in the empty group, const_cast is ok, EMPTY_GROUP is used only when the table is empty
222216
{
223217
}
224218

@@ -234,7 +228,7 @@ namespace hud
234228
// Hash the key
235229
u64 hash = hasher_type {}(key);
236230
control_iterator probe = control_iterator(H1(hash), max_slot_count_);
237-
const control_e *control = control_;
231+
const control_type *control = control_;
238232
while (true)
239233
{
240234
group g {control + probe.offset()};
@@ -244,11 +238,37 @@ namespace hud
244238
u64 mask_of_empty_slot = g.mask_of_empty_slot();
245239
if (mask_of_empty_slot != 0) [[likely]]
246240
{
241+
u64 insert_offset = hud::bits::trailing_zero(mask_of_empty_slot);
242+
u64 target = probe.offset(insert_offset);
243+
prepare_insert(hash, target, probe.index());
247244
}
248245
}
249246
return hud::nullopt;
250247
}
251248

249+
u64 prepare_insert(u64 hash, u64 target, )
250+
{
251+
if (growth_left_ == 0)
252+
{
253+
const usize old_capacity = max_slot_count_;
254+
rehash_and_grow_if_necessary();
255+
}
256+
}
257+
258+
void rehash_and_grow_if_necessary()
259+
{
260+
const usize cap = max_slot_count_;
261+
262+
// Rehash in place if the current size is <= 25/32 of capacity.
263+
if (cap > group::slot_per_group_ && count_ * uint64_t {32} <= cap * uint64_t {25})
264+
{
265+
}
266+
else
267+
{
268+
resize(NextCapacity(cap));
269+
}
270+
}
271+
252272
private:
253273
/** The max slot count of the hashmap. */
254274
usize max_slot_count_ {0};
@@ -257,10 +277,13 @@ namespace hud
257277
usize count_ {0};
258278

259279
/** Pointer to the control segment. */
260-
control_e *control_;
280+
control_type *control_;
261281

262282
/** Pointer to the slot segment. */
263283
value_type *slots_;
284+
285+
/** growth left elements. */
286+
usize growth_left_ {0};
264287
};
265288

266289
} // namespace details::hashmap

interface/core/os_common/bits.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ namespace hud::os::common
6262
#if defined(HD_COMPILER_CLANG) || defined(HD_COMPILER_CLANG_CL) || defined(HD_COMPILER_GCC)
6363
return u8(__builtin_clz((u32(value) << 1) | 1) - 23);
6464
#else
65-
return 7 - floor_log2(u32(value));
65+
return 7 - hud::math::floor_log2(u32(value));
6666
#endif
6767
}
6868

interface/core/os_common/memory.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -711,11 +711,11 @@ namespace hud::os::common
711711
}
712712

713713
/** Load 64 bits value and return it. */
714-
[[nodiscard]] static constexpr u64 unaligned_load64(const void *ptr) noexcept
714+
[[nodiscard]] static constexpr u64 unaligned_load64(const u8 *buffer) noexcept
715715
{
716-
u64 value;
717-
copy(&value, ptr, sizeof(u64));
718-
return value;
716+
u8 result[sizeof(u64)];
717+
copy(result, buffer, sizeof(u64));
718+
return hud::bit_cast<u64>(result);
719719
}
720720
};
721721

src/containers/hashmap.cpp

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,38 @@
33
namespace hud::details::hashmap
44
{
55

6-
alignas(16) constexpr const control_e EMPTY_GROUP[32] {
7-
details::hashmap::control_e {0}, // 0
8-
details::hashmap::control_e {0},
9-
details::hashmap::control_e {0},
10-
details::hashmap::control_e {0},
11-
details::hashmap::control_e {0}, // 4
12-
details::hashmap::control_e {0},
13-
details::hashmap::control_e {0},
14-
details::hashmap::control_e {0},
15-
details::hashmap::control_e {0}, // 8
16-
details::hashmap::control_e {0},
17-
details::hashmap::control_e {0},
18-
details::hashmap::control_e {0},
19-
details::hashmap::control_e {0}, // 12
20-
details::hashmap::control_e {0},
21-
details::hashmap::control_e {0},
22-
details::hashmap::control_e {0},
23-
details::hashmap::control_e::sentinel, // 16
24-
details::hashmap::control_e::empty,
25-
details::hashmap::control_e::empty,
26-
details::hashmap::control_e::empty,
27-
details::hashmap::control_e::empty, // 20
28-
details::hashmap::control_e::empty,
29-
details::hashmap::control_e::empty,
30-
details::hashmap::control_e::empty,
31-
details::hashmap::control_e::empty, // 24
32-
details::hashmap::control_e::empty,
33-
details::hashmap::control_e::empty,
34-
details::hashmap::control_e::empty,
35-
details::hashmap::control_e::empty, // 28
36-
details::hashmap::control_e::empty,
37-
details::hashmap::control_e::empty,
38-
details::hashmap::control_e::empty, // 31
6+
alignas(16) constexpr const control_type EMPTY_GROUP[32] {
7+
details::hashmap::control_type {0}, // 0
8+
details::hashmap::control_type {0},
9+
details::hashmap::control_type {0},
10+
details::hashmap::control_type {0},
11+
details::hashmap::control_type {0}, // 4
12+
details::hashmap::control_type {0},
13+
details::hashmap::control_type {0},
14+
details::hashmap::control_type {0},
15+
details::hashmap::control_type {0}, // 8
16+
details::hashmap::control_type {0},
17+
details::hashmap::control_type {0},
18+
details::hashmap::control_type {0},
19+
details::hashmap::control_type {0}, // 12
20+
details::hashmap::control_type {0},
21+
details::hashmap::control_type {0},
22+
details::hashmap::control_type {0},
23+
details::hashmap::control_sentinel, // 16
24+
details::hashmap::control_empty,
25+
details::hashmap::control_empty,
26+
details::hashmap::control_empty,
27+
details::hashmap::control_empty, // 20
28+
details::hashmap::control_empty,
29+
details::hashmap::control_empty,
30+
details::hashmap::control_empty,
31+
details::hashmap::control_empty, // 24
32+
details::hashmap::control_empty,
33+
details::hashmap::control_empty,
34+
details::hashmap::control_empty,
35+
details::hashmap::control_empty, // 28
36+
details::hashmap::control_empty,
37+
details::hashmap::control_empty,
38+
details::hashmap::control_empty, // 31
3939
};
4040
} // namespace hud::details::hashmap

test/hashmap/hashmap_insert.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44
GTEST_TEST(hashmap, insert)
55
{
66
hud::hashmap<const char *, const char *> map;
7-
// auto res = map.insert("key", "value");
7+
auto res = map.insert("key", "value");
88
}

0 commit comments

Comments
 (0)