Now passes the regress tests.OPENBSD_3_6
@ -0,0 +1,195 @@ | |||
.\" $OpenBSD: hcreate.3,v 1.1 2004/06/24 04:43:33 millert Exp $ | |||
.\" $NetBSD: hcreate.3,v 1.6 2003/04/16 13:34:46 wiz Exp $ | |||
.\" | |||
.\" Copyright (c) 1999 The NetBSD Foundation, Inc. | |||
.\" All rights reserved. | |||
.\" | |||
.\" This code is derived from software contributed to The NetBSD Foundation | |||
.\" by Klaus Klein. | |||
.\" | |||
.\" Redistribution and use in source and binary forms, with or without | |||
.\" modification, are permitted provided that the following conditions | |||
.\" are met: | |||
.\" 1. Redistributions of source code must retain the above copyright | |||
.\" notice, this list of conditions and the following disclaimer. | |||
.\" 2. Redistributions in binary form must reproduce the above copyright | |||
.\" notice, this list of conditions and the following disclaimer in the | |||
.\" documentation and/or other materials provided with the distribution. | |||
.\" 3. All advertising materials mentioning features or use of this software | |||
.\" must display the following acknowledgement: | |||
.\" This product includes software developed by the NetBSD | |||
.\" Foundation, Inc. and its contributors. | |||
.\" 4. Neither the name of The NetBSD Foundation nor the names of its | |||
.\" contributors may be used to endorse or promote products derived | |||
.\" from this software without specific prior written permission. | |||
.\" | |||
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |||
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |||
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |||
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |||
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |||
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |||
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
.\" POSSIBILITY OF SUCH DAMAGE. | |||
.\" | |||
.Dd February 13, 2001 | |||
.Dt HCREATE 3 | |||
.Os | |||
.Sh NAME | |||
.Nm hcreate , | |||
.Nm hdestroy , | |||
.Nm hsearch | |||
.Nd manage hash search table | |||
.Sh SYNOPSIS | |||
.In search.h | |||
.Ft int | |||
.Fn hcreate "size_t nel" | |||
.Ft void | |||
.Fn hdestroy "void" | |||
.Ft ENTRY * | |||
.Fn hsearch "ENTRY item" "ACTION action" | |||
.Sh DESCRIPTION | |||
The | |||
.Fn hcreate , | |||
.Fn hdestroy | |||
and | |||
.Fn hsearch | |||
functions manage hash search tables. | |||
.Pp | |||
The | |||
.Fn hcreate | |||
function allocates and initializes the table. | |||
The | |||
.Fa nel | |||
argument specifies an estimate of the maximum number of entries to be held | |||
by the table. | |||
Unless further memory allocation fails, supplying an insufficient | |||
.Fa nel | |||
value will not result in functional harm, although a performance degradation | |||
may occur. | |||
Initialization using the | |||
.Fn hcreate | |||
function is mandatory prior to any access operations using | |||
.Fn hsearch . | |||
.Pp | |||
The | |||
.Fn hdestroy | |||
function destroys a table previously created using | |||
.Fn hcreate . | |||
After a call to | |||
.Fn hdestroy , | |||
the data can no longer be accessed. | |||
.Pp | |||
The | |||
.Fn hsearch | |||
function is used to search to the hash table. | |||
It returns a pointer into the | |||
hash table indicating the address of an item. | |||
The | |||
.Fa item | |||
argument is of type | |||
.Dv ENTRY , | |||
a structural type which contains the following members: | |||
.Bl -tag -compact -offset indent -width voidX*dataXX | |||
.It Fa char *key | |||
comparison key. | |||
.It Fa void *data | |||
pointer to data associated with | |||
.Fa key . | |||
.El | |||
.Pp | |||
The key comparison function used by | |||
.Fn hsearch | |||
is | |||
.Xr strcmp 3 . | |||
.Pp | |||
The | |||
.Fa action | |||
argument is of type | |||
.Dv ACTION , | |||
an enumeration type which defines the following values: | |||
.Bl -tag -compact -offset indent -width ENTERXX | |||
.It Dv ENTER | |||
Insert | |||
.Fa item | |||
into the hash table. | |||
If an existing item with the same key is found, it is not replaced. | |||
Note that the | |||
.Fa key | |||
and | |||
.Fa data | |||
elements of | |||
.Fa item | |||
are used directly by the new table entry. | |||
The storage for the | |||
key must not be modified during the lifetime of the hash table. | |||
.It Dv FIND | |||
Search the hash table without inserting | |||
.Fa item . | |||
.El | |||
.Sh RETURN VALUES | |||
If successful, the | |||
.Fn hcreate | |||
function returns a non-zero value. | |||
Otherwise, a value of 0 is returned and | |||
.Va errno | |||
is set to indicate the error. | |||
.Pp | |||
The | |||
.Fn hdestroy | |||
functions | |||
returns no value. | |||
.Pp | |||
If successful, the | |||
.Fn hsearch | |||
function returns a pointer to hash table entry matching | |||
the provided key. | |||
If the action is | |||
.Dv FIND | |||
and the item was not found, or if the action is | |||
.Dv ENTER | |||
and the insertion failed, | |||
.Dv NULL | |||
is returned and | |||
.Va errno | |||
is set to indicate the error. | |||
If the action is | |||
.Dv ENTER | |||
and an entry already existed in the table matching the given | |||
key, the existing entry is returned and is not replaced. | |||
.Sh ERRORS | |||
The | |||
.Fn hcreate | |||
and | |||
.Fn hsearch | |||
functions will fail if: | |||
.Bl -tag -width Er | |||
.It Bq Er ENOMEM | |||
Insufficient memory is available. | |||
.El | |||
.Sh SEE ALSO | |||
.Xr bsearch 3 , | |||
.Xr lsearch 3 , | |||
.Xr malloc 3 , | |||
.Xr strcmp 3 | |||
.Sh STANDARDS | |||
The | |||
.Fn hcreate , | |||
.Fn hdestroy | |||
and | |||
.Fn hsearch | |||
functions conform to | |||
.St -xpg4.2 . | |||
.Sh HISTORY | |||
The | |||
.Fn hcreate , | |||
.Fn hdestroy | |||
and | |||
.Fn hsearch | |||
functions first appeared in | |||
.At V . | |||
.Sh BUGS | |||
The interface permits the use of only one hash table at a time. |
@ -0,0 +1,200 @@ | |||
/* $OpenBSD: hcreate.c,v 1.1 2004/06/24 04:43:33 millert Exp $ */ | |||
/* $NetBSD: hcreate.c,v 1.5 2004/04/23 02:48:12 simonb Exp $ */ | |||
/* | |||
* Copyright (c) 2001 Christopher G. Demetriou | |||
* All rights reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions | |||
* are met: | |||
* 1. Redistributions of source code must retain the above copyright | |||
* notice, this list of conditions and the following disclaimer. | |||
* 2. Redistributions in binary form must reproduce the above copyright | |||
* notice, this list of conditions and the following disclaimer in the | |||
* documentation and/or other materials provided with the distribution. | |||
* 3. All advertising materials mentioning features or use of this software | |||
* must display the following acknowledgement: | |||
* This product includes software developed for the | |||
* NetBSD Project. See http://www.NetBSD.org/ for | |||
* information about NetBSD. | |||
* 4. The name of the author may not be used to endorse or promote products | |||
* derived from this software without specific prior written permission. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
* | |||
* <<Id: LICENSE,v 1.2 2000/06/14 15:57:33 cgd Exp>> | |||
*/ | |||
/* | |||
* hcreate() / hsearch() / hdestroy() | |||
* | |||
* SysV/XPG4 hash table functions. | |||
* | |||
* Implementation done based on NetBSD manual page and Solaris manual page, | |||
* plus my own personal experience about how they're supposed to work. | |||
* | |||
* I tried to look at Knuth (as cited by the Solaris manual page), but | |||
* nobody had a copy in the office, so... | |||
*/ | |||
#ifndef lint | |||
static const char copyright[] = | |||
"@(#) Copyright (c) 2001 Christopher G. Demetriou. All rights reserved.\n"; | |||
#endif /* not lint */ | |||
#ifndef lint | |||
static const char rcsid[] = "$OpenBSD: hcreate.c,v 1.1 2004/06/24 04:43:33 millert Exp $"; | |||
#endif /* not lint */ | |||
#include "namespace.h" | |||
#include <assert.h> | |||
#include <errno.h> | |||
#include <inttypes.h> | |||
#include <search.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <sys/queue.h> | |||
#ifndef _DIAGASSERT | |||
#define _DIAGASSERT | |||
#endif | |||
/* | |||
* DO NOT MAKE THIS STRUCTURE LARGER THAN 32 BYTES (4 ptrs on 64-bit | |||
* ptr machine) without adjusting MAX_BUCKETS_LG2 below. | |||
*/ | |||
struct internal_entry { | |||
SLIST_ENTRY(internal_entry) link; | |||
ENTRY ent; | |||
}; | |||
SLIST_HEAD(internal_head, internal_entry); | |||
#define MIN_BUCKETS_LG2 4 | |||
#define MIN_BUCKETS (1 << MIN_BUCKETS_LG2) | |||
/* | |||
* max * sizeof internal_entry must fit into size_t. | |||
* assumes internal_entry is <= 32 (2^5) bytes. | |||
*/ | |||
#define MAX_BUCKETS_LG2 (sizeof (size_t) * 8 - 1 - 5) | |||
#define MAX_BUCKETS ((size_t)1 << MAX_BUCKETS_LG2) | |||
/* Default hash function, from db/hash/hash_func.c */ | |||
extern u_int32_t (*__default_hash)(const void *, size_t); | |||
static struct internal_head *htable; | |||
static size_t htablesize; | |||
int | |||
hcreate(size_t nel) | |||
{ | |||
size_t idx; | |||
unsigned int p2; | |||
/* Make sure this isn't called when a table already exists. */ | |||
_DIAGASSERT(htable == NULL); | |||
if (htable != NULL) { | |||
errno = EINVAL; | |||
return 0; | |||
} | |||
/* If nel is too small, make it min sized. */ | |||
if (nel < MIN_BUCKETS) | |||
nel = MIN_BUCKETS; | |||
/* If it's too large, cap it. */ | |||
if (nel > MAX_BUCKETS) | |||
nel = MAX_BUCKETS; | |||
/* If it's is not a power of two in size, round up. */ | |||
if ((nel & (nel - 1)) != 0) { | |||
for (p2 = 0; nel != 0; p2++) | |||
nel >>= 1; | |||
_DIAGASSERT(p2 <= MAX_BUCKETS_LG2); | |||
nel = 1 << p2; | |||
} | |||
/* Allocate the table. */ | |||
htablesize = nel; | |||
htable = malloc(htablesize * sizeof htable[0]); | |||
if (htable == NULL) { | |||
errno = ENOMEM; | |||
return 0; | |||
} | |||
/* Initialize it. */ | |||
for (idx = 0; idx < htablesize; idx++) | |||
SLIST_INIT(&htable[idx]); | |||
return 1; | |||
} | |||
void | |||
hdestroy(void) | |||
{ | |||
struct internal_entry *ie; | |||
size_t idx; | |||
_DIAGASSERT(htable != NULL); | |||
if (htable == NULL) | |||
return; | |||
for (idx = 0; idx < htablesize; idx++) { | |||
while (!SLIST_EMPTY(&htable[idx])) { | |||
ie = SLIST_FIRST(&htable[idx]); | |||
SLIST_REMOVE_HEAD(&htable[idx], link); | |||
free(ie->ent.key); | |||
free(ie); | |||
} | |||
} | |||
free(htable); | |||
htable = NULL; | |||
} | |||
ENTRY * | |||
hsearch(ENTRY item, ACTION action) | |||
{ | |||
struct internal_head *head; | |||
struct internal_entry *ie; | |||
uint32_t hashval; | |||
size_t len; | |||
_DIAGASSERT(htable != NULL); | |||
_DIAGASSERT(item.key != NULL); | |||
_DIAGASSERT(action == ENTER || action == FIND); | |||
len = strlen(item.key); | |||
hashval = (*__default_hash)(item.key, len); | |||
head = &htable[hashval & (htablesize - 1)]; | |||
ie = SLIST_FIRST(head); | |||
while (ie != NULL) { | |||
if (strcmp(ie->ent.key, item.key) == 0) | |||
break; | |||
ie = SLIST_NEXT(ie, link); | |||
} | |||
if (ie != NULL) | |||
return &ie->ent; | |||
else if (action == FIND) | |||
return NULL; | |||
ie = malloc(sizeof *ie); | |||
if (ie == NULL) | |||
return NULL; | |||
ie->ent.key = item.key; | |||
ie->ent.data = item.data; | |||
SLIST_INSERT_HEAD(head, ie, link); | |||
return &ie->ent; | |||
} |