Skip to content

Commit 1ff4529

Browse files
committed
#124 improve map rehashing
1 parent a2d2fee commit 1ff4529

3 files changed

Lines changed: 78 additions & 72 deletions

File tree

flecs.c

Lines changed: 39 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -12440,7 +12440,7 @@ int32_t ecs_strbuf_written(
1244012440

1244112441
/* The ratio used to determine whether the map should rehash. If
1244212442
* (element_count * LOAD_FACTOR) > bucket_count, bucket count is increased. */
12443-
#define LOAD_FACTOR (1.5f)
12443+
#define LOAD_FACTOR (1.2f)
1244412444
#define KEY_SIZE (ECS_SIZEOF(ecs_map_key_t))
1244512445
#define GET_ELEM(array, elem_size, index) \
1244612446
ECS_OFFSET(array, (elem_size) * (index))
@@ -12571,19 +12571,18 @@ int32_t add_to_bucket(
1257112571
const void *payload)
1257212572
{
1257312573
int32_t index = bucket->count ++;
12574-
int32_t bucket_count = index + 1;
12574+
int32_t count = index + 1;
12575+
12576+
bucket->keys = ecs_os_realloc_n(bucket->keys, ecs_map_key_t, count);
12577+
if (elem_size) {
12578+
bucket->payload = ecs_os_realloc(bucket->payload, elem_size * count);
12579+
}
1257512580

12576-
bucket->keys = ecs_os_realloc(bucket->keys, KEY_SIZE * bucket_count);
1257712581
bucket->keys[index] = key;
1257812582

12579-
if (elem_size) {
12580-
bucket->payload = ecs_os_realloc(bucket->payload, elem_size * bucket_count);
12581-
if (payload) {
12582-
void *elem = GET_ELEM(bucket->payload, elem_size, index);
12583-
ecs_os_memcpy(elem, payload, elem_size);
12584-
}
12585-
} else {
12586-
bucket->payload = NULL;
12583+
if (elem_size && payload) {
12584+
void *elem = GET_ELEM(bucket->payload, elem_size, index);
12585+
ecs_os_memcpy(elem, payload, elem_size);
1258712586
}
1258812587

1258912588
return index;
@@ -12642,44 +12641,48 @@ void rehash(
1264212641
ecs_assert(bucket_count != 0, ECS_INTERNAL_ERROR, NULL);
1264312642
ecs_assert(bucket_count > map->bucket_count, ECS_INTERNAL_ERROR, NULL);
1264412643

12645-
ensure_buckets(map, bucket_count);
12646-
12647-
ecs_bucket_t *buckets = map->buckets;
12648-
ecs_assert(buckets != NULL, ECS_INTERNAL_ERROR, NULL);
12644+
ecs_bucket_t *old_buckets = map->buckets;
1264912645
ecs_size_t elem_size = map->elem_size;
12650-
uint16_t bucket_shift = map->bucket_shift;
12651-
int32_t bucket_id;
1265212646

12653-
/* Iterate backwards as elements could otherwise be moved to existing
12654-
* buckets which could temporarily cause the number of elements in a
12655-
* bucket to exceed BUCKET_COUNT. */
12656-
for (bucket_id = bucket_count - 1; bucket_id >= 0; bucket_id --) {
12657-
ecs_bucket_t *bucket = &buckets[bucket_id];
12647+
int32_t b, old_count = map->bucket_count;
12648+
int32_t new_count = flecs_next_pow_of_2(bucket_count);
12649+
12650+
map->buckets = ecs_os_calloc_n(ecs_bucket_t, new_count);
12651+
map->bucket_count = new_count;
12652+
uint8_t bucket_shift = map->bucket_shift = get_bucket_shift(new_count);
12653+
12654+
for (b = 0; b < old_count; b ++) {
12655+
ecs_bucket_t *old = &old_buckets[b];
1265812656

12659-
int i, count = bucket->count;
12660-
ecs_map_key_t *key_array = bucket->keys;
12661-
void *payload_array = bucket->payload;
12657+
int i, count = old->count;
12658+
ecs_map_key_t *keys = old->keys;
12659+
void *payload = old->payload;
1266212660

1266312661
for (i = 0; i < count; i ++) {
12664-
ecs_map_key_t key = key_array[i];
12665-
void *elem = GET_ELEM(payload_array, elem_size, i);
12662+
ecs_map_key_t key = keys[i];
12663+
void *elem = GET_ELEM(payload, elem_size, i);
1266612664
int32_t new_bucket_id = get_bucket_index(map, bucket_shift, key);
1266712665

12668-
if (new_bucket_id != bucket_id) {
12669-
ecs_bucket_t *new_bucket = &buckets[new_bucket_id];
12666+
ecs_bucket_t *new_bucket = &map->buckets[new_bucket_id];
1267012667

12668+
if (count == 1 && !new_bucket->count) {
12669+
new_bucket->keys = keys;
12670+
new_bucket->payload = payload;
12671+
new_bucket->count = 1;
12672+
keys = NULL;
12673+
payload = NULL;
12674+
} else {
1267112675
add_to_bucket(new_bucket, elem_size, key, elem);
12672-
remove_from_bucket(bucket, elem_size, key, i);
12673-
12674-
count --;
12675-
i --;
1267612676
}
1267712677
}
1267812678

12679-
if (!bucket->count) {
12680-
clear_bucket(bucket);
12679+
if (count) {
12680+
ecs_os_free(keys);
12681+
ecs_os_free(payload);
1268112682
}
1268212683
}
12684+
12685+
ecs_os_free(old_buckets);
1268312686
}
1268412687

1268512688
void _ecs_map_init(
@@ -39368,7 +39371,7 @@ void ecs_table_cache_init(
3936839371
ecs_table_cache_t *cache)
3936939372
{
3937039373
ecs_assert(cache != NULL, ECS_INTERNAL_ERROR, NULL);
39371-
ecs_map_init(&cache->index, ecs_table_cache_hdr_t*, 0);
39374+
ecs_map_init(&cache->index, ecs_table_cache_hdr_t*, 4);
3937239375
}
3937339376

3937439377
void ecs_table_cache_fini(

src/datastructures/map.c

Lines changed: 38 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
/* The ratio used to determine whether the map should rehash. If
55
* (element_count * LOAD_FACTOR) > bucket_count, bucket count is increased. */
6-
#define LOAD_FACTOR (1.5f)
6+
#define LOAD_FACTOR (1.2f)
77
#define KEY_SIZE (ECS_SIZEOF(ecs_map_key_t))
88
#define GET_ELEM(array, elem_size, index) \
99
ECS_OFFSET(array, (elem_size) * (index))
@@ -134,19 +134,18 @@ int32_t add_to_bucket(
134134
const void *payload)
135135
{
136136
int32_t index = bucket->count ++;
137-
int32_t bucket_count = index + 1;
137+
int32_t count = index + 1;
138+
139+
bucket->keys = ecs_os_realloc_n(bucket->keys, ecs_map_key_t, count);
140+
if (elem_size) {
141+
bucket->payload = ecs_os_realloc(bucket->payload, elem_size * count);
142+
}
138143

139-
bucket->keys = ecs_os_realloc(bucket->keys, KEY_SIZE * bucket_count);
140144
bucket->keys[index] = key;
141145

142-
if (elem_size) {
143-
bucket->payload = ecs_os_realloc(bucket->payload, elem_size * bucket_count);
144-
if (payload) {
145-
void *elem = GET_ELEM(bucket->payload, elem_size, index);
146-
ecs_os_memcpy(elem, payload, elem_size);
147-
}
148-
} else {
149-
bucket->payload = NULL;
146+
if (elem_size && payload) {
147+
void *elem = GET_ELEM(bucket->payload, elem_size, index);
148+
ecs_os_memcpy(elem, payload, elem_size);
150149
}
151150

152151
return index;
@@ -205,44 +204,48 @@ void rehash(
205204
ecs_assert(bucket_count != 0, ECS_INTERNAL_ERROR, NULL);
206205
ecs_assert(bucket_count > map->bucket_count, ECS_INTERNAL_ERROR, NULL);
207206

208-
ensure_buckets(map, bucket_count);
209-
210-
ecs_bucket_t *buckets = map->buckets;
211-
ecs_assert(buckets != NULL, ECS_INTERNAL_ERROR, NULL);
207+
ecs_bucket_t *old_buckets = map->buckets;
212208
ecs_size_t elem_size = map->elem_size;
213-
uint16_t bucket_shift = map->bucket_shift;
214-
int32_t bucket_id;
215209

216-
/* Iterate backwards as elements could otherwise be moved to existing
217-
* buckets which could temporarily cause the number of elements in a
218-
* bucket to exceed BUCKET_COUNT. */
219-
for (bucket_id = bucket_count - 1; bucket_id >= 0; bucket_id --) {
220-
ecs_bucket_t *bucket = &buckets[bucket_id];
210+
int32_t b, old_count = map->bucket_count;
211+
int32_t new_count = flecs_next_pow_of_2(bucket_count);
212+
213+
map->buckets = ecs_os_calloc_n(ecs_bucket_t, new_count);
214+
map->bucket_count = new_count;
215+
uint8_t bucket_shift = map->bucket_shift = get_bucket_shift(new_count);
216+
217+
for (b = 0; b < old_count; b ++) {
218+
ecs_bucket_t *old = &old_buckets[b];
221219

222-
int i, count = bucket->count;
223-
ecs_map_key_t *key_array = bucket->keys;
224-
void *payload_array = bucket->payload;
220+
int i, count = old->count;
221+
ecs_map_key_t *keys = old->keys;
222+
void *payload = old->payload;
225223

226224
for (i = 0; i < count; i ++) {
227-
ecs_map_key_t key = key_array[i];
228-
void *elem = GET_ELEM(payload_array, elem_size, i);
225+
ecs_map_key_t key = keys[i];
226+
void *elem = GET_ELEM(payload, elem_size, i);
229227
int32_t new_bucket_id = get_bucket_index(map, bucket_shift, key);
230228

231-
if (new_bucket_id != bucket_id) {
232-
ecs_bucket_t *new_bucket = &buckets[new_bucket_id];
229+
ecs_bucket_t *new_bucket = &map->buckets[new_bucket_id];
233230

231+
if (count == 1 && !new_bucket->count) {
232+
new_bucket->keys = keys;
233+
new_bucket->payload = payload;
234+
new_bucket->count = 1;
235+
keys = NULL;
236+
payload = NULL;
237+
} else {
234238
add_to_bucket(new_bucket, elem_size, key, elem);
235-
remove_from_bucket(bucket, elem_size, key, i);
236-
237-
count --;
238-
i --;
239239
}
240240
}
241241

242-
if (!bucket->count) {
243-
clear_bucket(bucket);
242+
if (count) {
243+
ecs_os_free(keys);
244+
ecs_os_free(payload);
244245
}
245246
}
247+
248+
ecs_os_free(old_buckets);
246249
}
247250

248251
void _ecs_map_init(

src/table_cache.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ void ecs_table_cache_init(
6363
ecs_table_cache_t *cache)
6464
{
6565
ecs_assert(cache != NULL, ECS_INTERNAL_ERROR, NULL);
66-
ecs_map_init(&cache->index, ecs_table_cache_hdr_t*, 0);
66+
ecs_map_init(&cache->index, ecs_table_cache_hdr_t*, 4);
6767
}
6868

6969
void ecs_table_cache_fini(

0 commit comments

Comments
 (0)