1 /*
2 * Copyright (C) 2005 iptelorg GmbH
3 *
4 * This file is part of ser, a free SIP server.
5 *
6 * ser is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version
10 *
11 * For a license to use the ser software under conditions
12 * other than those described here, or to purchase support for this
13 * software, please contact iptel.org by e-mail at the following addresses:
14 * info@iptel.org
15 *
16 * ser is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 */
25
26 #include <cds/hash_table.h>
27 #include <cds/memory.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
ht_init(hash_table_t * ht,hash_func_t hash_func,key_cmp_func_t cmp_keys,int size)32 int ht_init(hash_table_t *ht, hash_func_t hash_func, key_cmp_func_t cmp_keys, int size)
33 {
34 if (!ht) return -1;
35 if ((!hash_func) || (!cmp_keys)) return -1;
36
37 ht->cslots = (ht_cslot_t*)cds_malloc(size * sizeof(ht_cslot_t));
38 if (!ht->cslots) return -1;
39 memset(ht->cslots, 0, size * sizeof(ht_cslot_t));
40
41 ht->size = size;
42 ht->hash = hash_func;
43 ht->cmp = cmp_keys;
44
45 ht->find_cnt = 0;
46 ht->cmp_cnt = 0;
47 ht->nocmp_cnt = 0;
48 ht->missed_cnt = 0;
49 return 0;
50 }
51
ht_destroy(hash_table_t * ht)52 void ht_destroy(hash_table_t *ht)
53 {
54 ht_element_t *e, *n;
55 int i;
56
57 if (!ht) return;
58 if (ht->cslots) {
59 for (i = 0; i < ht->size; i++) {
60 e = ht->cslots[i].first;
61 while (e) {
62 n = e->next;
63 cds_free(e);
64 e = n;
65 }
66 }
67 cds_free(ht->cslots);
68 }
69 ht->cslots = NULL;
70 }
71
ht_add(hash_table_t * ht,ht_key_t key,ht_data_t data)72 int ht_add(hash_table_t *ht, ht_key_t key, ht_data_t data)
73 {
74 int h;
75 ht_element_t *new_e;
76
77 if (!ht) return -1;
78 new_e = (ht_element_t*)cds_malloc(sizeof(ht_element_t));
79 if (!new_e) return -1;
80 new_e->next = NULL;
81 new_e->key = key;
82 new_e->data = data;
83
84 h = ht->hash(key) % ht->size;
85 if (h < 0) h = -h;
86
87 if (!ht->cslots[h].last) {
88 ht->cslots[h].first = new_e;
89 }
90 else {
91 ht->cslots[h].last->next = new_e;
92 }
93
94 ht->cslots[h].cnt++;
95 ht->cslots[h].last = new_e;
96 return 0;
97 }
98
ht_find(hash_table_t * ht,ht_key_t key)99 ht_data_t ht_find(hash_table_t *ht, ht_key_t key)
100 {
101 int h;
102 ht_element_t *e;
103
104 if (!ht) return NULL;
105
106 ht->find_cnt++; //monitor
107
108 h = ht->hash(key) % ht->size;
109 if (h < 0) h = -h;
110 e = ht->cslots[h].first;
111 if (!e) ht->nocmp_cnt++; //monitor
112 while (e) {
113 ht->cmp_cnt++; //monitor
114 if (ht->cmp(e->key, key) == 0) return e->data;
115 e = e->next;
116 }
117
118 ht->missed_cnt++; //monitor
119 return NULL;
120 }
121
ht_remove(hash_table_t * ht,ht_key_t key)122 ht_data_t ht_remove(hash_table_t *ht, ht_key_t key)
123 {
124 int h;
125 ht_element_t *e,*p;
126 ht_data_t data;
127
128 if (!ht) return NULL;
129 h = ht->hash(key) % ht->size;
130 if (h < 0) h = -h;
131 e = ht->cslots[h].first;
132 p = NULL;
133 while (e) {
134 if (ht->cmp(e->key, key) == 0) {
135 if (p) p->next = e->next;
136 else ht->cslots[h].first = e->next;
137 ht->cslots[h].cnt--;
138 if (!e->next) ht->cslots[h].last = p;
139 data = e->data;
140 cds_free(e);
141 return data;
142 }
143 p = e;
144 e = e->next;
145 }
146 return NULL;
147 }
148
ht_get_statistic(hash_table_t * ht,ht_statistic_t * s)149 void ht_get_statistic(hash_table_t *ht, ht_statistic_t *s)
150 {
151 if (!s) return;
152 if (!ht) {
153 s->find_cnt = 0;
154 s->cmp_cnt = 0;
155 s->nocmp_cnt = 0;
156 s->missed_cnt = 0;
157 }
158 else {
159 s->find_cnt = ht->find_cnt;
160 s->cmp_cnt = ht->cmp_cnt;
161 s->nocmp_cnt = ht->nocmp_cnt;
162 s->missed_cnt = ht->missed_cnt;
163 }
164 }
165
ht_clear_statistic(hash_table_t * ht)166 void ht_clear_statistic(hash_table_t *ht)
167 {
168 if (!ht) return;
169
170 ht->find_cnt = 0;
171 ht->cmp_cnt = 0;
172 ht->nocmp_cnt = 0;
173 ht->missed_cnt = 0;
174 }
175
176 /* --------- hash table traversing functions -------- */
177
get_first_ht_element(hash_table_t * ht,ht_traversal_info_t * info)178 ht_element_t *get_first_ht_element(hash_table_t *ht, ht_traversal_info_t *info)
179 {
180 int i;
181 if (!info) return NULL;
182 info->ht = ht;
183 info->current = NULL;
184 for (i = 0; i < ht->size; i++) {
185 if (ht->cslots[i].first) {
186 info->current = ht->cslots[i].first;
187 break;
188 }
189 }
190 info->slot_pos = i;
191 return info->current;
192 }
193
get_next_ht_element(ht_traversal_info_t * info)194 ht_element_t *get_next_ht_element(ht_traversal_info_t *info)
195 {
196 int i;
197 if (!info) return NULL;
198
199 if (info->current) info->current = info->current->next;
200
201 if (info->current) return info->current;
202 else {
203 for (i = info->slot_pos + 1; i < info->ht->size; i++) {
204 if (info->ht->cslots[i].first) {
205 info->current = info->ht->cslots[i].first;
206 break;
207 }
208 }
209 info->slot_pos = i;
210 }
211 return info->current;
212 }
213
214 /* --------- HASH functions -------- */
215
rshash(const char * str,unsigned int len)216 unsigned int rshash(const char* str, unsigned int len)
217 {
218 unsigned int b = 378551;
219 unsigned int a = 63689;
220 unsigned int hash = 0;
221 unsigned int i = 0;
222
223 for(i = 0; i < len; str++, i++) {
224 hash = hash * a + (*str);
225 a = a * b;
226 }
227
228 return (hash & 0x7FFFFFFF);
229 }
230
231