hash_map_insert(): Added parameter 'update' to specify if the value of an existing key should be updated +

hash_map_remove(): Added parameter 'value' to return the value that was associated with the deleted key (optional).
This commit is contained in:
LoRd_MuldeR 2022-12-04 21:47:44 +01:00
parent f229c7ccfb
commit 669bf3a28b
6 changed files with 58 additions and 32 deletions

View File

@ -514,15 +514,14 @@ void hash_map_destroy(
Tries to insert the given key-value pair into the hash map. Tries to insert the given key-value pair into the hash map.
If the map already contains the given key, then the value associated with the existing key is updated.
***Note:*** If the key is actually inserted, then the hash map *may* need to grow. ***Note:*** If the key is actually inserted, then the hash map *may* need to grow.
```C ```C
errno_t hash_map_insert( errno_t hash_map_insert(
hash_map_t *const instance, hash_map_t *const instance,
const value_t key, const value_t key,
const value_t value const value_t value,
const int update
); );
``` ```
@ -537,6 +536,9 @@ errno_t hash_map_insert(
* `value` * `value`
The value to be associated with the given key. The value to be associated with the given key.
* `update`
If the map already contains the specified key, then if this parameter is *non-zero*, the value associated with the existing key will be updated; otherwise, the value currently associated with key remains unchanged.
#### Return value #### Return value
On success, this function returns *zero*. On error, the appropriate error code is returned. Possible error codes include: On success, this function returns *zero*. On error, the appropriate error code is returned. Possible error codes include:
@ -546,7 +548,7 @@ On success, this function returns *zero*. On error, the appropriate error code i
* `EEXIST` * `EEXIST`
The given key was *not* inserted into the hash map (again), because it was already present. The given key was *not* inserted into the hash map (again), because it was already present.
Nonetheless, the value associated with the existing key has been updated! Nonetheless, if `update` was non-zero, the value associated with the existing key has been updated.
* `ENOMEM` * `ENOMEM`
The key could *not* be inserted, because the required amount of memory could *not* be allocated. The key could *not* be inserted, because the required amount of memory could *not* be allocated.
@ -565,7 +567,8 @@ The value associated with the removed key is discarded.
```C ```C
errno_t hash_map_remove( errno_t hash_map_remove(
hash_map_t *const instance, hash_map_t *const instance,
const value_t key const value_t key,
value_t *const value
); );
``` ```
@ -577,6 +580,11 @@ errno_t hash_map_remove(
* `key` * `key`
The key to be removed from the hash map. The key to be removed from the hash map.
* `value`
A pointer to a variable of type `value_t` where the value that was associated with the deleted key is stored.
The content of the variable should be considered *undefined*, if the key could *not* be removed.
***Note:*** This parameter can be set to `NULL`, in which case the value will *not* be reported to the application.
#### Return value #### Return value
On success, this function returns *zero*. On error, the appropriate error code is returned. Possible error codes include: On success, this function returns *zero*. On error, the appropriate error code is returned. Possible error codes include:

View File

@ -35,7 +35,7 @@ int main(void)
while (have_more_items(offset)) while (have_more_items(offset))
{ {
const pair_t input = get_next_item(offset++); const pair_t input = get_next_item(offset++);
const errno_t error = hash_map_insert64(hash_map, input.key, input.value); const errno_t error = hash_map_insert64(hash_map, input.key, input.value, 1);
if (error) if (error)
{ {
fprintf(stderr, "Insert operation failed! (error: %d)\n", error); fprintf(stderr, "Insert operation failed! (error: %d)\n", error);

View File

@ -72,13 +72,13 @@ HASHSET_API void hash_map_destroy16(hash_map16_t *const instance);
HASHSET_API void hash_map_destroy32(hash_map32_t *const instance); HASHSET_API void hash_map_destroy32(hash_map32_t *const instance);
HASHSET_API void hash_map_destroy64(hash_map64_t *const instance); HASHSET_API void hash_map_destroy64(hash_map64_t *const instance);
HASHSET_API errno_t hash_map_insert16(hash_map16_t *const instance, const uint16_t key, const uint16_t value); HASHSET_API errno_t hash_map_insert16(hash_map16_t *const instance, const uint16_t key, const uint16_t value, const int update);
HASHSET_API errno_t hash_map_insert32(hash_map32_t *const instance, const uint32_t key, const uint32_t value); HASHSET_API errno_t hash_map_insert32(hash_map32_t *const instance, const uint32_t key, const uint32_t value, const int update);
HASHSET_API errno_t hash_map_insert64(hash_map64_t *const instance, const uint64_t key, const uint64_t value); HASHSET_API errno_t hash_map_insert64(hash_map64_t *const instance, const uint64_t key, const uint64_t value, const int update);
HASHSET_API errno_t hash_map_remove16(hash_map16_t *const instance, const uint16_t key); HASHSET_API errno_t hash_map_remove16(hash_map16_t *const instance, const uint16_t key, uint16_t *const value);
HASHSET_API errno_t hash_map_remove32(hash_map32_t *const instance, const uint32_t key); HASHSET_API errno_t hash_map_remove32(hash_map32_t *const instance, const uint32_t key, uint32_t *const value);
HASHSET_API errno_t hash_map_remove64(hash_map64_t *const instance, const uint64_t key); HASHSET_API errno_t hash_map_remove64(hash_map64_t *const instance, const uint64_t key, uint64_t *const value);
HASHSET_API errno_t hash_map_clear16(hash_map16_t *const instance); HASHSET_API errno_t hash_map_clear16(hash_map16_t *const instance);
HASHSET_API errno_t hash_map_clear32(hash_map32_t *const instance); HASHSET_API errno_t hash_map_clear32(hash_map32_t *const instance);

View File

@ -230,7 +230,7 @@ void DECLARE(hash_map_destroy)(hash_map_t *instance)
} }
} }
errno_t DECLARE(hash_map_insert)(hash_map_t *const instance, const value_t key, const value_t value) errno_t DECLARE(hash_map_insert)(hash_map_t *const instance, const value_t key, const value_t value, const bool_t update)
{ {
size_t index = SIZE_MAX; size_t index = SIZE_MAX;
bool_t slot_reused; bool_t slot_reused;
@ -242,20 +242,30 @@ errno_t DECLARE(hash_map_insert)(hash_map_t *const instance, const value_t key,
if (find_slot(&instance->data, instance->basis, key, &index, &slot_reused)) if (find_slot(&instance->data, instance->basis, key, &index, &slot_reused))
{ {
instance->data.entries[index].value = value; if (update)
{
instance->data.entries[index].value = value;
}
return EEXIST; return EEXIST;
} }
if ((!slot_reused) && (safe_add(instance->valid, instance->deleted) >= instance->limit)) if ((!slot_reused) && (safe_add(instance->valid, instance->deleted) >= instance->limit))
{ {
const errno_t error = rebuild_map(instance, safe_times2(instance->data.capacity)); if (instance->data.capacity < SIZE_MAX)
if (error)
{ {
return error; const errno_t error = rebuild_map(instance, safe_times2(instance->data.capacity));
if (error)
{
return error;
}
if (find_slot(&instance->data, instance->basis, key, &index, &slot_reused))
{
return EFAULT;
}
} }
if (find_slot(&instance->data, instance->basis, key, &index, &slot_reused)) else
{ {
return EFAULT; return ENOMEM; /*can not grow any futher!*/
} }
} }
@ -298,7 +308,7 @@ errno_t DECLARE(hash_map_get)(const hash_map_t *const instance, const value_t ke
return 0; return 0;
} }
errno_t DECLARE(hash_map_remove)(hash_map_t *const instance, const value_t key) errno_t DECLARE(hash_map_remove)(hash_map_t *const instance, const value_t key, value_t *const value)
{ {
size_t index; size_t index;
@ -312,6 +322,7 @@ errno_t DECLARE(hash_map_remove)(hash_map_t *const instance, const value_t key)
return ENOENT; return ENOENT;
} }
SAFE_SET(value, instance->data.entries[index].value);
set_flag(instance->data.deleted, index); set_flag(instance->data.deleted, index);
instance->deleted = safe_incr(instance->deleted); instance->deleted = safe_incr(instance->deleted);
instance->valid = safe_decr(instance->valid); instance->valid = safe_decr(instance->valid);

View File

@ -238,14 +238,21 @@ errno_t DECLARE(hash_set_insert)(hash_set_t *const instance, const value_t item)
if ((!slot_reused) && (safe_add(instance->valid, instance->deleted) >= instance->limit)) if ((!slot_reused) && (safe_add(instance->valid, instance->deleted) >= instance->limit))
{ {
const errno_t error = rebuild_set(instance, safe_times2(instance->data.capacity)); if (instance->data.capacity < SIZE_MAX)
if (error)
{ {
return error; const errno_t error = rebuild_set(instance, safe_times2(instance->data.capacity));
if (error)
{
return error;
}
if (find_slot(&instance->data, instance->basis, item, &index, &slot_reused))
{
return EFAULT;
}
} }
if (find_slot(&instance->data, instance->basis, item, &index, &slot_reused)) else
{ {
return EFAULT; return ENOMEM; /*can not grow any futher!*/
} }
} }

View File

@ -86,7 +86,7 @@ int test_function_1(hash_map64_t *const hash_map)
{ {
if (test_key1[j]) if (test_key1[j])
{ {
const errno_t error = hash_map_insert64(hash_map, j, test_data[j] = random_next(&random)); const errno_t error = hash_map_insert64(hash_map, j, test_data[j] = random_next(&random), 1);
if (error) if (error)
{ {
printf("Insert operation has failed! (error: %d)\n", error); printf("Insert operation has failed! (error: %d)\n", error);
@ -153,7 +153,7 @@ int test_function_1(hash_map64_t *const hash_map)
{ {
if (test_key1[j]) if (test_key1[j])
{ {
const errno_t error = hash_map_remove64(hash_map, j); const errno_t error = hash_map_remove64(hash_map, j, NULL);
if (error) if (error)
{ {
printf("Remove operation has failed! (error: %d)\n", error); printf("Remove operation has failed! (error: %d)\n", error);
@ -238,7 +238,7 @@ int test_function_2(hash_map64_t *const hash_map)
{ {
if (test_key[j]) if (test_key[j])
{ {
const errno_t error = hash_map_insert64(hash_map, j, test_val[j] = random_next(&random)); const errno_t error = hash_map_insert64(hash_map, j, test_val[j] = random_next(&random), 1);
if (error) if (error)
{ {
printf("Insert operation has failed! (error: %d)\n", error); printf("Insert operation has failed! (error: %d)\n", error);
@ -255,7 +255,7 @@ int test_function_2(hash_map64_t *const hash_map)
{ {
if (test_key[j]) if (test_key[j])
{ {
const errno_t error = hash_map_insert64(hash_map, j, test_val[j] = random_next(&random)); const errno_t error = hash_map_insert64(hash_map, j, test_val[j] = random_next(&random), 1);
if (error != EEXIST) if (error != EEXIST)
{ {
printf("Insert operation has failed! (error: %d)\n", error); printf("Insert operation has failed! (error: %d)\n", error);
@ -325,7 +325,7 @@ int test_function_3(hash_map64_t *const hash_map)
for (;;) for (;;)
{ {
const uint64_t rnd = random_next(&random) & UINT64_C(0x1FFFFFFFFFFFFFF); const uint64_t rnd = random_next(&random) & UINT64_C(0x1FFFFFFFFFFFFFF);
const errno_t error = hash_map_insert64(hash_map, rnd, VALUE(rnd)); const errno_t error = hash_map_insert64(hash_map, rnd, VALUE(rnd), 1);
if (error) if (error)
{ {
if (error != EEXIST) if (error != EEXIST)
@ -391,7 +391,7 @@ int test_function_4(hash_map64_t *const hash_map)
for (key = 0U; key < LIMIT; ++key) for (key = 0U; key < LIMIT; ++key)
{ {
const errno_t error = hash_map_insert64(hash_map, key, VALUE(key)); const errno_t error = hash_map_insert64(hash_map, key, VALUE(key), 1);
if (error) if (error)
{ {
PRINT_SET_INFO(4); PRINT_SET_INFO(4);
@ -411,7 +411,7 @@ int test_function_4(hash_map64_t *const hash_map)
for (key = 0U; key < LIMIT; ++key) for (key = 0U; key < LIMIT; ++key)
{ {
const errno_t error = hash_map_remove64(hash_map, key); const errno_t error = hash_map_remove64(hash_map, key, NULL);
if (error) if (error)
{ {
PRINT_SET_INFO(4); PRINT_SET_INFO(4);