simd_map remove

This commit is contained in:
Richard Thier 2024-10-22 18:52:12 +02:00
parent ab3e80f020
commit cd30b70457
2 changed files with 72 additions and 5 deletions

View File

@ -186,6 +186,16 @@ void test_simd_map_basics() {
assert(*simd_map_find(&smap, i) == (uint32_t)(cnt - i));
}
/* Test removal */
assert(simd_map_remove(&smap, 41) != 0);
assert(simd_map_remove(&smap, 43) != 0);
assert(simd_map_find(&smap, 41) == NULL);
assert(simd_map_find(&smap, 43) == NULL);
assert(simd_map_find(&smap, 42) != NULL);
assert(simd_map_find(&smap, 99) != NULL);
assert(simd_map_find(&smap, 98) != NULL);
assert(simd_map_size(&smap) == 98);
/* Filled free */
simd_map_free(&smap);
}

View File

@ -109,6 +109,8 @@ non_simd_modulo:
}
}
// TODO: Implement find_all(..) and delegate to it in find(..)
/** Returns if this key is stored in the map or not - returns NULL if does not exists. */
static inline uint32_t *simd_map_find(simd_map *map, uint32_t key) {
/* Do not process last element because of last incomplete lane */
@ -131,7 +133,7 @@ static inline uint32_t *simd_map_find(simd_map *map, uint32_t key) {
}
/** Useful if you know the key have never been before added (faster)! Returns 0 on errors, otherwise 1. */
static inline char simd_map_force_insert(simd_map *map, uint32_t key, uint32_t value) {
static inline SM_ALWAYS_INLINE char simd_map_force_insert(simd_map *map, uint32_t key, uint32_t value) {
/* Handle storage growth needs. */
uint32_t storage_needed = (map->lane_modulo == 0) ? 1 : 0;
if(SM_UNLIKELY(map->end - map->usage_end < storage_needed)) {
@ -163,7 +165,9 @@ static inline char simd_map_force_insert(simd_map *map, uint32_t key, uint32_t v
return 1;
}
/** Returns 0 on errors, otherwise 1 when added as new, 2 when already found got overwritten */
/**
* Returns 0 on errors, otherwise 1 when added as new, 2 when already found got overwritten
*/
static inline char simd_map_set(simd_map *map, uint32_t key, uint32_t value) {
uint32_t *found = simd_map_find(map, key);
if(!found) {
@ -176,21 +180,74 @@ static inline char simd_map_set(simd_map *map, uint32_t key, uint32_t value) {
}
/** Empties the map - this does not free resources, just makes it reusable! */
static inline void simd_map_erase(simd_map *map) {
static inline SM_ALWAYS_INLINE void simd_map_erase(simd_map *map) {
map->usage_end = 0;
map->lane_modulo = 0;
}
/** Returns count of elements in the given simd_map */
static inline size_t simd_map_size(simd_map *map) {
static inline SM_ALWAYS_INLINE size_t simd_map_size(simd_map *map) {
return (map->usage_end > 0) ?
(((size_t)(map->usage_end) - 1) * 8 + map->lane_modulo) :
0;
}
/** Returns TRUE when map is empty and false otherwise - faster than simd_map_size(..) */
static inline SM_ALWAYS_INLINE char simd_map_is_empty(simd_map *map) {
return (map->usage_end == 0);
}
/** Returns the key location for a given value location */
static inline SM_ALWAYS_INLINE uint32_t *simd_map_key_location(uint32_t *value_location) {
return value_location -= SM_LANE_SPAN;
}
/** Returns the lastly inserted value's location in the map - you must ensure the map has elements! */
static inline SM_ALWAYS_INLINE uint32_t *simd_map_last_location(simd_map *map) {
return (map->lane_modulo > 0) ?
&(map->lanes[map->usage_end - 1].values[map->lane_modulo - 1]) :
&(map->lanes[map->usage_end - 1].values[SM_LANE_SPAN - 1]);
}
/**
* Removes the found location from the map.
*
* Most users should prefer simd_map_remove instead. This is an unchecked operation!
*
* This must be called right after a find(..) or find_all(..) operation,
* because the pointer can get invalidated (for example by erase or remove).
*
* @param map The map to remove from
* @param value_location The location returned by find(..) or find_all(..) and is not yet invalidated
*/
static inline SM_ALWAYS_INLINE void simd_map_remove_ptr(simd_map *map, uint32_t *value_location) {
/* Overwrite with the last key-value */
uint32_t *key_location = simd_map_key_location(value_location);
uint32_t *last_value_location = simd_map_last_location(map);
uint32_t *last_key_location = simd_map_key_location(last_value_location);
*value_location = *last_value_location;
*key_location = *last_key_location;
/* Shrink the data structure */
if(map->lane_modulo > 0) {
--(map->lane_modulo);
} else {
map->lane_modulo = SM_LANE_SPAN - 1;
}
}
/** Remove the given key from the map so its not stored anymore. Returns 1 when found and removed, 0 otherwise. */
static inline int simd_map_remove(simd_map *map, uint32_t key) {
assert(0); // TODO: Implement by swapping to end + shrink!
if(SM_UNLIKELY(map->usage_end == 0)) return 0;
uint32_t *found = simd_map_find(map, key);
if(found) {
simd_map_remove_ptr(map, found);
return 1;
}
return 0;
}
#endif