mirror of
https://github.com/AuxXxilium/eudev.git
synced 2025-01-20 11:09:22 +07:00
hashmap: introduce hashmap_reserve()
With the current hashmap implementation that uses chaining, placing a reservation can serve two purposes: - To optimize putting of entries if the number of entries to put is known. The reservation allocates buckets, so later resizing can be avoided. - To avoid having very long bucket chains after using hashmap_move(_one). In an alternative hashmap implementation it will serve an additional purpose: - To guarantee a subsequent hashmap_move(_one) will not fail with -ENOMEM (this never happens in the current implementation). Signed-off-by: Anthony G. Basile <blueness@gentoo.org>
This commit is contained in:
parent
ac2d134b8c
commit
4531818f12
@ -276,18 +276,26 @@ static struct hashmap_entry *hash_scan(Hashmap *h, unsigned hash, const void *ke
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int resize_buckets(Hashmap *h) {
|
||||
static int resize_buckets(Hashmap *h, unsigned entries_add) {
|
||||
struct hashmap_entry **n, *i;
|
||||
unsigned m;
|
||||
unsigned m, new_n_entries, new_n_buckets;
|
||||
uint8_t nkey[HASH_KEY_SIZE];
|
||||
|
||||
assert(h);
|
||||
|
||||
if (_likely_(h->n_entries*4 < h->n_buckets*3))
|
||||
new_n_entries = h->n_entries + entries_add;
|
||||
|
||||
/* overflow? */
|
||||
if (_unlikely_(new_n_entries < entries_add || new_n_entries > UINT_MAX / 4))
|
||||
return -ENOMEM;
|
||||
|
||||
new_n_buckets = new_n_entries * 4 / 3;
|
||||
|
||||
if (_likely_(new_n_buckets <= h->n_buckets))
|
||||
return 0;
|
||||
|
||||
/* Increase by four */
|
||||
m = (h->n_entries+1)*4-1;
|
||||
/* Increase by four at least */
|
||||
m = MAX((h->n_entries+1)*4-1, new_n_buckets);
|
||||
|
||||
/* If we hit OOM we simply risk packed hashmaps... */
|
||||
n = new0(struct hashmap_entry*, m);
|
||||
@ -339,7 +347,7 @@ static int __hashmap_put(Hashmap *h, const void *key, void *value, unsigned hash
|
||||
|
||||
struct hashmap_entry *e;
|
||||
|
||||
if (resize_buckets(h) > 0)
|
||||
if (resize_buckets(h, 1) > 0)
|
||||
hash = bucket_hash(h, key);
|
||||
|
||||
if (h->from_pool)
|
||||
@ -476,6 +484,18 @@ unsigned hashmap_size(Hashmap *h) {
|
||||
return h->n_entries;
|
||||
}
|
||||
|
||||
int hashmap_reserve(Hashmap *h, unsigned entries_add) {
|
||||
int r;
|
||||
|
||||
assert(h);
|
||||
|
||||
r = resize_buckets(h, entries_add);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char **hashmap_get_strv(Hashmap *h) {
|
||||
char **sv;
|
||||
Iterator it;
|
||||
|
@ -65,6 +65,7 @@ int hashmap_put(Hashmap *h, const void *key, void *value);
|
||||
void *hashmap_get(Hashmap *h, const void *key);
|
||||
void *hashmap_get2(Hashmap *h, const void *key, void **rkey);
|
||||
bool hashmap_contains(Hashmap *h, const void *key);
|
||||
int hashmap_reserve(Hashmap *h, unsigned entries_add);
|
||||
|
||||
unsigned hashmap_size(Hashmap *h) _pure_;
|
||||
|
||||
|
@ -50,3 +50,7 @@ bool set_contains(Set *s, void *value) {
|
||||
void *set_iterate(Set *s, Iterator *i) {
|
||||
return hashmap_iterate(MAKE_HASHMAP(s), i, NULL);
|
||||
}
|
||||
|
||||
int set_reserve(Set *s, unsigned entries_add) {
|
||||
return hashmap_reserve(MAKE_HASHMAP(s), entries_add);
|
||||
}
|
||||
|
@ -37,6 +37,8 @@ int set_put(Set *s, void *value);
|
||||
void *set_get(Set *s, void *value);
|
||||
bool set_contains(Set *s, void *value);
|
||||
|
||||
int set_reserve(Set *s, unsigned entries_add);
|
||||
|
||||
void *set_iterate(Set *s, Iterator *i);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free);
|
||||
|
Loading…
Reference in New Issue
Block a user