simd multimap operations - first version, seem compatible with non-multi for now
This commit is contained in:
parent
cd30b70457
commit
d219203939
126
simd_map.h
126
simd_map.h
@ -71,12 +71,22 @@ static inline SM_ALWAYS_INLINE char simd_map_free(simd_map *map) {
|
||||
/**
|
||||
* Returns if this key is stored in the given map LANE or not - returns NULL if not found.
|
||||
*
|
||||
* Rem.: The lane_begin and lane_next_begin parameters are used for reentrant multisearch.
|
||||
*
|
||||
* @param map_lane The lane to find in.
|
||||
* @param key The key to search for.
|
||||
* @param lane_modulo When non-zero, the lane only searched by this many elements. Zero means all elements. (mod lane length)
|
||||
* @param lane_modulo When non-zero, the lane only searched until this index. Zero means all remaining elements. (mod lane length)
|
||||
* @param lane_begin The lane is searched from this location(find_all). If full lane / lane prefix is needed, this should be 0.
|
||||
* @param lane_next_begin This pointer will be filled on non-NULL retvals with the incremented in-lane index (with % modulus).
|
||||
* @returns NULL when not found, otherwise pointer to the stored value for the key.
|
||||
*/
|
||||
static inline SM_ALWAYS_INLINE uint32_t *simd_map_lane_find(simd_map_lane *map_lane, uint32_t key, int lane_modulo) {
|
||||
static inline SM_ALWAYS_INLINE uint32_t *simd_map_lane_find(
|
||||
simd_map_lane *map_lane,
|
||||
uint32_t key,
|
||||
int lane_modulo,
|
||||
int lane_begin,
|
||||
int *lane_next_begin) {
|
||||
|
||||
uint32_t *keys = map_lane->keys;
|
||||
uint32_t *values = map_lane->values;
|
||||
|
||||
@ -90,18 +100,22 @@ static inline SM_ALWAYS_INLINE uint32_t *simd_map_lane_find(simd_map_lane *map_l
|
||||
/* Regular integer code - should have good ILP and cache locality patterns anyways */
|
||||
if(lane_modulo == 0) {
|
||||
/** Pretty hopeful this can get more easily unrolled / autovectorized */
|
||||
for(int i = 0; i < SM_LANE_SPAN; ++i) {
|
||||
for(int i = lane_begin; i < SM_LANE_SPAN; ++i) {
|
||||
if(SM_UNLIKELY(keys[i] == key)) {
|
||||
return &values[i];
|
||||
uint32_t *ptr = &values[i];
|
||||
*lane_next_begin = (i + 1) % SM_LANE_SPAN;
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
} else {
|
||||
non_simd_modulo:
|
||||
for(int i = 0; i < lane_modulo; ++i) {
|
||||
for(int i = lane_begin; i < lane_modulo; ++i) {
|
||||
if(SM_UNLIKELY(keys[i] == key)) {
|
||||
return &values[i];
|
||||
uint32_t *ptr = &values[i];
|
||||
*lane_next_begin = (i + 1) % SM_LANE_SPAN;
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,31 +123,99 @@ non_simd_modulo:
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Implement find_all(..) and delegate to it in find(..)
|
||||
/** The result of the find_all(..) operation */
|
||||
struct simd_map_find_res {
|
||||
/** The found location - or NULL when the key was not found */
|
||||
uint32_t *value_location;
|
||||
/** Meta-data for continuation of the search */
|
||||
uint32_t lane_next;
|
||||
/** Meta-data for continuation of the search */
|
||||
int lane_next_begin;
|
||||
};
|
||||
typedef struct simd_map_find_res simd_map_find_res;
|
||||
|
||||
/** 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 */
|
||||
if(map->usage_end > 0) for(uint32_t i = 0; i < map->usage_end - 1; ++i) {
|
||||
uint32_t *found = simd_map_lane_find(&(map->lanes[i]), key, 0);
|
||||
if(found) return found;
|
||||
/** Create the value for starting a find_all call */
|
||||
static inline simd_map_find_res simd_map_find_all_begin() {
|
||||
simd_map_find_res ret;
|
||||
ret.value_location = NULL;
|
||||
ret.lane_next = 0;
|
||||
ret.lane_next_begin = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful for multimap-like operations to find multiple mappings for the same key.
|
||||
*
|
||||
* @param map The map
|
||||
* @param key The key to search
|
||||
* @param prev The previous result - or simd_map_find_all_begin() to find the first / start lookup!
|
||||
* @returns The found pointer / location (if any) and if location was non-NULL meta-data so we can search further same-keys!
|
||||
*/
|
||||
static inline SM_ALWAYS_INLINE simd_map_find_res simd_map_find_all(simd_map *map, uint32_t key, simd_map_find_res prev) {
|
||||
simd_map_find_res ret;
|
||||
|
||||
/* Process most lanes */
|
||||
/* Do not process last element (-1) because of last incomplete lane */
|
||||
if(map->usage_end > 0) for(uint32_t i = prev.lane_next; i < map->usage_end - 1; ++i) {
|
||||
uint32_t *found = simd_map_lane_find(
|
||||
&(map->lanes[i]),
|
||||
key,
|
||||
0,
|
||||
prev.lane_next_begin,
|
||||
&(ret.lane_next_begin)); /* XXX: Fills part of retval! */
|
||||
|
||||
/* Needed so only the currently found are ignored in find_all(..) */
|
||||
prev.lane_next_begin = 0;
|
||||
|
||||
if(found) {
|
||||
ret.value_location = found;
|
||||
ret.lane_next = i + (ret.lane_next_begin != 0);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Process last lane - with a modulo lane */
|
||||
if(map->usage_end > 0) {
|
||||
if((map->usage_end > 0) && (prev.lane_next < map->usage_end)) {
|
||||
uint32_t *found = simd_map_lane_find(
|
||||
&(map->lanes[map->usage_end - 1]),
|
||||
key,
|
||||
map->lane_modulo);
|
||||
if(found) return found;
|
||||
&(map->lanes[map->usage_end - 1]),
|
||||
key,
|
||||
map->lane_modulo,
|
||||
prev.lane_next_begin,
|
||||
&(ret.lane_next_begin)); /* XXX: Fills part of retval! */
|
||||
|
||||
/* Needed so only the currently found are ignored in find_all(..) */
|
||||
prev.lane_next_begin = 0;
|
||||
|
||||
if(found) {
|
||||
ret.value_location = found;
|
||||
ret.lane_next = (map->usage_end - 1) + (ret.lane_next_begin != 0);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Not found */
|
||||
return NULL;
|
||||
ret = simd_map_find_all_begin();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Useful if you know the key have never been before added (faster)! Returns 0 on errors, otherwise 1. */
|
||||
static inline SM_ALWAYS_INLINE char simd_map_force_insert(simd_map *map, uint32_t key, uint32_t value) {
|
||||
/** 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) {
|
||||
simd_map_find_res begin = simd_map_find_all_begin();
|
||||
simd_map_find_res fires = simd_map_find_all(map, key, begin);
|
||||
return fires.value_location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert without checking that the value have been already added or not.
|
||||
*
|
||||
* Useful for multimap operation or if you know the key have never been before added (faster)!
|
||||
*
|
||||
* @param map The map
|
||||
* @param key The key to insert
|
||||
* @param value The value for this key to insert
|
||||
* @returns 0 on errors, otherwise 1.
|
||||
*/
|
||||
static inline SM_ALWAYS_INLINE char simd_map_multi_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)) {
|
||||
@ -171,7 +253,7 @@ static inline SM_ALWAYS_INLINE char simd_map_force_insert(simd_map *map, uint32_
|
||||
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) {
|
||||
return simd_map_force_insert(map, key, value);
|
||||
return simd_map_multi_insert(map, key, value);
|
||||
} else {
|
||||
/* Overwrite already existing mapping */
|
||||
*found = value;
|
||||
|
Loading…
x
Reference in New Issue
Block a user