From cd30b7045714a86648098889f63cb33d4f544a72 Mon Sep 17 00:00:00 2001 From: Richard Thier Date: Tue, 22 Oct 2024 18:52:12 +0200 Subject: [PATCH] simd_map remove --- main.cpp | 10 ++++++++ simd_map.h | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 72 insertions(+), 5 deletions(-) diff --git a/main.cpp b/main.cpp index a8930a4..c01e25a 100644 --- a/main.cpp +++ b/main.cpp @@ -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); } diff --git a/simd_map.h b/simd_map.h index 900486f..62dc785 100644 --- a/simd_map.h +++ b/simd_map.h @@ -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