171dafaa1Schristos /* $OpenBSD: ohash_do.c,v 1.4 2004/06/22 20:00:16 espie Exp $ */
271dafaa1Schristos /* ex:ts=8 sw=4:
371dafaa1Schristos */
471dafaa1Schristos
571dafaa1Schristos /* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
671dafaa1Schristos *
771dafaa1Schristos * Permission to use, copy, modify, and distribute this software for any
871dafaa1Schristos * purpose with or without fee is hereby granted, provided that the above
971dafaa1Schristos * copyright notice and this permission notice appear in all copies.
1071dafaa1Schristos *
1171dafaa1Schristos * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1271dafaa1Schristos * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1371dafaa1Schristos * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1471dafaa1Schristos * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1571dafaa1Schristos * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1671dafaa1Schristos * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1771dafaa1Schristos * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1871dafaa1Schristos */
1971dafaa1Schristos
2071dafaa1Schristos #include "ohash_int.h"
2171dafaa1Schristos
2271dafaa1Schristos static void ohash_resize(struct ohash *);
2371dafaa1Schristos
2471dafaa1Schristos static void
ohash_resize(struct ohash * h)2571dafaa1Schristos ohash_resize(struct ohash *h)
2671dafaa1Schristos {
2771dafaa1Schristos struct _ohash_record *n;
2871dafaa1Schristos unsigned int ns, j;
2971dafaa1Schristos unsigned int i, incr;
3071dafaa1Schristos
3171dafaa1Schristos if (4 * h->deleted < h->total)
3271dafaa1Schristos ns = h->size << 1;
3371dafaa1Schristos else if (3 * h->deleted > 2 * h->total)
3471dafaa1Schristos ns = h->size >> 1;
3571dafaa1Schristos else
3671dafaa1Schristos ns = h->size;
3771dafaa1Schristos if (ns < MINSIZE)
3871dafaa1Schristos ns = MINSIZE;
3971dafaa1Schristos #ifdef STATS_HASH
4071dafaa1Schristos STAT_HASH_EXPAND++;
4171dafaa1Schristos STAT_HASH_SIZE += ns - h->size;
4271dafaa1Schristos #endif
4371dafaa1Schristos n = (h->info.halloc)(sizeof(struct _ohash_record) * ns, h->info.data);
4471dafaa1Schristos if (!n)
4571dafaa1Schristos return;
4671dafaa1Schristos
4771dafaa1Schristos for (j = 0; j < h->size; j++) {
4871dafaa1Schristos if (h->t[j].p != NULL && h->t[j].p != DELETED) {
4971dafaa1Schristos i = h->t[j].hv % ns;
5071dafaa1Schristos incr = ((h->t[j].hv % (ns - 2)) & ~1) + 1;
5171dafaa1Schristos while (n[i].p != NULL) {
5271dafaa1Schristos i += incr;
5371dafaa1Schristos if (i >= ns)
5471dafaa1Schristos i -= ns;
5571dafaa1Schristos }
5671dafaa1Schristos n[i].hv = h->t[j].hv;
5771dafaa1Schristos n[i].p = h->t[j].p;
5871dafaa1Schristos }
5971dafaa1Schristos }
6071dafaa1Schristos (h->info.hfree)(h->t, sizeof(struct _ohash_record) * h->size,
6171dafaa1Schristos h->info.data);
6271dafaa1Schristos h->t = n;
6371dafaa1Schristos h->size = ns;
6471dafaa1Schristos h->total -= h->deleted;
6571dafaa1Schristos h->deleted = 0;
6671dafaa1Schristos }
6771dafaa1Schristos
6871dafaa1Schristos void *
ohash_remove(struct ohash * h,unsigned int i)6971dafaa1Schristos ohash_remove(struct ohash *h, unsigned int i)
7071dafaa1Schristos {
71*315c7490Schristos void *result = __UNCONST(h->t[i].p);
7271dafaa1Schristos
7371dafaa1Schristos if (result == NULL || result == DELETED)
7471dafaa1Schristos return NULL;
7571dafaa1Schristos
7671dafaa1Schristos #ifdef STATS_HASH
7771dafaa1Schristos STAT_HASH_ENTRIES--;
7871dafaa1Schristos #endif
7971dafaa1Schristos h->t[i].p = DELETED;
8071dafaa1Schristos h->deleted++;
8171dafaa1Schristos if (h->deleted >= MINDELETED && 4 * h->deleted > h->total)
8271dafaa1Schristos ohash_resize(h);
8371dafaa1Schristos return result;
8471dafaa1Schristos }
8571dafaa1Schristos
8671dafaa1Schristos void *
ohash_find(struct ohash * h,unsigned int i)8771dafaa1Schristos ohash_find(struct ohash *h, unsigned int i)
8871dafaa1Schristos {
8971dafaa1Schristos if (h->t[i].p == DELETED)
9071dafaa1Schristos return NULL;
9171dafaa1Schristos else
92*315c7490Schristos return __UNCONST(h->t[i].p);
9371dafaa1Schristos }
9471dafaa1Schristos
9571dafaa1Schristos void *
ohash_insert(struct ohash * h,unsigned int i,void * p)9671dafaa1Schristos ohash_insert(struct ohash *h, unsigned int i, void *p)
9771dafaa1Schristos {
9871dafaa1Schristos #ifdef STATS_HASH
9971dafaa1Schristos STAT_HASH_ENTRIES++;
10071dafaa1Schristos #endif
10171dafaa1Schristos if (h->t[i].p == DELETED) {
10271dafaa1Schristos h->deleted--;
10371dafaa1Schristos h->t[i].p = p;
10471dafaa1Schristos } else {
10571dafaa1Schristos h->t[i].p = p;
10671dafaa1Schristos /* Arbitrary resize boundary. Tweak if not efficient enough. */
10771dafaa1Schristos if (++h->total * 4 > h->size * 3)
10871dafaa1Schristos ohash_resize(h);
10971dafaa1Schristos }
11071dafaa1Schristos return p;
11171dafaa1Schristos }
112