It's not a standard interface, so it doesn't belong in libc. I hate duplicating the code in client programs, so do beck@, kettenis@, schwarze@, millert@, miod@... and they agree with libutil.OPENBSD_5_6
@ -0,0 +1,75 @@ | |||
#ifndef OHASH_H | |||
#define OHASH_H | |||
/* $OpenBSD: ohash.h,v 1.1 2014/05/12 19:09:00 espie Exp $ */ | |||
/* ex:ts=8 sw=4: | |||
*/ | |||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org> | |||
* | |||
* Permission to use, copy, modify, and distribute this software for any | |||
* purpose with or without fee is hereby granted, provided that the above | |||
* copyright notice and this permission notice appear in all copies. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/* Open hashing support. | |||
* Open hashing was chosen because it is much lighter than other hash | |||
* techniques, and more efficient in most cases. | |||
*/ | |||
/* user-visible data structure */ | |||
struct ohash_info { | |||
ptrdiff_t key_offset; | |||
void *data; /* user data */ | |||
void *(*calloc)(size_t, size_t, void *); | |||
void (*free)(void *, void *); | |||
void *(*alloc)(size_t, void *); | |||
}; | |||
struct _ohash_record; | |||
/* private structure. It's there just so you can do a sizeof */ | |||
struct ohash { | |||
struct _ohash_record *t; | |||
struct ohash_info info; | |||
unsigned int size; | |||
unsigned int total; | |||
unsigned int deleted; | |||
}; | |||
/* For this to be tweakable, we use small primitives, and leave part of the | |||
* logic to the client application. e.g., hashing is left to the client | |||
* application. We also provide a simple table entry lookup that yields | |||
* a hashing table index (opaque) to be used in find/insert/remove. | |||
* The keys are stored at a known position in the client data. | |||
*/ | |||
__BEGIN_DECLS | |||
void ohash_init(struct ohash *, unsigned, struct ohash_info *); | |||
void ohash_delete(struct ohash *); | |||
unsigned int ohash_lookup_interval(struct ohash *, const char *, | |||
const char *, uint32_t); | |||
unsigned int ohash_lookup_memory(struct ohash *, const char *, | |||
size_t, uint32_t) | |||
__attribute__ ((__bounded__(__string__,2,3))); | |||
void *ohash_find(struct ohash *, unsigned int); | |||
void *ohash_remove(struct ohash *, unsigned int); | |||
void *ohash_insert(struct ohash *, unsigned int, void *); | |||
void *ohash_first(struct ohash *, unsigned int *); | |||
void *ohash_next(struct ohash *, unsigned int *); | |||
unsigned int ohash_entries(struct ohash *); | |||
void *ohash_create_entry(struct ohash_info *, const char *, const char **); | |||
uint32_t ohash_interval(const char *, const char **); | |||
unsigned int ohash_qlookupi(struct ohash *, const char *, const char **); | |||
unsigned int ohash_qlookup(struct ohash *, const char *); | |||
__END_DECLS | |||
#endif |
@ -0,0 +1,38 @@ | |||
/* $OpenBSD: ohash_create_entry.c,v 1.1 2014/05/12 19:09:00 espie Exp $ */ | |||
/* ex:ts=8 sw=4: | |||
*/ | |||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org> | |||
* | |||
* Permission to use, copy, modify, and distribute this software for any | |||
* purpose with or without fee is hereby granted, provided that the above | |||
* copyright notice and this permission notice appear in all copies. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#include "ohash_int.h" | |||
/* This handles the common case of variable length keys, where the | |||
* key is stored at the end of the record. | |||
*/ | |||
void * | |||
ohash_create_entry(struct ohash_info *i, const char *start, const char **end) | |||
{ | |||
char *p; | |||
if (!*end) | |||
*end = start + strlen(start); | |||
p = (i->alloc)(i->key_offset + (*end - start) + 1, i->data); | |||
if (p) { | |||
memcpy(p+i->key_offset, start, *end-start); | |||
p[i->key_offset + (*end - start)] = '\0'; | |||
} | |||
return (void *)p; | |||
} |
@ -0,0 +1,30 @@ | |||
/* $OpenBSD: ohash_delete.c,v 1.1 2014/05/12 19:09:00 espie Exp $ */ | |||
/* ex:ts=8 sw=4: | |||
*/ | |||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org> | |||
* | |||
* Permission to use, copy, modify, and distribute this software for any | |||
* purpose with or without fee is hereby granted, provided that the above | |||
* copyright notice and this permission notice appear in all copies. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#include "ohash_int.h" | |||
/* hash_delete only frees the hash structure. Use hash_first/hash_next | |||
* to free entries as well. */ | |||
void | |||
ohash_delete(struct ohash *h) | |||
{ | |||
(h->info.free)(h->t, h->info.data); | |||
#ifndef NDEBUG | |||
h->t = NULL; | |||
#endif | |||
} |
@ -0,0 +1,116 @@ | |||
/* $OpenBSD: ohash_do.c,v 1.1 2014/05/12 19:09:00 espie Exp $ */ | |||
/* ex:ts=8 sw=4: | |||
*/ | |||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org> | |||
* | |||
* Permission to use, copy, modify, and distribute this software for any | |||
* purpose with or without fee is hereby granted, provided that the above | |||
* copyright notice and this permission notice appear in all copies. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#include <limits.h> | |||
#include "ohash_int.h" | |||
static void ohash_resize(struct ohash *); | |||
static void | |||
ohash_resize(struct ohash *h) | |||
{ | |||
struct _ohash_record *n; | |||
size_t ns; | |||
unsigned int j; | |||
unsigned int i, incr; | |||
if (4 * h->deleted < h->total) { | |||
if (h->size >= (UINT_MAX >> 1U)) | |||
ns = UINT_MAX; | |||
else | |||
ns = h->size << 1U; | |||
} else if (3 * h->deleted > 2 * h->total) | |||
ns = h->size >> 1U; | |||
else | |||
ns = h->size; | |||
if (ns < MINSIZE) | |||
ns = MINSIZE; | |||
#ifdef STATS_HASH | |||
STAT_HASH_EXPAND++; | |||
STAT_HASH_SIZE += ns - h->size; | |||
#endif | |||
n = (h->info.calloc)(ns, sizeof(struct _ohash_record), h->info.data); | |||
if (!n) | |||
return; | |||
for (j = 0; j < h->size; j++) { | |||
if (h->t[j].p != NULL && h->t[j].p != DELETED) { | |||
i = h->t[j].hv % ns; | |||
incr = ((h->t[j].hv % (ns - 2)) & ~1) + 1; | |||
while (n[i].p != NULL) { | |||
i += incr; | |||
if (i >= ns) | |||
i -= ns; | |||
} | |||
n[i].hv = h->t[j].hv; | |||
n[i].p = h->t[j].p; | |||
} | |||
} | |||
(h->info.free)(h->t, h->info.data); | |||
h->t = n; | |||
h->size = ns; | |||
h->total -= h->deleted; | |||
h->deleted = 0; | |||
} | |||
void * | |||
ohash_remove(struct ohash *h, unsigned int i) | |||
{ | |||
void *result = (void *)h->t[i].p; | |||
if (result == NULL || result == DELETED) | |||
return NULL; | |||
#ifdef STATS_HASH | |||
STAT_HASH_ENTRIES--; | |||
#endif | |||
h->t[i].p = DELETED; | |||
h->deleted++; | |||
if (h->deleted >= MINDELETED && 4 * h->deleted > h->total) | |||
ohash_resize(h); | |||
return result; | |||
} | |||
void * | |||
ohash_find(struct ohash *h, unsigned int i) | |||
{ | |||
if (h->t[i].p == DELETED) | |||
return NULL; | |||
else | |||
return (void *)h->t[i].p; | |||
} | |||
void * | |||
ohash_insert(struct ohash *h, unsigned int i, void *p) | |||
{ | |||
#ifdef STATS_HASH | |||
STAT_HASH_ENTRIES++; | |||
#endif | |||
if (h->t[i].p == DELETED) { | |||
h->deleted--; | |||
h->t[i].p = p; | |||
} else { | |||
h->t[i].p = p; | |||
/* Arbitrary resize boundary. Tweak if not efficient enough. */ | |||
if (++h->total * 4 > h->size * 3) | |||
ohash_resize(h); | |||
} | |||
return p; | |||
} |
@ -0,0 +1,26 @@ | |||
/* $OpenBSD: ohash_entries.c,v 1.1 2014/05/12 19:09:00 espie Exp $ */ | |||
/* ex:ts=8 sw=4: | |||
*/ | |||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org> | |||
* | |||
* Permission to use, copy, modify, and distribute this software for any | |||
* purpose with or without fee is hereby granted, provided that the above | |||
* copyright notice and this permission notice appear in all copies. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#include "ohash_int.h" | |||
unsigned int | |||
ohash_entries(struct ohash *h) | |||
{ | |||
return h->total - h->deleted; | |||
} |
@ -0,0 +1,36 @@ | |||
/* $OpenBSD: ohash_enum.c,v 1.1 2014/05/12 19:09:00 espie Exp $ */ | |||
/* ex:ts=8 sw=4: | |||
*/ | |||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org> | |||
* | |||
* Permission to use, copy, modify, and distribute this software for any | |||
* purpose with or without fee is hereby granted, provided that the above | |||
* copyright notice and this permission notice appear in all copies. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#include "ohash_int.h" | |||
void * | |||
ohash_first(struct ohash *h, unsigned int *pos) | |||
{ | |||
*pos = 0; | |||
return ohash_next(h, pos); | |||
} | |||
void * | |||
ohash_next(struct ohash *h, unsigned int *pos) | |||
{ | |||
for (; *pos < h->size; (*pos)++) | |||
if (h->t[*pos].p != DELETED && h->t[*pos].p != NULL) | |||
return (void *)h->t[(*pos)++].p; | |||
return NULL; | |||
} |
@ -0,0 +1,271 @@ | |||
.\" $OpenBSD: ohash_init.3,v 1.1 2014/05/12 19:09:00 espie Exp $ | |||
.\" Copyright (c) 1999 Marc Espie <espie@openbsd.org> | |||
.\" | |||
.\" Permission to use, copy, modify, and distribute this software for any | |||
.\" purpose with or without fee is hereby granted, provided that the above | |||
.\" copyright notice and this permission notice appear in all copies. | |||
.\" | |||
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
.\" | |||
.Dd $Mdocdate: May 12 2014 $ | |||
.Dt OHASH_INIT 3 | |||
.Os | |||
.Sh NAME | |||
.Nm ohash_init , | |||
.Nm ohash_delete , | |||
.Nm ohash_lookup_interval , | |||
.Nm ohash_lookup_memory , | |||
.Nm ohash_find , | |||
.Nm ohash_remove , | |||
.Nm ohash_insert , | |||
.Nm ohash_first , | |||
.Nm ohash_next , | |||
.Nm ohash_entries | |||
.Nd light-weight open hashing | |||
.Sh SYNOPSIS | |||
.In stdint.h | |||
.In stddef.h | |||
.In ohash.h | |||
.Ft void | |||
.Fn ohash_init "struct ohash *h" "unsigned int size" "struct ohash_info *info" | |||
.Ft void | |||
.Fn ohash_delete "struct ohash *h" | |||
.Ft "unsigned int" | |||
.Fn ohash_lookup_interval "struct ohash *h" "const char *start" "const char *end" "uint32_t hv" | |||
.Ft "unsigned int" | |||
.Fn ohash_lookup_memory "struct ohash *h" "const char *k" "size_t s" "uint32_t hv" | |||
.Ft void * | |||
.Fn ohash_find "struct ohash *h" "unsigned int i" | |||
.Ft void * | |||
.Fn ohash_remove "struct ohash *h" "unsigned int i" | |||
.Ft void * | |||
.Fn ohash_insert "struct ohash *h" "unsigned int i" "void *p" | |||
.Ft void * | |||
.Fn ohash_first "struct ohash *h" "unsigned int *i" | |||
.Ft void * | |||
.Fn ohash_next "struct ohash *h" "unsigned int *i" | |||
.Ft "unsigned int" | |||
.Fn ohash_entries "struct ohash *h" | |||
.Sh DESCRIPTION | |||
These functions have been designed as a fast, extensible alternative to | |||
the usual hash table functions. | |||
They provide storage and retrieval of records indexed by keys, | |||
where a key is a contiguous sequence of bytes at a fixed position in | |||
each record. | |||
Keys can either be NUL-terminated strings or fixed-size memory areas. | |||
All functions take a pointer to an ohash structure as the | |||
.Fa h | |||
function argument. | |||
Storage for this structure should be provided by user code. | |||
.Pp | |||
.Fn ohash_init | |||
initializes the table to store roughly 2 to the power | |||
.Fa size | |||
elements. | |||
.Fa info | |||
is a pointer to a | |||
.Fa struct ohash_info . | |||
.Bd -literal -offset indent | |||
struct ohash_info { | |||
ptrdiff_t key_offset; | |||
void *data; /* user data */ | |||
void *(*calloc)(size_t, size_t, void *); | |||
void (*free)(void *, void *); | |||
void *(*alloc)(size_t, void *); | |||
}; | |||
.Ed | |||
.Pp | |||
The | |||
.Va offset | |||
field holds the position of the key in each record; | |||
the | |||
.Va calloc | |||
and | |||
.Va free | |||
fields are pointers to | |||
.Xr calloc 3 | |||
and | |||
.Xr free 3 Ns -like | |||
functions, used for managing the table internal storage; | |||
the | |||
.Va alloc | |||
field is only used by the utility function | |||
.Xr ohash_create_entry 3 . | |||
.Pp | |||
Each of these functions are called similarly to their standard counterpart, | |||
but with an extra | |||
.Ft void * | |||
parameter corresponding to the content of the field | |||
.Fa data , | |||
which can be used to communicate specific information to the functions. | |||
.Pp | |||
.Fn ohash_init | |||
stores a copy of those fields internally, so | |||
.Fa info | |||
can be reclaimed after initialization. | |||
.Pp | |||
.Fn ohash_delete | |||
frees storage internal to | |||
.Fa h . | |||
Elements themselves should be freed by the user first, using for instance | |||
.Fn ohash_first | |||
and | |||
.Fn ohash_next . | |||
.Pp | |||
.Fn ohash_lookup_interval | |||
and | |||
.Fn ohash_lookup_memory | |||
are the basic look-up element functions. | |||
The hashing function result is provided by the user as | |||
.Fa hv . | |||
These return a | |||
.Qq slot | |||
in the ohash table | |||
.Fa h , | |||
to be used with | |||
.Fn ohash_find , | |||
.Fn ohash_insert , | |||
or | |||
.Fn ohash_remove . | |||
This slot is only valid up to the next call to | |||
.Fn ohash_insert | |||
or | |||
.Fn ohash_remove . | |||
.Pp | |||
.Fn ohash_lookup_interval | |||
handles string-like keys. | |||
.Fn ohash_lookup_interval | |||
assumes the key is the interval between | |||
.Fa start | |||
and | |||
.Fa end , | |||
exclusive, | |||
though the actual elements stored in the table should only contain | |||
NUL-terminated keys. | |||
.Pp | |||
.Fn ohash_lookup_memory | |||
assumes the key is the memory area starting at | |||
.Fa k | |||
of size | |||
.Fa s . | |||
All bytes are significant in key comparison. | |||
.Pp | |||
.Fn ohash_find | |||
retrieves an element from a slot | |||
.Fa i | |||
returned by the | |||
.Fn ohash_lookup* | |||
functions. | |||
It returns | |||
.Dv NULL | |||
if the slot is empty. | |||
.Pp | |||
.Fn ohash_insert | |||
inserts a new element | |||
.Fa p | |||
at slot | |||
.Fa i . | |||
Slot | |||
.Fa i | |||
must be empty and element | |||
.Fa p | |||
must have a key corresponding to the | |||
.Fn ohash_lookup* | |||
call. | |||
.Pp | |||
.Fn ohash_remove | |||
removes the element at slot | |||
.Fa i . | |||
It returns the removed element, for user code to dispose of, or | |||
.Dv NULL | |||
if the slot was empty. | |||
.Pp | |||
.Fn ohash_first | |||
and | |||
.Fn ohash_next | |||
can be used to access all elements in an ohash table, like this: | |||
.Bd -literal -offset indent | |||
for (n = ohash_first(h, &i); n != NULL; n = ohash_next(h, &i)) | |||
do_something_with(n); | |||
.Ed | |||
.Pp | |||
.Fa i | |||
points to an auxiliary unsigned integer used to record the current position | |||
in the ohash table. | |||
Those functions are safe to use even while entries are added to/removed | |||
from the table, but in such a case they don't guarantee that new entries | |||
will be returned. | |||
As a special case, they can safely be used to free elements in the table. | |||
.Pp | |||
.Fn ohash_entries | |||
returns the number of elements in the hash table. | |||
.Sh STORAGE HANDLING | |||
Only | |||
.Fn ohash_init , | |||
.Fn ohash_insert , | |||
.Fn ohash_remove | |||
and | |||
.Fn ohash_delete | |||
may call the user-supplied memory functions: | |||
.Bd -literal -offset indent | |||
p = (*info->calloc)(n, sizeof_record, info->data); | |||
/* copy data from old to p */ | |||
(*info->free)(old, info->data); | |||
.Ed | |||
.Pp | |||
It is the responsibility of the user memory allocation code to verify | |||
that those calls did not fail. | |||
.Pp | |||
If memory allocation fails, | |||
.Fn ohash_init | |||
returns a useless hash table. | |||
.Fn ohash_insert | |||
and | |||
.Fn ohash_remove | |||
still perform the requested operation, but the returned table should be | |||
considered read-only. | |||
It can still be accessed by | |||
.Fn ohash_lookup* , | |||
.Fn ohash_find , | |||
.Fn ohash_first | |||
and | |||
.Fn ohash_next | |||
to dump relevant information to disk before aborting. | |||
.Sh THREAD SAFETY | |||
The open hashing functions are not thread-safe by design. | |||
In particular, in a threaded environment, there is no guarantee that a | |||
.Qq slot | |||
will not move between a | |||
.Fn ohash_lookup* | |||
and a | |||
.Fn ohash_find , | |||
.Fn ohash_insert | |||
or | |||
.Fn ohash_remove | |||
call. | |||
.Pp | |||
Multi-threaded applications should explicitly protect ohash table access. | |||
.Sh SEE ALSO | |||
.Xr hcreate 3 , | |||
.Xr ohash_interval 3 | |||
.Rs | |||
.%A Donald E. Knuth | |||
.%B The Art of Computer Programming | |||
.%V Vol. 3 | |||
.%P pp 506-550 | |||
.%D 1973 | |||
.Re | |||
.Sh STANDARDS | |||
Those functions are completely non-standard and should be avoided in | |||
portable programs. | |||
.Sh HISTORY | |||
Those functions were designed and written for | |||
.Ox | |||
.Xr make 1 | |||
by Marc Espie in 1999. |
@ -0,0 +1,41 @@ | |||
/* $OpenBSD: ohash_init.c,v 1.1 2014/05/12 19:09:00 espie Exp $ */ | |||
/* ex:ts=8 sw=4: | |||
*/ | |||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org> | |||
* | |||
* Permission to use, copy, modify, and distribute this software for any | |||
* purpose with or without fee is hereby granted, provided that the above | |||
* copyright notice and this permission notice appear in all copies. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#include "ohash_int.h" | |||
void | |||
ohash_init(struct ohash *h, unsigned int size, struct ohash_info *info) | |||
{ | |||
h->size = 1UL << size; | |||
if (h->size < MINSIZE) | |||
h->size = MINSIZE; | |||
#ifdef STATS_HASH | |||
STAT_HASH_CREATION++; | |||
STAT_HASH_SIZE += h->size; | |||
#endif | |||
/* Copy info so that caller may free it. */ | |||
h->info.key_offset = info->key_offset; | |||
h->info.calloc = info->calloc; | |||
h->info.free = info->free; | |||
h->info.alloc = info->alloc; | |||
h->info.data = info->data; | |||
h->t = (h->info.calloc)(h->size, sizeof(struct _ohash_record), | |||
h->info.data); | |||
h->total = h->deleted = 0; | |||
} |
@ -0,0 +1,19 @@ | |||
/* $OpenBSD: ohash_int.h,v 1.1 2014/05/12 19:09:00 espie Exp $ */ | |||
#include <stddef.h> | |||
#include <stdint.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include "ohash.h" | |||
struct _ohash_record { | |||
uint32_t hv; | |||
const char *p; | |||
}; | |||
#define DELETED ((const char *)h) | |||
#define NONE (h->size) | |||
/* Don't bother changing the hash table if the change is small enough. */ | |||
#define MINSIZE (1UL << 4) | |||
#define MINDELETED 4 |
@ -0,0 +1,93 @@ | |||
.\" $OpenBSD: ohash_interval.3,v 1.1 2014/05/12 19:09:00 espie Exp $ | |||
.\" Copyright (c) 2001 Marc Espie <espie@openbsd.org> | |||
.\" | |||
.\" Permission to use, copy, modify, and distribute this software for any | |||
.\" purpose with or without fee is hereby granted, provided that the above | |||
.\" copyright notice and this permission notice appear in all copies. | |||
.\" | |||
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
.\" | |||
.Dd $Mdocdate: May 12 2014 $ | |||
.Dt OHASH_INTERVAL 3 | |||
.Os | |||
.Sh NAME | |||
.Nm ohash_interval , | |||
.Nm ohash_create_entry , | |||
.Nm ohash_qlookup , | |||
.Nm ohash_qlookupi | |||
.Nd helper functions for open hashing | |||
.Sh SYNOPSIS | |||
.In stdint.h | |||
.In stddef.h | |||
.In ohash.h | |||
.Ft uint32_t | |||
.Fn ohash_interval "const char *start" "const char **pend" | |||
.Ft "void *" | |||
.Fn ohash_create_entry "struct ohash_info *info" "const char *start" "const char **pend" | |||
.Ft "unsigned int" | |||
.Fn ohash_qlookupi "struct ohash *h" "const char *start" "const char **pend" | |||
.Ft "unsigned int" | |||
.Fn ohash_qlookup "struct ohash *h" "const char *start" | |||
.Sh DESCRIPTION | |||
These functions are commonly used to simplify open hashing usage, and use | |||
similar conventions. | |||
They operate indifferently on NUL-terminated strings | |||
.Po | |||
by setting | |||
.Fa *pend | |||
= | |||
.Dv NULL | |||
.Pc | |||
or memory ranges | |||
.Po | |||
delimited by | |||
.Fa start | |||
and | |||
.Fa *pend | |||
.Pc . | |||
For NUL-terminated strings, as a side effect, those functions | |||
set | |||
.Fa *pend | |||
to the terminating NUL byte. | |||
.Pp | |||
.Fn ohash_interval | |||
is a simple hashing function that yields good results on common data sets. | |||
.Pp | |||
.Fn ohash_create_entry | |||
can be used to create a new record with a given key. | |||
In that case, | |||
the alloc field of | |||
.Fa info | |||
should point to a | |||
.Xr malloc 3 Ns -like | |||
function to allocate the storage: | |||
.Bd -literal -offset indent | |||
p = (*info->alloc)(sz, info->data); | |||
.Ed | |||
.Pp | |||
.Fn ohash_qlookupi | |||
is a wrapper function that simply calls | |||
.Fn ohash_interval | |||
and | |||
.Fn ohash_lookup_interval . | |||
.Pp | |||
.Fn ohash_qlookup | |||
is a variation on | |||
.Fn ohash_qlookupi | |||
designed for NUL-terminated strings. | |||
.Sh SEE ALSO | |||
.Xr ohash_init 3 | |||
.Sh STANDARDS | |||
Those functions are completely non-standard and should be avoided in | |||
portable programs. | |||
.Sh HISTORY | |||
Those functions were designed and written for | |||
.Ox | |||
.Xr make 1 | |||
by Marc Espie in 1999. |
@ -0,0 +1,36 @@ | |||
/* $OpenBSD: ohash_interval.c,v 1.1 2014/05/12 19:09:00 espie Exp $ */ | |||
/* ex:ts=8 sw=4: | |||
*/ | |||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org> | |||
* | |||
* Permission to use, copy, modify, and distribute this software for any | |||
* purpose with or without fee is hereby granted, provided that the above | |||
* copyright notice and this permission notice appear in all copies. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#include "ohash_int.h" | |||
uint32_t | |||
ohash_interval(const char *s, const char **e) | |||
{ | |||
uint32_t k; | |||
if (!*e) | |||
*e = s + strlen(s); | |||
if (s == *e) | |||
k = 0; | |||
else | |||
k = *s++; | |||
while (s != *e) | |||
k = ((k << 2) | (k >> 30)) ^ *s++; | |||
return k; | |||
} |
@ -0,0 +1,68 @@ | |||
/* $OpenBSD: ohash_lookup_interval.c,v 1.1 2014/05/12 19:09:00 espie Exp $ */ | |||
/* ex:ts=8 sw=4: | |||
*/ | |||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org> | |||
* | |||
* Permission to use, copy, modify, and distribute this software for any | |||
* purpose with or without fee is hereby granted, provided that the above | |||
* copyright notice and this permission notice appear in all copies. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#include "ohash_int.h" | |||
unsigned int | |||
ohash_lookup_interval(struct ohash *h, const char *start, const char *end, | |||
uint32_t hv) | |||
{ | |||
unsigned int i, incr; | |||
unsigned int empty; | |||
#ifdef STATS_HASH | |||
STAT_HASH_LOOKUP++; | |||
#endif | |||
empty = NONE; | |||
i = hv % h->size; | |||
incr = ((hv % (h->size-2)) & ~1) + 1; | |||
while (h->t[i].p != NULL) { | |||
#ifdef STATS_HASH | |||
STAT_HASH_LENGTH++; | |||
#endif | |||
if (h->t[i].p == DELETED) { | |||
if (empty == NONE) | |||
empty = i; | |||
} else if (h->t[i].hv == hv && | |||
strncmp(h->t[i].p+h->info.key_offset, start, | |||
end - start) == 0 && | |||
(h->t[i].p+h->info.key_offset)[end-start] == '\0') { | |||
if (empty != NONE) { | |||
h->t[empty].hv = hv; | |||
h->t[empty].p = h->t[i].p; | |||
h->t[i].p = DELETED; | |||
return empty; | |||
} else { | |||
#ifdef STATS_HASH | |||
STAT_HASH_POSITIVE++; | |||
#endif | |||
return i; | |||
} | |||
} | |||
i += incr; | |||
if (i >= h->size) | |||
i -= h->size; | |||
} | |||
/* Found an empty position. */ | |||
if (empty != NONE) | |||
i = empty; | |||
h->t[i].hv = hv; | |||
return i; | |||
} |
@ -0,0 +1,64 @@ | |||
/* $OpenBSD: ohash_lookup_memory.c,v 1.1 2014/05/12 19:09:00 espie Exp $ */ | |||
/* ex:ts=8 sw=4: | |||
*/ | |||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org> | |||
* | |||
* Permission to use, copy, modify, and distribute this software for any | |||
* purpose with or without fee is hereby granted, provided that the above | |||
* copyright notice and this permission notice appear in all copies. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#include "ohash_int.h" | |||
unsigned int | |||
ohash_lookup_memory(struct ohash *h, const char *k, size_t size, uint32_t hv) | |||
{ | |||
unsigned int i, incr; | |||
unsigned int empty; | |||
#ifdef STATS_HASH | |||
STAT_HASH_LOOKUP++; | |||
#endif | |||
empty = NONE; | |||
i = hv % h->size; | |||
incr = ((hv % (h->size-2)) & ~1) + 1; | |||
while (h->t[i].p != NULL) { | |||
#ifdef STATS_HASH | |||
STAT_HASH_LENGTH++; | |||
#endif | |||
if (h->t[i].p == DELETED) { | |||
if (empty == NONE) | |||
empty = i; | |||
} else if (h->t[i].hv == hv && | |||
memcmp(h->t[i].p+h->info.key_offset, k, size) == 0) { | |||
if (empty != NONE) { | |||
h->t[empty].hv = hv; | |||
h->t[empty].p = h->t[i].p; | |||
h->t[i].p = DELETED; | |||
return empty; | |||
} else { | |||
#ifdef STATS_HASH | |||
STAT_HASH_POSITIVE++; | |||
#endif | |||
} return i; | |||
} | |||
i += incr; | |||
if (i >= h->size) | |||
i -= h->size; | |||
} | |||
/* Found an empty position. */ | |||
if (empty != NONE) | |||
i = empty; | |||
h->t[i].hv = hv; | |||
return i; | |||
} |
@ -0,0 +1,27 @@ | |||
/* $OpenBSD: ohash_qlookup.c,v 1.1 2014/05/12 19:09:00 espie Exp $ */ | |||
/* ex:ts=8 sw=4: | |||
*/ | |||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org> | |||
* | |||
* Permission to use, copy, modify, and distribute this software for any | |||
* purpose with or without fee is hereby granted, provided that the above | |||
* copyright notice and this permission notice appear in all copies. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#include "ohash_int.h" | |||
unsigned int | |||
ohash_qlookup(struct ohash *h, const char *s) | |||
{ | |||
const char *e = NULL; | |||
return ohash_qlookupi(h, s, &e); | |||
} |
@ -0,0 +1,29 @@ | |||
/* $OpenBSD: ohash_qlookupi.c,v 1.1 2014/05/12 19:09:00 espie Exp $ */ | |||
/* ex:ts=8 sw=4: | |||
*/ | |||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org> | |||
* | |||
* Permission to use, copy, modify, and distribute this software for any | |||
* purpose with or without fee is hereby granted, provided that the above | |||
* copyright notice and this permission notice appear in all copies. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#include "ohash_int.h" | |||
unsigned int | |||
ohash_qlookupi(struct ohash *h, const char *s, const char **e) | |||
{ | |||
uint32_t hv; | |||
hv = ohash_interval(s, e); | |||
return ohash_lookup_interval(h, s, *e, hv); | |||
} |
@ -1,2 +1,2 @@ | |||
major=12 | |||
minor=0 | |||
minor=1 |