hcreate.c revision 92986
11590Srgrimes/* $NetBSD: hcreate.c,v 1.2 2001/02/19 21:26:04 ross Exp $ */
21590Srgrimes
31590Srgrimes/*
41590Srgrimes * Copyright (c) 2001 Christopher G. Demetriou
51590Srgrimes * All rights reserved.
61590Srgrimes *
71590Srgrimes * Redistribution and use in source and binary forms, with or without
81590Srgrimes * modification, are permitted provided that the following conditions
91590Srgrimes * are met:
101590Srgrimes * 1. Redistributions of source code must retain the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer.
121590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
131590Srgrimes *    notice, this list of conditions and the following disclaimer in the
141590Srgrimes *    documentation and/or other materials provided with the distribution.
151590Srgrimes * 3. All advertising materials mentioning features or use of this software
161590Srgrimes *    must display the following acknowledgement:
171590Srgrimes *          This product includes software developed for the
181590Srgrimes *          NetBSD Project.  See http://www.netbsd.org/ for
191590Srgrimes *          information about NetBSD.
201590Srgrimes * 4. The name of the author may not be used to endorse or promote products
211590Srgrimes *    derived from this software without specific prior written permission.
221590Srgrimes *
231590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
241590Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
251590Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
261590Srgrimes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
271590Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
281590Srgrimes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
291590Srgrimes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
301590Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
311590Srgrimes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
321590Srgrimes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
331590Srgrimes *
3487674Smarkm * <<Id: LICENSE,v 1.2 2000/06/14 15:57:33 cgd Exp>>
3587674Smarkm */
3687674Smarkm
3787674Smarkm/*
381590Srgrimes * hcreate() / hsearch() / hdestroy()
3987674Smarkm *
4028694Scharnier * SysV/XPG4 hash table functions.
411590Srgrimes *
421590Srgrimes * Implementation done based on NetBSD manual page and Solaris manual page,
431590Srgrimes * plus my own personal experience about how they're supposed to work.
441590Srgrimes *
451590Srgrimes * I tried to look at Knuth (as cited by the Solaris manual page), but
461590Srgrimes * nobody had a copy in the office, so...
47181922Sache */
481590Srgrimes
491590Srgrimes#include <sys/cdefs.h>
501590Srgrimes#if 0
511590Srgrimes#if defined(LIBC_SCCS) && !defined(lint)
521590Srgrimes__RCSID("$NetBSD: hcreate.c,v 1.2 2001/02/19 21:26:04 ross Exp $");
538874Srgrimes#endif /* LIBC_SCCS and not lint */
541590Srgrimes#endif
551590Srgrimes__FBSDID("$FreeBSD: head/lib/libc/stdlib/hcreate.c 92986 2002-03-22 21:53:29Z obrien $");
5697981Sjmallett
571590Srgrimes#include <sys/types.h>
581590Srgrimes#include <sys/queue.h>
5953073Sdavidn#include <errno.h>
601590Srgrimes#include <search.h>
611590Srgrimes#include <stdlib.h>
621590Srgrimes#include <string.h>
6353073Sdavidn#include "namespace.h"
6453073Sdavidn
651590Srgrimes/*
661590Srgrimes * DO NOT MAKE THIS STRUCTURE LARGER THAN 32 BYTES (4 ptrs on 64-bit
671590Srgrimes * ptr machine) without adjusting MAX_BUCKETS_LG2 below.
689987Swollman */
691590Srgrimesstruct internal_entry {
701590Srgrimes	SLIST_ENTRY(internal_entry) link;
711590Srgrimes	ENTRY ent;
7253073Sdavidn};
7353073SdavidnSLIST_HEAD(internal_head, internal_entry);
7453073Sdavidn
7553073Sdavidn#define	MIN_BUCKETS_LG2	4
7653073Sdavidn#define	MIN_BUCKETS	(1 << MIN_BUCKETS_LG2)
7774603Sache
781590Srgrimes/*
791590Srgrimes * max * sizeof internal_entry must fit into size_t.
801590Srgrimes * assumes internal_entry is <= 32 (2^5) bytes.
811590Srgrimes */
8274603Sache#define	MAX_BUCKETS_LG2	(sizeof (size_t) * 8 - 1 - 5)
831590Srgrimes#define	MAX_BUCKETS	((size_t)1 << MAX_BUCKETS_LG2)
841590Srgrimes
8574603Sache/* Default hash function, from db/hash/hash_func.c */
86181922Sacheextern u_int32_t (*__default_hash)(const void *, size_t);
871590Srgrimes
881590Srgrimesstatic struct internal_head *htable;
891590Srgrimesstatic size_t htablesize;
901590Srgrimes
911590Srgrimesint
9242481Speterhcreate(size_t nel)
931590Srgrimes{
9422558Sdanny	size_t idx;
9597981Sjmallett	unsigned int p2;
961590Srgrimes
971590Srgrimes	/* Make sure this this isn't called when a table already exists. */
9810948Sdima	if (htable != NULL) {
9910948Sdima		errno = EINVAL;
10011339Sache		return 0;
10142481Speter	}
10242481Speter
10322558Sdanny	/* If nel is too small, make it min sized. */
10442481Speter	if (nel < MIN_BUCKETS)
10510948Sdima		nel = MIN_BUCKETS;
1061590Srgrimes
1071590Srgrimes	/* If it's too large, cap it. */
1089987Swollman	if (nel > MAX_BUCKETS)
1091590Srgrimes		nel = MAX_BUCKETS;
11032055Salex
1111590Srgrimes	/* If it's is not a power of two in size, round up. */
1129987Swollman	if ((nel & (nel - 1)) != 0) {
1133138Sache		for (p2 = 0; nel != 0; p2++)
1143138Sache			nel >>= 1;
1151590Srgrimes		nel = 1 << p2;
1161590Srgrimes	}
11732055Salex
11822558Sdanny	/* Allocate the table. */
11942481Speter	htablesize = nel;
1201590Srgrimes	htable = malloc(htablesize * sizeof htable[0]);
121	if (htable == NULL) {
122		errno = ENOMEM;
123		return 0;
124	}
125
126	/* Initialize it. */
127	for (idx = 0; idx < htablesize; idx++)
128		SLIST_INIT(&htable[idx]);
129
130	return 1;
131}
132
133void
134hdestroy(void)
135{
136	struct internal_entry *ie;
137	size_t idx;
138
139	if (htable == NULL)
140		return;
141
142	for (idx = 0; idx < htablesize; idx++) {
143		while (!SLIST_EMPTY(&htable[idx])) {
144			ie = SLIST_FIRST(&htable[idx]);
145			SLIST_REMOVE_HEAD(&htable[idx], link);
146			free(ie->ent.key);
147			free(ie);
148		}
149	}
150	free(htable);
151	htable = NULL;
152}
153
154ENTRY *
155hsearch(ENTRY item, ACTION action)
156{
157	struct internal_head *head;
158	struct internal_entry *ie;
159	uint32_t hashval;
160	size_t len;
161
162	len = strlen(item.key);
163	hashval = (*__default_hash)(item.key, len);
164
165	head = &htable[hashval & (htablesize - 1)];
166	ie = SLIST_FIRST(head);
167	while (ie != NULL) {
168		if (strcmp(ie->ent.key, item.key) == 0)
169			break;
170		ie = SLIST_NEXT(ie, link);
171	}
172
173	if (ie != NULL)
174		return &ie->ent;
175	else if (action == FIND)
176		return NULL;
177
178	ie = malloc(sizeof *ie);
179	if (ie == NULL)
180		return NULL;
181	ie->ent.key = item.key;
182	ie->ent.data = item.data;
183
184	SLIST_INSERT_HEAD(head, ie, link);
185	return &ie->ent;
186}
187