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:
parent
f229c7ccfb
commit
669bf3a28b
18
README.md
18
README.md
@ -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:
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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!*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user