3 * libEtPan! -- a mail stuff library
5 * chash - Implements generic hash tables.
7 * Copyright (c) 1999-2000, Gaƫl Roualland <gael.roualland@iname.com>
8 * interface changes - 2002 - DINH Viet Hoa
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the libEtPan! project nor the names of its
20 * contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 /* This defines the maximum (average) number of entries per bucket.
48 The hash is resized everytime inserting an entry makes the
49 average go over that value. */
50 #define CHASH_MAXDEPTH 3
52 static inline unsigned int chash_func(const char * key
, unsigned int len
) {
54 register unsigned int c
= 0, t
;
55 register const char * k
= key
;
59 if ((t
= c
& 0xF0000000)) {
66 register unsigned int c
= 5381;
67 register const char * k
= key
;
70 c
= ((c
<< 5) + c
) + *k
++;
76 static inline char * chash_dup(const void * data
, unsigned int len
)
80 r
= (char *) malloc(len
);
87 chash
* chash_new(unsigned int size
, int flags
)
91 h
= (chash
*) malloc(sizeof(chash
));
96 h
->cells
= (struct chashcell
**) calloc(size
, sizeof(struct chashcell
*));
97 if (h
->cells
== NULL
) {
102 h
->copykey
= flags
& CHASH_COPYKEY
;
103 h
->copyvalue
= flags
& CHASH_COPYVALUE
;
108 int chash_get(chash
* hash
,
109 chashdatum
* key
, chashdatum
* result
)
114 func
= chash_func(key
->data
, key
->len
);
116 /* look for the key in existing cells */
117 iter
= hash
->cells
[func
% hash
->size
];
119 if (iter
->key
.len
== key
->len
&& iter
->func
== func
120 && !memcmp(iter
->key
.data
, key
->data
, key
->len
)) {
121 * result
= iter
->value
; /* found */
131 int chash_set(chash
* hash
,
134 chashdatum
* oldvalue
)
136 unsigned int func
, indx
;
137 chashiter
* iter
, * cell
;
140 if (hash
->count
> hash
->size
* CHASH_MAXDEPTH
) {
141 r
= chash_resize(hash
, (hash
->count
/ CHASH_MAXDEPTH
) * 2 + 1);
146 func
= chash_func(key
->data
, key
->len
);
147 indx
= func
% hash
->size
;
149 /* look for the key in existing cells */
150 iter
= hash
->cells
[indx
];
152 if (iter
->key
.len
== key
->len
&& iter
->func
== func
153 && !memcmp(iter
->key
.data
, key
->data
, key
->len
)) {
154 /* found, replacing entry */
155 if (hash
->copyvalue
) {
158 data
= chash_dup(value
->data
, value
->len
);
162 free(iter
->value
.data
);
163 iter
->value
.data
= data
;
164 iter
->value
.len
= value
->len
;
166 if (oldvalue
!= NULL
) {
167 oldvalue
->data
= iter
->value
.data
;
168 oldvalue
->len
= iter
->value
.len
;
170 iter
->value
.data
= value
->data
;
171 iter
->value
.len
= value
->len
;
174 iter
->key
.data
= key
->data
;
176 if (oldvalue
!= NULL
) {
177 oldvalue
->data
= value
->data
;
178 oldvalue
->len
= value
->len
;
186 if (oldvalue
!= NULL
) {
187 oldvalue
->data
= NULL
;
191 /* not found, adding entry */
192 cell
= (struct chashcell
*) malloc(sizeof(struct chashcell
));
197 cell
->key
.data
= chash_dup(key
->data
, key
->len
);
198 if (cell
->key
.data
== NULL
)
202 cell
->key
.data
= key
->data
;
204 cell
->key
.len
= key
->len
;
205 if (hash
->copyvalue
) {
206 cell
->value
.data
= chash_dup(value
->data
, value
->len
);
207 if (cell
->value
.data
== NULL
)
211 cell
->value
.data
= value
->data
;
213 cell
->value
.len
= value
->len
;
215 cell
->next
= hash
->cells
[indx
];
216 hash
->cells
[indx
] = cell
;
223 free(cell
->key
.data
);
230 int chash_delete(chash
* hash
, chashdatum
* key
, chashdatum
* oldvalue
)
232 /* chashdatum result = { NULL, TRUE }; */
233 unsigned int func
, indx
;
234 chashiter
* iter
, * old
;
238 keylen = strlen(key) + 1;
241 func
= chash_func(key
->data
, key
->len
);
242 indx
= func
% hash
->size
;
244 /* look for the key in existing cells */
246 iter
= hash
->cells
[indx
];
248 if (iter
->key
.len
== key
->len
&& iter
->func
== func
249 && !memcmp(iter
->key
.data
, key
->data
, key
->len
)) {
250 /* found, deleting */
252 old
->next
= iter
->next
;
254 hash
->cells
[indx
] = iter
->next
;
256 free(iter
->key
.data
);
258 free(iter
->value
.data
);
260 if (oldvalue
!= NULL
) {
261 oldvalue
->data
= iter
->value
.data
;
262 oldvalue
->len
= iter
->value
.len
;
273 return -1; /* not found */
276 void chash_free(chash
* hash
) {
278 chashiter
* iter
, * next
;
280 /* browse the hash table */
281 for(indx
= 0; indx
< hash
->size
; indx
++) {
282 iter
= hash
->cells
[indx
];
286 free(iter
->key
.data
);
288 free(iter
->value
.data
);
297 void chash_clear(chash
* hash
) {
299 chashiter
* iter
, * next
;
301 /* browse the hash table */
302 for(indx
= 0; indx
< hash
->size
; indx
++) {
303 iter
= hash
->cells
[indx
];
307 free(iter
->key
.data
);
309 free(iter
->value
.data
);
314 memset(hash
->cells
, 0, hash
->size
* sizeof(* hash
->cells
));
318 chashiter
* chash_begin(chash
* hash
) {
320 unsigned int indx
= 0;
322 iter
= hash
->cells
[0];
325 if (indx
>= hash
->size
)
327 iter
= hash
->cells
[indx
];
332 chashiter
* chash_next(chash
* hash
, chashiter
* iter
) {
338 indx
= iter
->func
% hash
->size
;
343 if (indx
>= hash
->size
)
345 iter
= hash
->cells
[indx
];
350 int chash_resize(chash
* hash
, unsigned int size
)
352 struct chashcell
** cells
;
353 unsigned int indx
, nindx
;
354 chashiter
* iter
, * next
;
356 if (hash
->size
== size
)
359 cells
= (struct chashcell
**) calloc(size
, sizeof(struct chashcell
*));
363 /* browse initial hash and copy items in second hash */
364 for(indx
= 0; indx
< hash
->size
; indx
++) {
365 iter
= hash
->cells
[indx
];
368 nindx
= iter
->func
% size
;
369 iter
->next
= cells
[nindx
];
382 int chash_count(chash
* hash
) {
386 int chash_size(chash
* hash
) {
390 void chash_value(chashiter
* iter
, chashdatum
* result
) {
391 * result
= iter
->value
;
394 void chash_key(chashiter
* iter
, chashdatum
* result
) {
395 * result
= iter
->key
;