1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
35 #define INITIAL_N_BUCKETS 31
37 struct hashmap_entry {
40 struct hashmap_entry *bucket_next, *bucket_previous;
41 struct hashmap_entry *iterate_next, *iterate_previous;
45 hash_func_t hash_func;
46 compare_func_t compare_func;
48 struct hashmap_entry *iterate_list_head, *iterate_list_tail;
50 struct hashmap_entry ** buckets;
51 unsigned n_buckets, n_entries;
62 static struct pool *first_hashmap_pool = NULL;
63 static void *first_hashmap_tile = NULL;
65 static struct pool *first_entry_pool = NULL;
66 static void *first_entry_tile = NULL;
68 static void* allocate_tile(struct pool **first_pool, void **first_tile, size_t tile_size) {
71 /* When a tile is released we add it to the list and simply
72 * place the next pointer at its offset 0. */
74 assert(tile_size >= sizeof(void*));
80 *first_tile = * (void**) (*first_tile);
84 if (_unlikely_(!*first_pool) || _unlikely_((*first_pool)->n_used >= (*first_pool)->n_tiles)) {
89 n = *first_pool ? (*first_pool)->n_tiles : 0;
91 size = PAGE_ALIGN(ALIGN(sizeof(struct pool)) + n*tile_size);
92 n = (unsigned)((size - ALIGN(sizeof(struct pool))) / tile_size);
98 p->next = *first_pool;
105 i = (*first_pool)->n_used++;
107 return ((uint8_t*) (*first_pool)) + ALIGN(sizeof(struct pool)) + i*tile_size;
110 static void deallocate_tile(void **first_tile, void *p) {
111 * (void**) p = *first_tile;
117 static void drop_pool(struct pool *p) {
126 __attribute__((destructor)) static void cleanup_pool(void) {
127 /* Be nice to valgrind */
129 drop_pool(first_hashmap_pool);
130 drop_pool(first_entry_pool);
135 unsigned string_hash_func(const void *p) {
136 unsigned hash = 5381;
137 const signed char *c;
139 /* DJB's hash function */
142 hash = (hash << 5) + hash + (unsigned) *c;
147 int string_compare_func(const void *a, const void *b) {
151 unsigned trivial_hash_func(const void *p) {
152 return PTR_TO_UINT(p);
155 int trivial_compare_func(const void *a, const void *b) {
156 return a < b ? -1 : (a > b ? 1 : 0);
159 unsigned uint64_hash_func(const void *p) {
162 assert(sizeof(uint64_t) == 2*sizeof(unsigned));
164 u = *(const uint64_t*) p;
166 return (unsigned) ((u >> 32) ^ u);
169 int uint64_compare_func(const void *_a, const void *_b) {
172 a = *(const uint64_t*) _a;
173 b = *(const uint64_t*) _b;
175 return a < b ? -1 : (a > b ? 1 : 0);
178 Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func) {
182 size = ALIGN(sizeof(Hashmap)) + INITIAL_N_BUCKETS * sizeof(struct hashmap_entry*);
184 h = allocate_tile(&first_hashmap_pool, &first_hashmap_tile, size);
188 h->hash_func = hash_func ? hash_func : trivial_hash_func;
189 h->compare_func = compare_func ? compare_func : trivial_compare_func;
191 h->n_buckets = INITIAL_N_BUCKETS;
193 h->iterate_list_head = h->iterate_list_tail = NULL;
195 h->buckets = (struct hashmap_entry**) ((uint8_t*) h + ALIGN(sizeof(Hashmap)));
201 int hashmap_ensure_allocated(Hashmap **h, hash_func_t hash_func, compare_func_t compare_func) {
209 q = hashmap_new(hash_func, compare_func);
216 static void link_entry(Hashmap *h, struct hashmap_entry *e, unsigned hash) {
220 /* Insert into hash table */
221 e->bucket_next = h->buckets[hash];
222 e->bucket_previous = NULL;
223 if (h->buckets[hash])
224 h->buckets[hash]->bucket_previous = e;
225 h->buckets[hash] = e;
227 /* Insert into iteration list */
228 e->iterate_previous = h->iterate_list_tail;
229 e->iterate_next = NULL;
230 if (h->iterate_list_tail) {
231 assert(h->iterate_list_head);
232 h->iterate_list_tail->iterate_next = e;
234 assert(!h->iterate_list_head);
235 h->iterate_list_head = e;
237 h->iterate_list_tail = e;
240 assert(h->n_entries >= 1);
243 static void unlink_entry(Hashmap *h, struct hashmap_entry *e, unsigned hash) {
247 /* Remove from iteration list */
249 e->iterate_next->iterate_previous = e->iterate_previous;
251 h->iterate_list_tail = e->iterate_previous;
253 if (e->iterate_previous)
254 e->iterate_previous->iterate_next = e->iterate_next;
256 h->iterate_list_head = e->iterate_next;
258 /* Remove from hash table bucket list */
260 e->bucket_next->bucket_previous = e->bucket_previous;
262 if (e->bucket_previous)
263 e->bucket_previous->bucket_next = e->bucket_next;
265 h->buckets[hash] = e->bucket_next;
267 assert(h->n_entries >= 1);
271 static void remove_entry(Hashmap *h, struct hashmap_entry *e) {
277 hash = h->hash_func(e->key) % h->n_buckets;
279 unlink_entry(h, e, hash);
282 deallocate_tile(&first_entry_tile, e);
287 void hashmap_free(Hashmap*h) {
289 /* Free the hashmap, but nothing in it */
296 if (h->buckets != (struct hashmap_entry**) ((uint8_t*) h + ALIGN(sizeof(Hashmap))))
300 deallocate_tile(&first_hashmap_tile, h);
305 void hashmap_free_free(Hashmap *h) {
307 /* Free the hashmap and all data objects in it, but not the
313 hashmap_clear_free(h);
317 void hashmap_free_free_free(Hashmap *h) {
319 /* Free the hashmap and all data and key objects in it */
324 hashmap_clear_free_free(h);
328 void hashmap_clear(Hashmap *h) {
332 while (h->iterate_list_head)
333 remove_entry(h, h->iterate_list_head);
336 void hashmap_clear_free(Hashmap *h) {
342 while ((p = hashmap_steal_first(h)))
346 void hashmap_clear_free_free(Hashmap *h) {
350 while (h->iterate_list_head) {
353 a = h->iterate_list_head->value;
354 b = (void*) h->iterate_list_head->key;
355 remove_entry(h, h->iterate_list_head);
362 static struct hashmap_entry *hash_scan(Hashmap *h, unsigned hash, const void *key) {
363 struct hashmap_entry *e;
365 assert(hash < h->n_buckets);
367 for (e = h->buckets[hash]; e; e = e->bucket_next)
368 if (h->compare_func(e->key, key) == 0)
374 static bool resize_buckets(Hashmap *h) {
376 struct hashmap_entry **n, *i;
380 if (_likely_(h->n_entries*4 < h->n_buckets*3))
383 /* Increase by four */
384 m = (h->n_entries+1)*4-1;
386 /* If we hit OOM we simply risk packed hashmaps... */
387 n = new0(struct hashmap_entry*, m);
391 for (i = h->iterate_list_head; i; i = i->iterate_next) {
394 hash = h->hash_func(i->key);
396 /* First, drop from old bucket table */
398 i->bucket_next->bucket_previous = i->bucket_previous;
400 if (i->bucket_previous)
401 i->bucket_previous->bucket_next = i->bucket_next;
403 h->buckets[hash % h->n_buckets] = i->bucket_next;
405 /* Then, add to new backet table */
408 i->bucket_next = n[x];
409 i->bucket_previous = NULL;
411 n[x]->bucket_previous = i;
415 if (h->buckets != (struct hashmap_entry**) ((uint8_t*) h + ALIGN(sizeof(Hashmap))))
424 int hashmap_put(Hashmap *h, const void *key, void *value) {
425 struct hashmap_entry *e;
430 hash = h->hash_func(key) % h->n_buckets;
431 e = hash_scan(h, hash, key);
433 if (e->value == value)
438 if (resize_buckets(h))
439 hash = h->hash_func(key) % h->n_buckets;
442 e = allocate_tile(&first_entry_pool, &first_entry_tile, sizeof(struct hashmap_entry));
444 e = new(struct hashmap_entry, 1);
452 link_entry(h, e, hash);
457 int hashmap_replace(Hashmap *h, const void *key, void *value) {
458 struct hashmap_entry *e;
463 hash = h->hash_func(key) % h->n_buckets;
464 e = hash_scan(h, hash, key);
471 return hashmap_put(h, key, value);
474 int hashmap_update(Hashmap *h, const void *key, void *value) {
475 struct hashmap_entry *e;
480 hash = h->hash_func(key) % h->n_buckets;
481 e = hash_scan(h, hash, key);
489 void* hashmap_get(Hashmap *h, const void *key) {
491 struct hashmap_entry *e;
496 hash = h->hash_func(key) % h->n_buckets;
497 e = hash_scan(h, hash, key);
504 void* hashmap_get2(Hashmap *h, const void *key, void **key2) {
506 struct hashmap_entry *e;
511 hash = h->hash_func(key) % h->n_buckets;
512 e = hash_scan(h, hash, key);
517 *key2 = (void*) e->key;
522 bool hashmap_contains(Hashmap *h, const void *key) {
528 hash = h->hash_func(key) % h->n_buckets;
530 if (!hash_scan(h, hash, key))
536 void* hashmap_remove(Hashmap *h, const void *key) {
537 struct hashmap_entry *e;
544 hash = h->hash_func(key) % h->n_buckets;
546 if (!(e = hash_scan(h, hash, key)))
555 int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value) {
556 struct hashmap_entry *e;
557 unsigned old_hash, new_hash;
562 old_hash = h->hash_func(old_key) % h->n_buckets;
563 if (!(e = hash_scan(h, old_hash, old_key)))
566 new_hash = h->hash_func(new_key) % h->n_buckets;
567 if (hash_scan(h, new_hash, new_key))
570 unlink_entry(h, e, old_hash);
575 link_entry(h, e, new_hash);
580 int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_key, void *value) {
581 struct hashmap_entry *e, *k;
582 unsigned old_hash, new_hash;
587 old_hash = h->hash_func(old_key) % h->n_buckets;
588 if (!(e = hash_scan(h, old_hash, old_key)))
591 new_hash = h->hash_func(new_key) % h->n_buckets;
592 if ((k = hash_scan(h, new_hash, new_key)))
596 unlink_entry(h, e, old_hash);
601 link_entry(h, e, new_hash);
606 void* hashmap_remove_value(Hashmap *h, const void *key, void *value) {
607 struct hashmap_entry *e;
613 hash = h->hash_func(key) % h->n_buckets;
615 e = hash_scan(h, hash, key);
619 if (e->value != value)
627 void *hashmap_iterate(Hashmap *h, Iterator *i, const void **key) {
628 struct hashmap_entry *e;
635 if (*i == ITERATOR_LAST)
638 if (*i == ITERATOR_FIRST && !h->iterate_list_head)
641 e = *i == ITERATOR_FIRST ? h->iterate_list_head : (struct hashmap_entry*) *i;
644 *i = (Iterator) e->iterate_next;
662 void *hashmap_iterate_backwards(Hashmap *h, Iterator *i, const void **key) {
663 struct hashmap_entry *e;
670 if (*i == ITERATOR_FIRST)
673 if (*i == ITERATOR_LAST && !h->iterate_list_tail)
676 e = *i == ITERATOR_LAST ? h->iterate_list_tail : (struct hashmap_entry*) *i;
678 if (e->iterate_previous)
679 *i = (Iterator) e->iterate_previous;
697 void *hashmap_iterate_skip(Hashmap *h, const void *key, Iterator *i) {
699 struct hashmap_entry *e;
704 hash = h->hash_func(key) % h->n_buckets;
706 e = hash_scan(h, hash, key);
715 void* hashmap_first(Hashmap *h) {
720 if (!h->iterate_list_head)
723 return h->iterate_list_head->value;
726 void* hashmap_first_key(Hashmap *h) {
731 if (!h->iterate_list_head)
734 return (void*) h->iterate_list_head->key;
737 void* hashmap_last(Hashmap *h) {
742 if (!h->iterate_list_tail)
745 return h->iterate_list_tail->value;
748 void* hashmap_steal_first(Hashmap *h) {
754 if (!h->iterate_list_head)
757 data = h->iterate_list_head->value;
758 remove_entry(h, h->iterate_list_head);
763 void* hashmap_steal_first_key(Hashmap *h) {
769 if (!h->iterate_list_head)
772 key = (void*) h->iterate_list_head->key;
773 remove_entry(h, h->iterate_list_head);
778 unsigned hashmap_size(Hashmap *h) {
786 unsigned hashmap_buckets(Hashmap *h) {
794 bool hashmap_isempty(Hashmap *h) {
799 return h->n_entries == 0;
802 int hashmap_merge(Hashmap *h, Hashmap *other) {
803 struct hashmap_entry *e;
810 for (e = other->iterate_list_head; e; e = e->iterate_next) {
813 if ((r = hashmap_put(h, e->key, e->value)) < 0)
821 void hashmap_move(Hashmap *h, Hashmap *other) {
822 struct hashmap_entry *e, *n;
826 /* The same as hashmap_merge(), but every new item from other
827 * is moved to h. This function is guaranteed to succeed. */
832 for (e = other->iterate_list_head; e; e = n) {
833 unsigned h_hash, other_hash;
837 h_hash = h->hash_func(e->key) % h->n_buckets;
839 if (hash_scan(h, h_hash, e->key))
842 other_hash = other->hash_func(e->key) % other->n_buckets;
844 unlink_entry(other, e, other_hash);
845 link_entry(h, e, h_hash);
849 int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key) {
850 unsigned h_hash, other_hash;
851 struct hashmap_entry *e;
858 h_hash = h->hash_func(key) % h->n_buckets;
859 if (hash_scan(h, h_hash, key))
862 other_hash = other->hash_func(key) % other->n_buckets;
863 e = hash_scan(other, other_hash, key);
867 unlink_entry(other, e, other_hash);
868 link_entry(h, e, h_hash);
873 Hashmap *hashmap_copy(Hashmap *h) {
878 copy = hashmap_new(h->hash_func, h->compare_func);
882 if (hashmap_merge(copy, h) < 0) {
890 char **hashmap_get_strv(Hashmap *h) {
896 sv = new(char*, h->n_entries+1);
901 HASHMAP_FOREACH(item, h, it)
908 void *hashmap_next(Hashmap *h, const void *key) {
910 struct hashmap_entry *e;
918 hash = h->hash_func(key) % h->n_buckets;
919 e = hash_scan(h, hash, key);