9e42da07a936220dcae41ad1593a32af78a6a9d3
[project/opkg-lede.git] / libopkg / hash_table.c
1 /* hash.c - hash tables for opkg
2
3 Steven M. Ayer, Jamey Hicks
4
5 Copyright (C) 2002 Compaq Computer Corporation
6
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.
11
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.
16 */
17
18 #include <errno.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include "hash_table.h"
23 #include "opkg_message.h"
24 #include "libbb/libbb.h"
25
26
27 static int hash_index(hash_table_t *hash, const char *pkg_name);
28 static int rotating(const char *key, int len, int prime);
29
30 static int hash_index(hash_table_t *hash, const char *pkg_name)
31 {
32 return rotating(pkg_name, strlen(pkg_name), hash->n_entries);
33 }
34
35 static int rotating(const char *key, int len, int prime)
36 {
37 unsigned int hash, i;
38 for (hash=len, i=0; i<len; ++i)
39 hash = (hash<<4)^(hash>>28)^key[i];
40 return (hash % prime);
41 }
42
43
44 /*
45 * this is an open table keyed by strings
46 */
47 int hash_table_init(const char *name, hash_table_t *hash, int len)
48 {
49 static int primes_table[] = {
50 379, 761, 983, 1423, 2711, 3361, 3931, 4679, 5519, 6701, 9587,
51 19471, 23143, 33961, 46499, 49727, 99529, 0
52 };
53 int *picker;
54
55 if (hash->entries != NULL) {
56 /* we have been here already */
57 return 0;
58 }
59
60 hash->name = name;
61 hash->entries = NULL;
62 hash->n_entries = 0;
63 hash->hash_entry_key = NULL;
64
65 picker = primes_table;
66 while(*picker && (*picker++ < len));
67 if(!*picker)
68 fprintf(stderr, "%s: primes table might not be big enough (! << %d)\n", __FUNCTION__, len);
69 --picker;
70
71 hash->n_entries = *picker;
72 hash->entries = xcalloc(hash->n_entries, sizeof(hash_entry_t));
73
74 return 0;
75 }
76
77 void hash_table_deinit(hash_table_t *hash)
78 {
79 int i;
80 if (!hash)
81 return;
82
83 /* free the reminaing entries */
84 for (i = 0; i < hash->n_entries; i++) {
85 hash_entry_t *hash_entry = (hash->entries + i);
86 free (hash_entry->key);
87 /* skip the first entry as this is part of the array */
88 hash_entry = hash_entry->next;
89 while (hash_entry)
90 {
91 hash_entry_t *old = hash_entry;
92 hash_entry = hash_entry->next;
93 free (old->key);
94 free (old);
95 }
96 }
97
98 free (hash->entries);
99
100 hash->entries = NULL;
101 hash->n_entries = 0;
102 }
103
104 void *hash_table_get(hash_table_t *hash, const char *key)
105 {
106 int ndx= hash_index(hash, key);
107 hash_entry_t *hash_entry = hash->entries + ndx;
108 while (hash_entry)
109 {
110 if (hash_entry->key)
111 {
112 if (strcmp(key, hash_entry->key) == 0) {
113 // opkg_message(NULL, OPKG_DEBUG, "Function: %s. Key found for '%s' \n", __FUNCTION__, key);
114 return hash_entry->data;
115 }
116 }
117 hash_entry = hash_entry->next;
118 }
119 return NULL;
120 }
121
122 int hash_table_insert(hash_table_t *hash, const char *key, void *value)
123 {
124 int ndx= hash_index(hash, key);
125 hash_entry_t *hash_entry = hash->entries + ndx;
126 if (hash_entry->key) {
127 if (strcmp(hash_entry->key, key) == 0) {
128 /* alread in table, update the value */
129 hash_entry->data = value;
130 return 0;
131 } else {
132 /*
133 * if this is a collision, we have to go to the end of the ll,
134 * then add a new entry
135 * before we can hook up the value
136 */
137 while (hash_entry->next) {
138 hash_entry = hash_entry->next;
139 if (strcmp(hash_entry->key, key) == 0) {
140 hash_entry->data = value;
141 return 0;
142 }
143 }
144 hash_entry->next = xcalloc(1, sizeof(hash_entry_t));
145 hash_entry = hash_entry->next;
146 hash_entry->next = NULL;
147 }
148 }
149 hash->n_elements++;
150 hash_entry->key = xstrdup(key);
151 hash_entry->data = value;
152
153 return 0;
154 }
155
156 int hash_table_remove(hash_table_t *hash, const char *key)
157 {
158 int ndx= hash_index(hash, key);
159 hash_entry_t *hash_entry = hash->entries + ndx;
160 hash_entry_t *next_entry=NULL, *last_entry=NULL;
161 while (hash_entry)
162 {
163 if (hash_entry->key)
164 {
165 if (strcmp(key, hash_entry->key) == 0) {
166 free(hash_entry->key);
167 if (last_entry) {
168 last_entry->next = hash_entry->next;
169 free(hash_entry);
170 } else {
171 next_entry = hash_entry->next;
172 if (next_entry) {
173 memmove(hash_entry, next_entry, sizeof(hash_entry_t));
174 free(next_entry);
175 } else {
176 memset(hash_entry, 0 , sizeof(hash_entry_t));
177 }
178 }
179 return 1;
180 }
181 }
182 last_entry = hash_entry;
183 hash_entry = hash_entry->next;
184 }
185 return 0;
186 }
187
188 void hash_table_foreach(hash_table_t *hash, void (*f)(const char *key, void *entry, void *data), void *data)
189 {
190 int i;
191 if (!hash || !f)
192 return;
193
194 for (i = 0; i < hash->n_entries; i++) {
195 hash_entry_t *hash_entry = (hash->entries + i);
196 do {
197 if(hash_entry->key) {
198 f(hash_entry->key, hash_entry->data, data);
199 }
200 } while((hash_entry = hash_entry->next));
201 }
202 }
203