Some improvements.

This commit is contained in:
LoRd_MuldeR 2022-11-19 18:42:09 +01:00
parent 9f22ab7005
commit 083da3e14e
2 changed files with 63 additions and 65 deletions

View File

@ -27,8 +27,8 @@ struct _hash_set
{ {
double load_factor; double load_factor;
int fail_fast; int fail_fast;
struct _hash_set_data data;
size_t size, limit; size_t size, limit;
struct _hash_set_data data;
}; };
#define BOUND(MIN,VAL,MAX) (((VAL) < (MIN)) ? (MIN) : (((VAL) > (MAX)) ? (MAX) : (VAL))) #define BOUND(MIN,VAL,MAX) (((VAL) < (MIN)) ? (MIN) : (((VAL) > (MAX)) ? (MAX) : (VAL)))
@ -39,24 +39,9 @@ struct _hash_set
/* PRIVATE FUNCTIONS */ /* PRIVATE FUNCTIONS */
/* ========================================================================= */ /* ========================================================================= */
static INLINE size_t hash(uint64_t value, const size_t capacity) static inline size_t safe_mult2(const size_t value)
{ {
#if SIZE_MAX > UINT32_MAX return (value < (SIZE_MAX >> 1)) ? (value << 1) : SIZE_MAX;
uint64_t h = UINT64_C(14695981039346656037);
for (size_t i = 0U; i < sizeof(uint64_t); ++i, value >>= CHAR_BIT)
{
h ^= value & 0xFF;
h *= UINT64_C(1099511628211);
}
#else
uint32_t h = UINT32_C(2166136261);
for (size_t i = 0U; i < sizeof(uint64_t); ++i, value >>= CHAR_BIT)
{
h ^= value & 0xFF;
h *= UINT32_C(16777619);
}
#endif
return ((size_t) h) % capacity;
} }
static INLINE size_t round(double d) static INLINE size_t round(double d)
@ -64,15 +49,27 @@ static INLINE size_t round(double d)
return (d >= 0.0) ? ((size_t)(d + 0.5)) : ((size_t)(d - ((double)((size_t)(d - 1))) + 0.5)) + ((size_t)(d - 1)); return (d >= 0.0) ? ((size_t)(d + 0.5)) : ((size_t)(d - ((double)((size_t)(d - 1))) + 0.5)) + ((size_t)(d - 1));
} }
static INLINE size_t safe_mult(const size_t a, const size_t b) #define HASH_STEP() do \
{ { \
if ((a == 0U) || (b == 0U)) h = (h ^ (value & 0xFF)) * MAGIC_PRIME; \
{ value >>= CHAR_BIT; \
return 0U; } \
} while(0)
const size_t result = a * b; static INLINE size_t hash(uint64_t value, const size_t capacity)
return(result / a != b) ? SIZE_MAX : result; {
#if SIZE_MAX > UINT32_MAX
uint64_t h = UINT64_C(14695981039346656037);
const uint64_t MAGIC_PRIME = UINT64_C(1099511628211);
#else
uint32_t h = UINT32_C(2166136261);
const uint32_t MAGIC_PRIME = UINT32_C(16777619);
#endif
HASH_STEP(); HASH_STEP(); HASH_STEP(); HASH_STEP();
HASH_STEP(); HASH_STEP(); HASH_STEP(); HASH_STEP();
return (size_t)(h % capacity);
} }
static INLINE size_t next_pow2(const size_t minimum) static INLINE size_t next_pow2(const size_t minimum)
@ -80,7 +77,7 @@ static INLINE size_t next_pow2(const size_t minimum)
size_t result = 2U; size_t result = 2U;
while (result < minimum) while (result < minimum)
{ {
result = safe_mult(result, 2U); result = safe_mult2(result);
} }
return result; return result;
} }
@ -111,19 +108,17 @@ static INLINE void free_data(struct _hash_set_data *const data)
{ {
if (data) if (data)
{ {
data->capacity = 0U;
if (data->values) if (data->values)
{ {
free(data->values); free(data->values);
data->values = NULL; data->values = NULL;
} }
if (data->used) if (data->used)
{ {
free(data->used); free(data->used);
data->used = NULL; data->used = NULL;
} }
data->capacity = 0U;
} }
} }
@ -132,45 +127,35 @@ static INLINE int is_used(struct _hash_set_data *const data, const size_t index)
return (data->used[index / 8U] >> (index % 8U)) & 1U; return (data->used[index / 8U] >> (index % 8U)) & 1U;
} }
static INLINE int find_value(struct _hash_set_data* const data, const uint64_t value, size_t *const index_out) static INLINE int find_value(struct _hash_set_data* const data, const uint64_t value, size_t *const index)
{ {
size_t index = hash(value, data->capacity); *index = hash(value, data->capacity);
while (is_used(data, index)) while (is_used(data, *index))
{ {
if (data->values[index] == value) if (data->values[*index] == value)
{ {
if (index_out)
{
*index_out = index;
}
return 1; return 1;
} }
if (++index >= data->capacity) if (++*index >= data->capacity)
{ {
index = 0U; *index = 0U;
} }
} }
if (index_out)
{
*index_out = index;
}
return 0; return 0;
} }
static INLINE void insert_value(struct _hash_set_data *const data, const size_t index, const uint64_t value) static INLINE int insert_value(struct _hash_set_data *const data, const size_t index, const uint64_t value)
{ {
data->values[index] = value; if (is_used(data, index))
data->used[index / 8U] |= 1U << (index % 8U); {
} return 0;
}
static INLINE void swap_data(struct _hash_set_data *const a, struct _hash_set_data *const b) data->values[index] = value;
{ data->used[index / 8U] |= UINT8_C(1) << (index % 8U);
struct _hash_set_data temp = *a; return 1;
*a = *b;
*b = temp;
} }
static INLINE int grow_set(hash_set_t *const instance, const size_t new_capacity) static INLINE int grow_set(hash_set_t *const instance, const size_t new_capacity)
@ -191,12 +176,15 @@ static INLINE int grow_set(hash_set_t *const instance, const size_t new_capacity
{ {
abort(); /*whoops!*/ abort(); /*whoops!*/
} }
insert_value(&temp, index, value); if (!insert_value(&temp, index, value))
{
abort(); /*whoops!*/
}
} }
} }
swap_data(&instance->data, &temp); free_data(&instance->data);
free_data(&temp); instance->data = temp;
instance->limit = round(instance->data.capacity * instance->load_factor); instance->limit = round(instance->data.capacity * instance->load_factor);
return 1; return 1;
} }
@ -259,7 +247,7 @@ int hash_set_insert(hash_set_t *const instance, const uint64_t value)
} }
else else
{ {
if (grow_set(instance, safe_mult(instance->data.capacity, 2U))) if (grow_set(instance, safe_mult2(instance->data.capacity)))
{ {
if (find_value(&instance->data, value, &index)) if (find_value(&instance->data, value, &index))
{ {
@ -277,7 +265,11 @@ int hash_set_insert(hash_set_t *const instance, const uint64_t value)
} }
} }
insert_value(&instance->data, index, value); if (!insert_value(&instance->data, index, value))
{
abort(); /*whoops!*/
}
++instance->size; ++instance->size;
return 1; return 1;
} }
@ -289,7 +281,8 @@ int hash_set_contains(hash_set_t *const instance, const uint64_t value)
return -1; return -1;
} }
return find_value(&instance->data, value, NULL); size_t index;
return find_value(&instance->data, value, &index);
} }
size_t hash_set_current_size(hash_set_t *const instance) size_t hash_set_current_size(hash_set_t *const instance)

View File

@ -25,19 +25,24 @@ int main()
return EXIT_FAILURE; return EXIT_FAILURE;
} }
clock_t now, next_update = clock(); uint8_t spinner = 0U;
clock_t next_update = clock() + (2U * CLOCKS_PER_SEC);
for (;;) for (;;)
{ {
const int ret = hash_set_insert(set, next_rand() & 0xFFFFFFFFFFFFFFllu); const int ret = hash_set_insert(set, next_rand() & 0x3FFFFFFFFFFFFFFllu);
if (ret != 1) if (ret != 1)
{ {
printf("Error! (%d)\n", ret); printf("Error! (%d)\n", ret);
break; break;
} }
if ((now = clock()) >= next_update) if (!(++spinner & 0x7F))
{ {
printf("%zu\n", hash_set_current_size(set)); const clock_t now = clock();
next_update = now + (3U * CLOCKS_PER_SEC); if (now >= next_update)
{
printf("%zu\n", hash_set_current_size(set));
next_update = now + (2U * CLOCKS_PER_SEC);
}
} }
} }