Small improvement to map entry handling.
This commit is contained in:
parent
fb8ec13127
commit
d1cf093e76
@ -143,17 +143,17 @@ static INLINE void zero_memory(void *const addr, const size_t count, const size_
|
|||||||
/* Flags */
|
/* Flags */
|
||||||
/* ------------------------------------------------- */
|
/* ------------------------------------------------- */
|
||||||
|
|
||||||
static INLINE bool_t get_flag(const uint8_t *const flags, const size_t index)
|
static FORCE_INLINE bool_t get_flag(const uint8_t *const flags, const size_t index)
|
||||||
{
|
{
|
||||||
return (flags[index / 8U] >> (index % 8U)) & UINT8_C(1);
|
return (flags[index / 8U] >> (index % 8U)) & UINT8_C(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static INLINE void set_flag(uint8_t *const flags, const size_t index)
|
static FORCE_INLINE void set_flag(uint8_t *const flags, const size_t index)
|
||||||
{
|
{
|
||||||
flags[index / 8U] |= UINT8_C(1) << (index % 8U);
|
flags[index / 8U] |= UINT8_C(1) << (index % 8U);
|
||||||
}
|
}
|
||||||
|
|
||||||
static INLINE void clear_flag(uint8_t *const flags, const size_t index)
|
static FORCE_INLINE void clear_flag(uint8_t *const flags, const size_t index)
|
||||||
{
|
{
|
||||||
flags[index / 8U] &= ~(UINT8_C(1) << (index % 8U));
|
flags[index / 8U] &= ~(UINT8_C(1) << (index % 8U));
|
||||||
}
|
}
|
||||||
|
@ -18,9 +18,16 @@
|
|||||||
/* Data types */
|
/* Data types */
|
||||||
/* ------------------------------------------------- */
|
/* ------------------------------------------------- */
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
value_t key;
|
||||||
|
value_t value;
|
||||||
|
}
|
||||||
|
entry_t;
|
||||||
|
|
||||||
typedef struct DECLARE(_hash_map_data)
|
typedef struct DECLARE(_hash_map_data)
|
||||||
{
|
{
|
||||||
value_t *keys, *values;
|
entry_t *entries;
|
||||||
uint8_t *used, *deleted;
|
uint8_t *used, *deleted;
|
||||||
size_t capacity;
|
size_t capacity;
|
||||||
}
|
}
|
||||||
@ -42,33 +49,24 @@ static INLINE bool_t alloc_data(hash_data_t *const data, const size_t capacity)
|
|||||||
{
|
{
|
||||||
zero_memory(data, 1U, sizeof(hash_data_t));
|
zero_memory(data, 1U, sizeof(hash_data_t));
|
||||||
|
|
||||||
data->keys = (value_t*) calloc(capacity, sizeof(value_t));
|
data->entries = (entry_t*) calloc(capacity, sizeof(entry_t));
|
||||||
if (!data->keys)
|
if (!data->entries)
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
data->values = (value_t*) calloc(capacity, sizeof(value_t));
|
|
||||||
if (!data->values)
|
|
||||||
{
|
|
||||||
SAFE_FREE(data->keys);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
data->used = (uint8_t*) calloc(div_ceil(capacity, 8U), sizeof(uint8_t));
|
data->used = (uint8_t*) calloc(div_ceil(capacity, 8U), sizeof(uint8_t));
|
||||||
if (!data->used)
|
if (!data->used)
|
||||||
{
|
{
|
||||||
SAFE_FREE(data->keys);
|
SAFE_FREE(data->entries);
|
||||||
SAFE_FREE(data->values);
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
data->deleted = (uint8_t*) calloc(div_ceil(capacity, 8U), sizeof(uint8_t));
|
data->deleted = (uint8_t*) calloc(div_ceil(capacity, 8U), sizeof(uint8_t));
|
||||||
if (!data->deleted)
|
if (!data->deleted)
|
||||||
{
|
{
|
||||||
SAFE_FREE(data->keys);
|
|
||||||
SAFE_FREE(data->values);
|
|
||||||
SAFE_FREE(data->used);
|
SAFE_FREE(data->used);
|
||||||
|
SAFE_FREE(data->entries);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,8 +78,7 @@ static INLINE void free_data(hash_data_t *const data)
|
|||||||
{
|
{
|
||||||
if (data)
|
if (data)
|
||||||
{
|
{
|
||||||
SAFE_FREE(data->keys);
|
SAFE_FREE(data->entries);
|
||||||
SAFE_FREE(data->values);
|
|
||||||
SAFE_FREE(data->used);
|
SAFE_FREE(data->used);
|
||||||
SAFE_FREE(data->deleted);
|
SAFE_FREE(data->deleted);
|
||||||
data->capacity = 0U;
|
data->capacity = 0U;
|
||||||
@ -113,7 +110,7 @@ static INLINE bool_t find_slot(const hash_data_t *const data, const uint64_t bas
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (data->keys[index] == key)
|
if (data->entries[index].key == key)
|
||||||
{
|
{
|
||||||
SAFE_SET(index_out, index);
|
SAFE_SET(index_out, index);
|
||||||
SAFE_SET(reused_out, FALSE);
|
SAFE_SET(reused_out, FALSE);
|
||||||
@ -131,10 +128,11 @@ static INLINE bool_t find_slot(const hash_data_t *const data, const uint64_t bas
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static INLINE void put_value(hash_data_t *const data, const size_t index, const value_t key, const value_t value, const bool_t reusing)
|
static INLINE void put_entry(hash_data_t *const data, const size_t index, const value_t key, const value_t value, const bool_t reusing)
|
||||||
{
|
{
|
||||||
data->keys[index] = key;
|
entry_t *const entry = &data->entries[index];
|
||||||
data->values[index] = value;
|
entry->key = key;
|
||||||
|
entry->value = value;
|
||||||
|
|
||||||
if (reusing)
|
if (reusing)
|
||||||
{
|
{
|
||||||
@ -179,13 +177,13 @@ static INLINE errno_t rebuild_map(hash_map_t *const instance, const size_t new_c
|
|||||||
{
|
{
|
||||||
if (IS_VALID(instance->data, k))
|
if (IS_VALID(instance->data, k))
|
||||||
{
|
{
|
||||||
const value_t key = instance->data.keys[k], value = instance->data.values[k];
|
const entry_t entry = instance->data.entries[k];
|
||||||
if (find_slot(&temp, instance->basis, key, &index, NULL))
|
if (find_slot(&temp, instance->basis, entry.key, &index, NULL))
|
||||||
{
|
{
|
||||||
free_data(&temp);
|
free_data(&temp);
|
||||||
return EFAULT; /*this should never happen!*/
|
return EFAULT; /*this should never happen!*/
|
||||||
}
|
}
|
||||||
put_value(&temp, index, key, value, FALSE);
|
put_entry(&temp, index, entry.key, entry.value, FALSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,14 +235,14 @@ errno_t DECLARE(hash_map_insert)(hash_map_t *const instance, const value_t key,
|
|||||||
size_t index = SIZE_MAX;
|
size_t index = SIZE_MAX;
|
||||||
bool_t slot_reused;
|
bool_t slot_reused;
|
||||||
|
|
||||||
if ((!instance) || (!instance->data.keys))
|
if ((!instance) || (!instance->data.entries))
|
||||||
{
|
{
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (find_slot(&instance->data, instance->basis, key, &index, &slot_reused))
|
if (find_slot(&instance->data, instance->basis, key, &index, &slot_reused))
|
||||||
{
|
{
|
||||||
instance->data.values[index] = value;
|
instance->data.entries[index].value = value;
|
||||||
return EEXIST;
|
return EEXIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,7 +259,7 @@ errno_t DECLARE(hash_map_insert)(hash_map_t *const instance, const value_t key,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
put_value(&instance->data, index, key, value, slot_reused);
|
put_entry(&instance->data, index, key, value, slot_reused);
|
||||||
|
|
||||||
instance->valid = safe_incr(instance->valid);
|
instance->valid = safe_incr(instance->valid);
|
||||||
if (slot_reused)
|
if (slot_reused)
|
||||||
@ -274,7 +272,7 @@ errno_t DECLARE(hash_map_insert)(hash_map_t *const instance, const value_t key,
|
|||||||
|
|
||||||
errno_t DECLARE(hash_map_contains)(const hash_map_t *const instance, const value_t key)
|
errno_t DECLARE(hash_map_contains)(const hash_map_t *const instance, const value_t key)
|
||||||
{
|
{
|
||||||
if ((!instance) || (!instance->data.keys))
|
if ((!instance) || (!instance->data.entries))
|
||||||
{
|
{
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
@ -286,7 +284,7 @@ errno_t DECLARE(hash_map_get)(const hash_map_t *const instance, const value_t ke
|
|||||||
{
|
{
|
||||||
size_t index;
|
size_t index;
|
||||||
|
|
||||||
if ((!instance) || (!instance->data.keys))
|
if ((!instance) || (!instance->data.entries))
|
||||||
{
|
{
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
@ -296,7 +294,7 @@ errno_t DECLARE(hash_map_get)(const hash_map_t *const instance, const value_t ke
|
|||||||
return ENOENT;
|
return ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
*value = instance->data.values[index];
|
*value = instance->data.entries[index].value;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,7 +302,7 @@ errno_t DECLARE(hash_map_remove)(hash_map_t *const instance, const value_t key)
|
|||||||
{
|
{
|
||||||
size_t index;
|
size_t index;
|
||||||
|
|
||||||
if ((!instance) || (!instance->data.keys))
|
if ((!instance) || (!instance->data.entries))
|
||||||
{
|
{
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
@ -338,7 +336,7 @@ errno_t DECLARE(hash_map_remove)(hash_map_t *const instance, const value_t key)
|
|||||||
|
|
||||||
errno_t DECLARE(hash_map_clear)(hash_map_t *const instance)
|
errno_t DECLARE(hash_map_clear)(hash_map_t *const instance)
|
||||||
{
|
{
|
||||||
if ((!instance) || (!instance->data.values))
|
if ((!instance) || (!instance->data.entries))
|
||||||
{
|
{
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
@ -371,7 +369,7 @@ errno_t DECLARE(hash_map_iterate)(const hash_map_t *const instance, size_t *cons
|
|||||||
{
|
{
|
||||||
size_t index;
|
size_t index;
|
||||||
|
|
||||||
if ((!instance) || (!cursor) || (*cursor >= SIZE_MAX) || (!instance->data.values))
|
if ((!instance) || (!cursor) || (*cursor >= SIZE_MAX) || (!instance->data.entries))
|
||||||
{
|
{
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
@ -380,8 +378,9 @@ errno_t DECLARE(hash_map_iterate)(const hash_map_t *const instance, size_t *cons
|
|||||||
{
|
{
|
||||||
if (IS_VALID(instance->data, index))
|
if (IS_VALID(instance->data, index))
|
||||||
{
|
{
|
||||||
SAFE_SET(key, instance->data.keys[index]);
|
const entry_t* const entntry = &instance->data.entries[index];
|
||||||
SAFE_SET(value, instance->data.values[index]);
|
SAFE_SET(key, entntry->key);
|
||||||
|
SAFE_SET(value, entntry->value);
|
||||||
*cursor = index + 1U;
|
*cursor = index + 1U;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -398,7 +397,7 @@ size_t DECLARE(hash_map_size)(const hash_map_t *const instance)
|
|||||||
|
|
||||||
errno_t DECLARE(hash_map_info)(const hash_map_t *const instance, size_t *const capacity, size_t *const valid, size_t *const deleted, size_t *const limit)
|
errno_t DECLARE(hash_map_info)(const hash_map_t *const instance, size_t *const capacity, size_t *const valid, size_t *const deleted, size_t *const limit)
|
||||||
{
|
{
|
||||||
if ((!instance) || (!instance->data.values))
|
if ((!instance) || (!instance->data.entries))
|
||||||
{
|
{
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
@ -415,14 +414,15 @@ HASHSET_API errno_t DECLARE(hash_map_dump)(const hash_map_t *const instance, con
|
|||||||
{
|
{
|
||||||
size_t index;
|
size_t index;
|
||||||
|
|
||||||
if ((!instance) || (!instance->data.values) || (!callback))
|
if ((!instance) || (!instance->data.entries) || (!callback))
|
||||||
{
|
{
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (index = 0U; index < instance->data.capacity; ++index)
|
for (index = 0U; index < instance->data.capacity; ++index)
|
||||||
{
|
{
|
||||||
if (!callback(index, get_flag(instance->data.used, index) ? (get_flag(instance->data.deleted, index) ? 'd' : 'v') : 'u', instance->data.keys[index], instance->data.values[index]))
|
const entry_t* const entntry = &instance->data.entries[index];
|
||||||
|
if (!callback(index, get_flag(instance->data.used, index) ? (get_flag(instance->data.deleted, index) ? 'd' : 'v') : 'u', entntry->key, entntry->value))
|
||||||
{
|
{
|
||||||
return ECANCELED;
|
return ECANCELED;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user