chiark
/
gitweb
/
~ianmdlvl
/
elogind.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
hashmap: allow hashmap_move() to fail
[elogind.git]
/
src
/
shared
/
hashmap.c
diff --git
a/src/shared/hashmap.c
b/src/shared/hashmap.c
index 1c3a452899920c9ac5322863aec1c94db8f370bc..6f5f8204dd3dd0d2c733862edaa0b48662af3595 100644
(file)
--- a/
src/shared/hashmap.c
+++ b/
src/shared/hashmap.c
@@
-369,23
+369,31
@@
static struct hashmap_entry *hash_scan(Hashmap *h, unsigned hash, const void *ke
return NULL;
}
return NULL;
}
-static
bool resize_buckets(Hashmap *h
) {
+static
int resize_buckets(Hashmap *h, unsigned entries_add
) {
struct hashmap_entry **n, *i;
struct hashmap_entry **n, *i;
- unsigned m;
+ unsigned m
, new_n_entries, new_n_buckets
;
uint8_t nkey[HASH_KEY_SIZE];
assert(h);
uint8_t nkey[HASH_KEY_SIZE];
assert(h);
- if (_likely_(h->n_entries*4 < h->n_buckets*3))
- return false;
+ 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);
if (!n)
/* If we hit OOM we simply risk packed hashmaps... */
n = new0(struct hashmap_entry*, m);
if (!n)
- return
false
;
+ return
-ENOMEM
;
/* Let's use a different randomized hash key for the
* extension, so that people cannot guess what we are using
/* Let's use a different randomized hash key for the
* extension, so that people cannot guess what we are using
@@
-424,7
+432,7
@@
static bool resize_buckets(Hashmap *h) {
memcpy(h->hash_key, nkey, HASH_KEY_SIZE);
memcpy(h->hash_key, nkey, HASH_KEY_SIZE);
- return
true
;
+ return
1
;
}
static int __hashmap_put(Hashmap *h, const void *key, void *value, unsigned hash) {
}
static int __hashmap_put(Hashmap *h, const void *key, void *value, unsigned hash) {
@@
-432,7
+440,7
@@
static int __hashmap_put(Hashmap *h, const void *key, void *value, unsigned hash
struct hashmap_entry *e;
struct hashmap_entry *e;
- if (resize_buckets(h
)
)
+ if (resize_buckets(h
, 1) > 0
)
hash = bucket_hash(h, key);
if (h->from_pool)
hash = bucket_hash(h, key);
if (h->from_pool)
@@
-795,16
+803,28
@@
int hashmap_merge(Hashmap *h, Hashmap *other) {
return 0;
}
return 0;
}
-void hashmap_move(Hashmap *h, Hashmap *other) {
+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;
+}
+
+int hashmap_move(Hashmap *h, Hashmap *other) {
struct hashmap_entry *e, *n;
assert(h);
/* The same as hashmap_merge(), but every new item from other
struct hashmap_entry *e, *n;
assert(h);
/* The same as hashmap_merge(), but every new item from other
- * is moved to h.
This function is guaranteed to succeed.
*/
+ * is moved to h. */
if (!other)
if (!other)
- return;
+ return
0
;
for (e = other->iterate_list_head; e; e = n) {
unsigned h_hash, other_hash;
for (e = other->iterate_list_head; e; e = n) {
unsigned h_hash, other_hash;
@@
-819,6
+839,8
@@
void hashmap_move(Hashmap *h, Hashmap *other) {
unlink_entry(other, e, other_hash);
link_entry(h, e, h_hash);
}
unlink_entry(other, e, other_hash);
link_entry(h, e, h_hash);
}
+
+ return 0;
}
int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key) {
}
int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key) {