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