hashmap.c revision 9946996cda11a18b44d82344676e5a0e96339408
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2010 Lennart Poettering
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "util.h"
#include "hashmap.h"
#include "macro.h"
#define NBUCKETS 127
struct hashmap_entry {
const void *key;
void *value;
};
struct Hashmap {
unsigned n_entries;
bool from_pool;
};
struct pool {
unsigned n_tiles;
unsigned n_used;
};
static void *first_hashmap_tile = NULL;
static void *first_entry_tile = NULL;
unsigned i;
if (*first_tile) {
void *r;
r = *first_tile;
*first_tile = * (void**) (*first_tile);
return r;
}
unsigned n;
struct pool *p;
if (!p)
return NULL;
p->next = *first_pool;
p->n_tiles = n;
p->n_used = 0;
*first_pool = p;
}
i = (*first_pool)->n_used++;
}
static void deallocate_tile(void **first_tile, void *p) {
* (void**) p = *first_tile;
*first_tile = p;
}
#ifndef __OPTIMIZE__
while (p) {
struct pool *n;
n = p->next;
free(p);
p = n;
}
}
/* Be nice to valgrind */
}
#endif
unsigned string_hash_func(const void *p) {
unsigned hash = 5381;
const signed char *c;
/* DJB's hash function */
for (c = p; *c; c++)
return hash;
}
int string_compare_func(const void *a, const void *b) {
return strcmp(a, b);
}
unsigned trivial_hash_func(const void *p) {
return PTR_TO_UINT(p);
}
int trivial_compare_func(const void *a, const void *b) {
return a < b ? -1 : (a > b ? 1 : 0);
}
bool b;
Hashmap *h;
b = is_main_thread();
if (b) {
if (!h)
return NULL;
} else {
if (!h)
return NULL;
}
h->n_entries = 0;
h->from_pool = b;
return h;
}
assert(h);
if (*h)
return 0;
return -ENOMEM;
return 0;
}
assert(h);
assert(e);
/* Insert into hash table */
e->bucket_previous = NULL;
/* Insert into iteration list */
e->iterate_previous = h->iterate_list_tail;
e->iterate_next = NULL;
if (h->iterate_list_tail) {
assert(h->iterate_list_head);
h->iterate_list_tail->iterate_next = e;
} else {
assert(!h->iterate_list_head);
h->iterate_list_head = e;
}
h->iterate_list_tail = e;
h->n_entries++;
}
assert(h);
assert(e);
/* Remove from iteration list */
if (e->iterate_next)
else
h->iterate_list_tail = e->iterate_previous;
if (e->iterate_previous)
else
h->iterate_list_head = e->iterate_next;
/* Remove from hash table bucket list */
if (e->bucket_next)
if (e->bucket_previous)
else
h->n_entries--;
}
unsigned hash;
assert(h);
assert(e);
unlink_entry(h, e, hash);
if (h->from_pool)
else
free(e);
}
void hashmap_free(Hashmap*h) {
if (!h)
return;
hashmap_clear(h);
if (h->from_pool)
else
free(h);
}
void hashmap_free_free(Hashmap *h) {
hashmap_free(h);
}
void hashmap_clear(Hashmap *h) {
if (!h)
return;
while (h->iterate_list_head)
remove_entry(h, h->iterate_list_head);
}
void hashmap_clear_free(Hashmap *h) {
void *p;
assert(h);
while ((p = hashmap_steal_first(h)))
free(p);
}
struct hashmap_entry *e;
assert(h);
return e;
return NULL;
}
struct hashmap_entry *e;
unsigned hash;
assert(h);
return 0;
return -EEXIST;
}
if (h->from_pool)
else
if (!e)
return -ENOMEM;
link_entry(h, e, hash);
return 1;
}
struct hashmap_entry *e;
unsigned hash;
assert(h);
return 0;
}
}
unsigned hash;
struct hashmap_entry *e;
if (!h)
return NULL;
return NULL;
return e->value;
}
struct hashmap_entry *e;
unsigned hash;
void *data;
if (!h)
return NULL;
return NULL;
remove_entry(h, e);
return data;
}
struct hashmap_entry *e;
if (!h)
return -ENOENT;
return -ENOENT;
return -EEXIST;
unlink_entry(h, e, old_hash);
link_entry(h, e, new_hash);
return 0;
}
struct hashmap_entry *e, *k;
if (!h)
return -ENOENT;
return -ENOENT;
if (e != k)
remove_entry(h, k);
unlink_entry(h, e, old_hash);
link_entry(h, e, new_hash);
return 0;
}
struct hashmap_entry *e;
unsigned hash;
if (!h)
return NULL;
return NULL;
return NULL;
remove_entry(h, e);
return value;
}
struct hashmap_entry *e;
assert(i);
if (!h)
goto at_end;
if (*i == ITERATOR_LAST)
goto at_end;
if (*i == ITERATOR_FIRST && !h->iterate_list_head)
goto at_end;
if (e->iterate_next)
*i = (Iterator) e->iterate_next;
else
*i = ITERATOR_LAST;
if (key)
return e->value;
*i = ITERATOR_LAST;
if (key)
return NULL;
}
struct hashmap_entry *e;
assert(i);
if (!h)
goto at_beginning;
if (*i == ITERATOR_FIRST)
goto at_beginning;
if (*i == ITERATOR_LAST && !h->iterate_list_tail)
goto at_beginning;
if (e->iterate_previous)
*i = (Iterator) e->iterate_previous;
else
*i = ITERATOR_FIRST;
if (key)
return e->value;
*i = ITERATOR_FIRST;
if (key)
return NULL;
}
unsigned hash;
struct hashmap_entry *e;
if (!h)
return NULL;
return NULL;
*i = (Iterator) e;
return e->value;
}
void* hashmap_first(Hashmap *h) {
if (!h)
return NULL;
if (!h->iterate_list_head)
return NULL;
return h->iterate_list_head->value;
}
void* hashmap_first_key(Hashmap *h) {
if (!h)
return NULL;
if (!h->iterate_list_head)
return NULL;
return (void*) h->iterate_list_head->key;
}
void* hashmap_last(Hashmap *h) {
if (!h)
return NULL;
if (!h->iterate_list_tail)
return NULL;
return h->iterate_list_tail->value;
}
void* hashmap_steal_first(Hashmap *h) {
void *data;
if (!h)
return NULL;
if (!h->iterate_list_head)
return NULL;
remove_entry(h, h->iterate_list_head);
return data;
}
void* hashmap_steal_first_key(Hashmap *h) {
void *key;
if (!h)
return NULL;
if (!h->iterate_list_head)
return NULL;
remove_entry(h, h->iterate_list_head);
return key;
}
unsigned hashmap_size(Hashmap *h) {
if (!h)
return 0;
return h->n_entries;
}
bool hashmap_isempty(Hashmap *h) {
if (!h)
return true;
return h->n_entries == 0;
}
struct hashmap_entry *e;
assert(h);
if (!other)
return 0;
int r;
if (r != -EEXIST)
return r;
}
return 0;
}
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. */
if (!other)
return;
for (e = other->iterate_list_head; e; e = n) {
unsigned h_hash, other_hash;
n = e->iterate_next;
continue;
link_entry(h, e, h_hash);
}
}
unsigned h_hash, other_hash;
struct hashmap_entry *e;
if (!other)
return 0;
assert(h);
return -EEXIST;
return -ENOENT;
link_entry(h, e, h_hash);
return 0;
}
assert(h);
return NULL;
if (hashmap_merge(copy, h) < 0) {
return NULL;
}
return copy;
}
char **hashmap_get_strv(Hashmap *h) {
char **sv;
char *item;
int n;
if (!sv)
return NULL;
n = 0;
return sv;
}