11 /* $OpenBSD: ohash_int.h,v 1.3 2006/01/16 15:52:25 espie Exp $ */
17 #include "compat_ohash.h"
19 struct _ohash_record
{
24 #define DELETED ((const char *)h)
25 #define NONE (h->size)
27 /* Don't bother changing the hash table if the change is small enough. */
28 #define MINSIZE (1UL << 4)
30 /* $OpenBSD: ohash_create_entry.c,v 1.2 2004/06/22 20:00:16 espie Exp $ */
34 /* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
36 * Permission to use, copy, modify, and distribute this software for any
37 * purpose with or without fee is hereby granted, provided that the above
38 * copyright notice and this permission notice appear in all copies.
40 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
41 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
42 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
43 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
44 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
45 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
46 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
49 /* This handles the common case of variable length keys, where the
50 * key is stored at the end of the record.
53 ohash_create_entry(struct ohash_info
*i
, const char *start
, const char **end
)
58 *end
= start
+ strlen(start
);
59 p
= (i
->alloc
)(i
->key_offset
+ (*end
- start
) + 1, i
->data
);
61 memcpy(p
+i
->key_offset
, start
, *end
-start
);
62 p
[i
->key_offset
+ (*end
- start
)] = '\0';
67 /* hash_delete only frees the hash structure. Use hash_first/hash_next
68 * to free entries as well. */
70 ohash_delete(struct ohash
*h
)
72 (h
->info
.hfree
)(h
->t
, sizeof(struct _ohash_record
) * h
->size
,
79 static void ohash_resize(struct ohash
*);
82 ohash_resize(struct ohash
*h
)
84 struct _ohash_record
*n
;
88 if (4 * h
->deleted
< h
->total
)
90 else if (3 * h
->deleted
> 2 * h
->total
)
98 STAT_HASH_SIZE
+= ns
- h
->size
;
100 n
= (h
->info
.halloc
)(sizeof(struct _ohash_record
) * ns
, h
->info
.data
);
104 for (j
= 0; j
< h
->size
; j
++) {
105 if (h
->t
[j
].p
!= NULL
&& h
->t
[j
].p
!= DELETED
) {
107 incr
= ((h
->t
[j
].hv
% (ns
- 2)) & ~1) + 1;
108 while (n
[i
].p
!= NULL
) {
113 n
[i
].hv
= h
->t
[j
].hv
;
117 (h
->info
.hfree
)(h
->t
, sizeof(struct _ohash_record
) * h
->size
,
121 h
->total
-= h
->deleted
;
126 ohash_remove(struct ohash
*h
, unsigned int i
)
128 void *result
= (void *)h
->t
[i
].p
;
130 if (result
== NULL
|| result
== DELETED
)
138 if (h
->deleted
>= MINDELETED
&& 4 * h
->deleted
> h
->total
)
144 ohash_find(struct ohash
*h
, unsigned int i
)
146 if (h
->t
[i
].p
== DELETED
)
149 return (void *)h
->t
[i
].p
;
153 ohash_insert(struct ohash
*h
, unsigned int i
, void *p
)
158 if (h
->t
[i
].p
== DELETED
) {
163 /* Arbitrary resize boundary. Tweak if not efficient enough. */
164 if (++h
->total
* 4 > h
->size
* 3)
171 ohash_entries(struct ohash
*h
)
173 return h
->total
- h
->deleted
;
177 ohash_first(struct ohash
*h
, unsigned int *pos
)
180 return ohash_next(h
, pos
);
184 ohash_next(struct ohash
*h
, unsigned int *pos
)
186 for (; *pos
< h
->size
; (*pos
)++)
187 if (h
->t
[*pos
].p
!= DELETED
&& h
->t
[*pos
].p
!= NULL
)
188 return (void *)h
->t
[(*pos
)++].p
;
193 ohash_init(struct ohash
*h
, unsigned int size
, struct ohash_info
*info
)
195 h
->size
= 1UL << size
;
196 if (h
->size
< MINSIZE
)
199 STAT_HASH_CREATION
++;
200 STAT_HASH_SIZE
+= h
->size
;
202 /* Copy info so that caller may free it. */
203 h
->info
.key_offset
= info
->key_offset
;
204 h
->info
.halloc
= info
->halloc
;
205 h
->info
.hfree
= info
->hfree
;
206 h
->info
.alloc
= info
->alloc
;
207 h
->info
.data
= info
->data
;
208 h
->t
= (h
->info
.halloc
)(sizeof(struct _ohash_record
) * h
->size
,
210 h
->total
= h
->deleted
= 0;
214 ohash_interval(const char *s
, const char **e
)
225 k
= ((k
<< 2) | (k
>> 30)) ^ *s
++;
230 ohash_lookup_interval(struct ohash
*h
, const char *start
, const char *end
,
233 unsigned int i
, incr
;
241 incr
= ((hv
% (h
->size
-2)) & ~1) + 1;
242 while (h
->t
[i
].p
!= NULL
) {
246 if (h
->t
[i
].p
== DELETED
) {
249 } else if (h
->t
[i
].hv
== hv
&&
250 strncmp(h
->t
[i
].p
+h
->info
.key_offset
, start
,
252 (h
->t
[i
].p
+h
->info
.key_offset
)[end
-start
] == '\0') {
255 h
->t
[empty
].p
= h
->t
[i
].p
;
260 STAT_HASH_POSITIVE
++;
270 /* Found an empty position. */
278 ohash_lookup_memory(struct ohash
*h
, const char *k
, size_t size
, uint32_t hv
)
280 unsigned int i
, incr
;
288 incr
= ((hv
% (h
->size
-2)) & ~1) + 1;
289 while (h
->t
[i
].p
!= NULL
) {
293 if (h
->t
[i
].p
== DELETED
) {
296 } else if (h
->t
[i
].hv
== hv
&&
297 memcmp(h
->t
[i
].p
+h
->info
.key_offset
, k
, size
) == 0) {
300 h
->t
[empty
].p
= h
->t
[i
].p
;
305 STAT_HASH_POSITIVE
++;
314 /* Found an empty position. */
322 ohash_qlookup(struct ohash
*h
, const char *s
)
324 const char *e
= NULL
;
325 return ohash_qlookupi(h
, s
, &e
);
329 ohash_qlookupi(struct ohash
*h
, const char *s
, const char **e
)
333 hv
= ohash_interval(s
, e
);
334 return ohash_lookup_interval(h
, s
, *e
, hv
);
337 #endif /*!HAVE_OHASH*/