diff --git a/README.md b/README.md index 54520f9..55f297a 100644 --- a/README.md +++ b/README.md @@ -514,15 +514,14 @@ void hash_map_destroy( 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. ```C errno_t hash_map_insert( hash_map_t *const instance, 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` 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 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` 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` 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 errno_t hash_map_remove( 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` 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 On success, this function returns *zero*. On error, the appropriate error code is returned. Possible error codes include: diff --git a/example/hash-map/src/main.c b/example/hash-map/src/main.c index 46dddfc..ca2df9e 100644 --- a/example/hash-map/src/main.c +++ b/example/hash-map/src/main.c @@ -35,7 +35,7 @@ int main(void) while (have_more_items(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) { fprintf(stderr, "Insert operation failed! (error: %d)\n", error); diff --git a/libhashset/include/hash_map.h b/libhashset/include/hash_map.h index 4c3b25f..51edced 100644 --- a/libhashset/include/hash_map.h +++ b/libhashset/include/hash_map.h @@ -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_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_insert32(hash_map32_t *const instance, const uint32_t key, const uint32_t value); -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_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, const int update); +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_remove32(hash_map32_t *const instance, const uint32_t key); -HASHSET_API errno_t hash_map_remove64(hash_map64_t *const instance, const uint64_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, uint32_t *const value); +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_clear32(hash_map32_t *const instance); diff --git a/libhashset/src/generic_hash_map.h b/libhashset/src/generic_hash_map.h index 2ca0457..0f621a9 100644 --- a/libhashset/src/generic_hash_map.h +++ b/libhashset/src/generic_hash_map.h @@ -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; 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)) { - instance->data.entries[index].value = value; + if (update) + { + instance->data.entries[index].value = value; + } return EEXIST; } if ((!slot_reused) && (safe_add(instance->valid, instance->deleted) >= instance->limit)) { - const errno_t error = rebuild_map(instance, safe_times2(instance->data.capacity)); - if (error) + if (instance->data.capacity < SIZE_MAX) { - 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; } -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; @@ -312,6 +322,7 @@ errno_t DECLARE(hash_map_remove)(hash_map_t *const instance, const value_t key) return ENOENT; } + SAFE_SET(value, instance->data.entries[index].value); set_flag(instance->data.deleted, index); instance->deleted = safe_incr(instance->deleted); instance->valid = safe_decr(instance->valid); diff --git a/libhashset/src/generic_hash_set.h b/libhashset/src/generic_hash_set.h index 81bc1e1..bc771b9 100644 --- a/libhashset/src/generic_hash_set.h +++ b/libhashset/src/generic_hash_set.h @@ -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)) { - const errno_t error = rebuild_set(instance, safe_times2(instance->data.capacity)); - if (error) + if (instance->data.capacity < SIZE_MAX) { - 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!*/ } } diff --git a/test/hash-map/src/tests.c b/test/hash-map/src/tests.c index 21d81c1..448753a 100644 --- a/test/hash-map/src/tests.c +++ b/test/hash-map/src/tests.c @@ -86,7 +86,7 @@ int test_function_1(hash_map64_t *const hash_map) { 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) { 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]) { - const errno_t error = hash_map_remove64(hash_map, j); + const errno_t error = hash_map_remove64(hash_map, j, NULL); if (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]) { - 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) { 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]) { - 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) { printf("Insert operation has failed! (error: %d)\n", error); @@ -325,7 +325,7 @@ int test_function_3(hash_map64_t *const hash_map) for (;;) { 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 != EEXIST) @@ -391,7 +391,7 @@ int test_function_4(hash_map64_t *const hash_map) 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) { PRINT_SET_INFO(4); @@ -411,7 +411,7 @@ int test_function_4(hash_map64_t *const hash_map) 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) { PRINT_SET_INFO(4);