1 /* hash.c - hash tables for opkg
3 Steven M. Ayer, Jamey Hicks
5 Copyright (C) 2002 Compaq Computer Corporation
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2, or (at
10 your option) any later version.
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
21 #include "hash_table.h"
22 #include "opkg_message.h"
23 #include "libbb/libbb.h"
27 djb2_hash(const unsigned char *str)
29 unsigned long hash = 5381;
32 hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
37 hash_index(hash_table_t *hash, const char *key)
39 return djb2_hash((const unsigned char *)key) % hash->n_buckets;
43 * this is an open table keyed by strings
46 hash_table_init(const char *name, hash_table_t *hash, int len)
48 if (hash->entries != NULL) {
49 fprintf(stderr, "ERROR: %s called on a non empty hash table\n",
54 memset(hash, 0, sizeof(hash_table_t));
57 hash->n_buckets = len;
58 hash->entries = xcalloc(hash->n_buckets, sizeof(hash_entry_t));
62 hash_print_stats(hash_table_t *hash)
64 printf("hash_table: %s, %d bytes\n"
65 "\tn_buckets=%d, n_elements=%d, n_collisions=%d\n"
66 "\tmax_bucket_len=%d, n_used_buckets=%d, ave_bucket_len=%.2f\n"
67 "\tn_hits=%d, n_misses=%d\n",
69 hash->n_buckets*(int)sizeof(hash_entry_t),
75 (hash->n_used_buckets ?
76 ((float)hash->n_elements)/hash->n_used_buckets : 0.0f),
81 void hash_table_deinit(hash_table_t *hash)
87 /* free the reminaing entries */
88 for (i = 0; i < hash->n_buckets; i++) {
89 hash_entry_t *hash_entry = (hash->entries + i);
90 free (hash_entry->key);
91 /* skip the first entry as this is part of the array */
92 hash_entry = hash_entry->next;
95 hash_entry_t *old = hash_entry;
96 hash_entry = hash_entry->next;
102 free (hash->entries);
104 hash->entries = NULL;
108 void *hash_table_get(hash_table_t *hash, const char *key)
110 int ndx= hash_index(hash, key);
111 hash_entry_t *hash_entry = hash->entries + ndx;
116 if (strcmp(key, hash_entry->key) == 0) {
117 // opkg_message(NULL, OPKG_DEBUG, "Function: %s. Key found for '%s' \n", __FUNCTION__, key);
119 return hash_entry->data;
122 hash_entry = hash_entry->next;
128 int hash_table_insert(hash_table_t *hash, const char *key, void *value)
131 int ndx= hash_index(hash, key);
132 hash_entry_t *hash_entry = hash->entries + ndx;
133 if (hash_entry->key) {
134 if (strcmp(hash_entry->key, key) == 0) {
135 /* alread in table, update the value */
136 hash_entry->data = value;
140 * if this is a collision, we have to go to the end of the ll,
141 * then add a new entry
142 * before we can hook up the value
144 while (hash_entry->next) {
145 hash_entry = hash_entry->next;
146 if (strcmp(hash_entry->key, key) == 0) {
147 hash_entry->data = value;
152 hash_entry->next = xcalloc(1, sizeof(hash_entry_t));
153 hash_entry = hash_entry->next;
154 hash_entry->next = NULL;
156 hash->n_collisions++;
157 if (++bucket_len > hash->max_bucket_len)
158 hash->max_bucket_len = bucket_len;
161 hash->n_used_buckets++;
164 hash_entry->key = xstrdup(key);
165 hash_entry->data = value;
170 int hash_table_remove(hash_table_t *hash, const char *key)
172 int ndx= hash_index(hash, key);
173 hash_entry_t *hash_entry = hash->entries + ndx;
174 hash_entry_t *next_entry=NULL, *last_entry=NULL;
179 if (strcmp(key, hash_entry->key) == 0) {
180 free(hash_entry->key);
182 last_entry->next = hash_entry->next;
185 next_entry = hash_entry->next;
187 memmove(hash_entry, next_entry, sizeof(hash_entry_t));
190 memset(hash_entry, 0 , sizeof(hash_entry_t));
196 last_entry = hash_entry;
197 hash_entry = hash_entry->next;
202 void hash_table_foreach(hash_table_t *hash, void (*f)(const char *key, void *entry, void *data), void *data)
208 for (i = 0; i < hash->n_buckets; i++) {
209 hash_entry_t *hash_entry = (hash->entries + i);
211 if(hash_entry->key) {
212 f(hash_entry->key, hash_entry->data, data);
214 } while((hash_entry = hash_entry->next));