version 1.2, 2014/01/04 14:09:28 |
version 1.4, 2014/06/20 02:24:40 |
|
|
|
|
#else |
#else |
|
|
/* $OpenBSD$ */ |
/* $OpenBSD$ */ |
|
|
|
/* 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 <stddef.h> |
#include <stddef.h> |
#include <stdint.h> |
#include <stdint.h> |
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
|
#include <limits.h> |
#include "compat_ohash.h" |
#include "compat_ohash.h" |
|
|
struct _ohash_record { |
struct _ohash_record { |
uint32_t hv; |
uint32_t hv; |
const char *p; |
const char *p; |
}; |
}; |
|
|
#define DELETED ((const char *)h) |
#define DELETED ((const char *)h) |
Line 27 struct _ohash_record { |
|
Line 43 struct _ohash_record { |
|
/* Don't bother changing the hash table if the change is small enough. */ |
/* Don't bother changing the hash table if the change is small enough. */ |
#define MINSIZE (1UL << 4) |
#define MINSIZE (1UL << 4) |
#define MINDELETED 4 |
#define MINDELETED 4 |
/* $OpenBSD$ */ |
|
/* ex:ts=8 sw=4: |
|
*/ |
|
|
|
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org> |
static void ohash_resize(struct ohash *); |
* |
|
* 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. |
|
*/ |
|
|
|
/* This handles the common case of variable length keys, where the |
|
|
/* This handles the common case of variable length keys, where the |
* key is stored at the end of the record. |
* key is stored at the end of the record. |
*/ |
*/ |
void * |
void * |
Line 58 ohash_create_entry(struct ohash_info *i, const char *s |
|
Line 59 ohash_create_entry(struct ohash_info *i, const char *s |
|
*end = start + strlen(start); |
*end = start + strlen(start); |
p = (i->alloc)(i->key_offset + (*end - start) + 1, i->data); |
p = (i->alloc)(i->key_offset + (*end - start) + 1, i->data); |
if (p) { |
if (p) { |
memcpy(p+i->key_offset, start, *end-start); |
memcpy(p+i->key_offset, start, *end-start); |
p[i->key_offset + (*end - start)] = '\0'; |
p[i->key_offset + (*end - start)] = '\0'; |
} |
} |
return (void *)p; |
return (void *)p; |
} |
} |
|
|
/* hash_delete only frees the hash structure. Use hash_first/hash_next |
/* hash_delete only frees the hash structure. Use hash_first/hash_next |
* to free entries as well. */ |
* to free entries as well. */ |
void |
void |
ohash_delete(struct ohash *h) |
ohash_delete(struct ohash *h) |
{ |
{ |
(h->info.hfree)(h->t, sizeof(struct _ohash_record) * h->size, |
(h->info.free)(h->t, h->info.data); |
h->info.data); |
|
#ifndef NDEBUG |
#ifndef NDEBUG |
h->t = NULL; |
h->t = NULL; |
#endif |
#endif |
} |
} |
|
|
static void ohash_resize(struct ohash *); |
static void |
|
|
static void |
|
ohash_resize(struct ohash *h) |
ohash_resize(struct ohash *h) |
{ |
{ |
struct _ohash_record *n; |
struct _ohash_record *n; |
unsigned int ns, j; |
size_t ns; |
|
unsigned int j; |
unsigned int i, incr; |
unsigned int i, incr; |
|
|
if (4 * h->deleted < h->total) |
if (4 * h->deleted < h->total) { |
ns = h->size << 1; |
if (h->size >= (UINT_MAX >> 1U)) |
else if (3 * h->deleted > 2 * h->total) |
ns = UINT_MAX; |
ns = h->size >> 1; |
else |
|
ns = h->size << 1U; |
|
} else if (3 * h->deleted > 2 * h->total) |
|
ns = h->size >> 1U; |
else |
else |
ns = h->size; |
ns = h->size; |
if (ns < MINSIZE) |
if (ns < MINSIZE) |
Line 97 ohash_resize(struct ohash *h) |
|
Line 99 ohash_resize(struct ohash *h) |
|
STAT_HASH_EXPAND++; |
STAT_HASH_EXPAND++; |
STAT_HASH_SIZE += ns - h->size; |
STAT_HASH_SIZE += ns - h->size; |
#endif |
#endif |
n = (h->info.halloc)(sizeof(struct _ohash_record) * ns, h->info.data); |
|
|
n = (h->info.calloc)(ns, sizeof(struct _ohash_record), h->info.data); |
if (!n) |
if (!n) |
return; |
return; |
|
|
Line 109 ohash_resize(struct ohash *h) |
|
Line 112 ohash_resize(struct ohash *h) |
|
i += incr; |
i += incr; |
if (i >= ns) |
if (i >= ns) |
i -= ns; |
i -= ns; |
} |
} |
n[i].hv = h->t[j].hv; |
n[i].hv = h->t[j].hv; |
n[i].p = h->t[j].p; |
n[i].p = h->t[j].p; |
} |
} |
} |
} |
(h->info.hfree)(h->t, sizeof(struct _ohash_record) * h->size, |
(h->info.free)(h->t, h->info.data); |
h->info.data); |
|
h->t = n; |
h->t = n; |
h->size = ns; |
h->size = ns; |
h->total -= h->deleted; |
h->total -= h->deleted; |
Line 125 ohash_resize(struct ohash *h) |
|
Line 127 ohash_resize(struct ohash *h) |
|
void * |
void * |
ohash_remove(struct ohash *h, unsigned int i) |
ohash_remove(struct ohash *h, unsigned int i) |
{ |
{ |
void *result = (void *)h->t[i].p; |
void *result = (void *)h->t[i].p; |
|
|
if (result == NULL || result == DELETED) |
if (result == NULL || result == DELETED) |
return NULL; |
return NULL; |
Line 160 ohash_insert(struct ohash *h, unsigned int i, void *p) |
|
Line 162 ohash_insert(struct ohash *h, unsigned int i, void *p) |
|
h->t[i].p = p; |
h->t[i].p = p; |
} else { |
} else { |
h->t[i].p = p; |
h->t[i].p = p; |
/* Arbitrary resize boundary. Tweak if not efficient enough. */ |
/* Arbitrary resize boundary. Tweak if not efficient enough. */ |
if (++h->total * 4 > h->size * 3) |
if (++h->total * 4 > h->size * 3) |
ohash_resize(h); |
ohash_resize(h); |
} |
} |
return p; |
return p; |
} |
} |
|
|
unsigned int |
unsigned int |
Line 179 ohash_first(struct ohash *h, unsigned int *pos) |
|
Line 181 ohash_first(struct ohash *h, unsigned int *pos) |
|
*pos = 0; |
*pos = 0; |
return ohash_next(h, pos); |
return ohash_next(h, pos); |
} |
} |
|
|
void * |
void * |
ohash_next(struct ohash *h, unsigned int *pos) |
ohash_next(struct ohash *h, unsigned int *pos) |
{ |
{ |
for (; *pos < h->size; (*pos)++) |
for (; *pos < h->size; (*pos)++) |
if (h->t[*pos].p != DELETED && h->t[*pos].p != NULL) |
if (h->t[*pos].p != DELETED && h->t[*pos].p != NULL) |
return (void *)h->t[(*pos)++].p; |
return (void *)h->t[(*pos)++].p; |
return NULL; |
return NULL; |
} |
} |
|
|
void |
void |
ohash_init(struct ohash *h, unsigned int size, struct ohash_info *info) |
ohash_init(struct ohash *h, unsigned int size, struct ohash_info *info) |
{ |
{ |
h->size = 1UL << size; |
h->size = 1UL << size; |
Line 201 ohash_init(struct ohash *h, unsigned int size, struct |
|
Line 203 ohash_init(struct ohash *h, unsigned int size, struct |
|
#endif |
#endif |
/* Copy info so that caller may free it. */ |
/* Copy info so that caller may free it. */ |
h->info.key_offset = info->key_offset; |
h->info.key_offset = info->key_offset; |
h->info.halloc = info->halloc; |
h->info.calloc = info->calloc; |
h->info.hfree = info->hfree; |
h->info.free = info->free; |
h->info.alloc = info->alloc; |
h->info.alloc = info->alloc; |
h->info.data = info->data; |
h->info.data = info->data; |
h->t = (h->info.halloc)(sizeof(struct _ohash_record) * h->size, |
h->t = (h->info.calloc)(h->size, sizeof(struct _ohash_record), |
h->info.data); |
h->info.data); |
h->total = h->deleted = 0; |
h->total = h->deleted = 0; |
} |
} |
|
|
Line 227 ohash_interval(const char *s, const char **e) |
|
Line 229 ohash_interval(const char *s, const char **e) |
|
} |
} |
|
|
unsigned int |
unsigned int |
ohash_lookup_interval(struct ohash *h, const char *start, const char *end, |
ohash_lookup_interval(struct ohash *h, const char *start, const char *end, |
uint32_t hv) |
uint32_t hv) |
{ |
{ |
unsigned int i, incr; |
unsigned int i, incr; |
unsigned int empty; |
unsigned int empty; |
|
|
#ifdef STATS_HASH |
#ifdef STATS_HASH |
STAT_HASH_LOOKUP++; |
STAT_HASH_LOOKUP++; |
#endif |
#endif |
Line 246 ohash_lookup_interval(struct ohash *h, const char *sta |
|
Line 248 ohash_lookup_interval(struct ohash *h, const char *sta |
|
if (h->t[i].p == DELETED) { |
if (h->t[i].p == DELETED) { |
if (empty == NONE) |
if (empty == NONE) |
empty = i; |
empty = i; |
} else if (h->t[i].hv == hv && |
} else if (h->t[i].hv == hv && |
strncmp(h->t[i].p+h->info.key_offset, start, |
strncmp(h->t[i].p+h->info.key_offset, start, |
end - start) == 0 && |
end - start) == 0 && |
(h->t[i].p+h->info.key_offset)[end-start] == '\0') { |
(h->t[i].p+h->info.key_offset)[end-start] == '\0') { |
if (empty != NONE) { |
if (empty != NONE) { |
h->t[empty].hv = hv; |
h->t[empty].hv = hv; |
h->t[empty].p = h->t[i].p; |
h->t[empty].p = h->t[i].p; |
h->t[i].p = DELETED; |
h->t[i].p = DELETED; |
Line 263 ohash_lookup_interval(struct ohash *h, const char *sta |
|
Line 265 ohash_lookup_interval(struct ohash *h, const char *sta |
|
} |
} |
} |
} |
i += incr; |
i += incr; |
if (i >= h->size) |
if (i >= h->size) |
i -= h->size; |
i -= h->size; |
} |
} |
|
|
/* Found an empty position. */ |
/* Found an empty position. */ |
if (empty != NONE) |
if (empty != NONE) |
i = empty; |
i = empty; |
h->t[i].hv = hv; |
h->t[i].hv = hv; |
return i; |
return i; |
Line 279 ohash_lookup_memory(struct ohash *h, const char *k, si |
|
Line 281 ohash_lookup_memory(struct ohash *h, const char *k, si |
|
{ |
{ |
unsigned int i, incr; |
unsigned int i, incr; |
unsigned int empty; |
unsigned int empty; |
|
|
#ifdef STATS_HASH |
#ifdef STATS_HASH |
STAT_HASH_LOOKUP++; |
STAT_HASH_LOOKUP++; |
#endif |
#endif |
Line 293 ohash_lookup_memory(struct ohash *h, const char *k, si |
|
Line 295 ohash_lookup_memory(struct ohash *h, const char *k, si |
|
if (h->t[i].p == DELETED) { |
if (h->t[i].p == DELETED) { |
if (empty == NONE) |
if (empty == NONE) |
empty = i; |
empty = i; |
} else if (h->t[i].hv == hv && |
} else if (h->t[i].hv == hv && |
memcmp(h->t[i].p+h->info.key_offset, k, size) == 0) { |
memcmp(h->t[i].p+h->info.key_offset, k, size) == 0) { |
if (empty != NONE) { |
if (empty != NONE) { |
h->t[empty].hv = hv; |
h->t[empty].hv = hv; |
h->t[empty].p = h->t[i].p; |
h->t[empty].p = h->t[i].p; |
h->t[i].p = DELETED; |
h->t[i].p = DELETED; |
Line 307 ohash_lookup_memory(struct ohash *h, const char *k, si |
|
Line 309 ohash_lookup_memory(struct ohash *h, const char *k, si |
|
} return i; |
} return i; |
} |
} |
i += incr; |
i += incr; |
if (i >= h->size) |
if (i >= h->size) |
i -= h->size; |
i -= h->size; |
} |
} |
|
|
/* Found an empty position. */ |
/* Found an empty position. */ |
if (empty != NONE) |
if (empty != NONE) |
i = empty; |
i = empty; |
h->t[i].hv = hv; |
h->t[i].hv = hv; |
return i; |
return i; |