mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-09-16 08:18:13 +00:00
Improve the bucket distribution of SDL_HashTable
SDL_HashID does no hashing, which isn't good if the lower bits of the key aren't evenly distributed.
This commit is contained in:
@@ -32,6 +32,7 @@ struct SDL_HashTable
|
|||||||
{
|
{
|
||||||
SDL_HashItem **table;
|
SDL_HashItem **table;
|
||||||
Uint32 table_len;
|
Uint32 table_len;
|
||||||
|
int hash_shift;
|
||||||
SDL_bool stackable;
|
SDL_bool stackable;
|
||||||
void *data;
|
void *data;
|
||||||
SDL_HashTable_HashFn hash;
|
SDL_HashTable_HashFn hash;
|
||||||
@@ -46,8 +47,9 @@ SDL_HashTable *SDL_CreateHashTable(void *data, const Uint32 num_buckets, const S
|
|||||||
{
|
{
|
||||||
SDL_HashTable *table;
|
SDL_HashTable *table;
|
||||||
|
|
||||||
// num_buckets must be a power of two so we get a solid block of bits to mask hash values against.
|
// num_buckets must be a power of two so we can derive the bucket index with just a bitshift.
|
||||||
if ((num_buckets == 0) || ((num_buckets & (num_buckets - 1)) != 0)) {
|
// Need at least two buckets, otherwise hash_shift would be 32, which is UB!
|
||||||
|
if ((num_buckets < 2) || !SDL_HasExactlyOneBitSet32(num_buckets)) {
|
||||||
SDL_SetError("num_buckets must be a power of two");
|
SDL_SetError("num_buckets must be a power of two");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -64,6 +66,7 @@ SDL_HashTable *SDL_CreateHashTable(void *data, const Uint32 num_buckets, const S
|
|||||||
}
|
}
|
||||||
|
|
||||||
table->table_len = num_buckets;
|
table->table_len = num_buckets;
|
||||||
|
table->hash_shift = 32 - SDL_MostSignificantBitIndex32(num_buckets);
|
||||||
table->stackable = stackable;
|
table->stackable = stackable;
|
||||||
table->data = data;
|
table->data = data;
|
||||||
table->hash = hashfn;
|
table->hash = hashfn;
|
||||||
@@ -74,7 +77,9 @@ SDL_HashTable *SDL_CreateHashTable(void *data, const Uint32 num_buckets, const S
|
|||||||
|
|
||||||
static SDL_INLINE Uint32 calc_hash(const SDL_HashTable *table, const void *key)
|
static SDL_INLINE Uint32 calc_hash(const SDL_HashTable *table, const void *key)
|
||||||
{
|
{
|
||||||
return table->hash(key, table->data) & (table->table_len - 1);
|
// Mix the bits together, and use the highest bits as the bucket index.
|
||||||
|
const Uint32 BitMixer = 0x9E3779B1u;
|
||||||
|
return (table->hash(key, table->data) * BitMixer) >> table->hash_shift;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user