diff options
| author | Jerry Jelinek <jerry.jelinek@joyent.com> | 2016-08-18 11:22:02 +0000 | 
|---|---|---|
| committer | Jerry Jelinek <jerry.jelinek@joyent.com> | 2016-08-18 11:22:02 +0000 | 
| commit | e2384e44b3213551c4ea3de2e9b54f1a39eeb708 (patch) | |
| tree | 27853313eac66267f6845d2701dddf640705cd8d /usr/src/cmd/mandoc/compat_ohash.c | |
| parent | 2284cf450f099ce8441493d7c9f2c1cb0bbf474f (diff) | |
| parent | 371584c2eae4cf827fd406ba26c14f021adaaa70 (diff) | |
| download | illumos-joyent-e2384e44b3213551c4ea3de2e9b54f1a39eeb708.tar.gz | |
	[illumos-gate merge]
commit 371584c2eae4cf827fd406ba26c14f021adaaa70
    7243 update mdocml to 1.13.4
commit 7a8b8fd18ff115f0caa89183db5373afb568b630
    5166 sendmail package should be replaceable (followup)
Diffstat (limited to 'usr/src/cmd/mandoc/compat_ohash.c')
| -rw-r--r-- | usr/src/cmd/mandoc/compat_ohash.c | 339 | 
1 files changed, 339 insertions, 0 deletions
| diff --git a/usr/src/cmd/mandoc/compat_ohash.c b/usr/src/cmd/mandoc/compat_ohash.c new file mode 100644 index 0000000000..cbd6052182 --- /dev/null +++ b/usr/src/cmd/mandoc/compat_ohash.c @@ -0,0 +1,339 @@ +#include "config.h" + +#if HAVE_OHASH + +int dummy; + +#else + +/* $OpenBSD: ohash.c,v 1.1 2014/06/02 18:52:03 deraadt Exp $ */ + +/* 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 <sys/types.h> + +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include "compat_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 + +static void ohash_resize(struct ohash *); + + +/* 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; +} + +/* 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 +} + +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; +} + +unsigned int +ohash_entries(struct ohash *h) +{ +	return h->total - h->deleted; +} + +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; +} + +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; +} + +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; +} + +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; +} + +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; +} + +unsigned int +ohash_qlookup(struct ohash *h, const char *s) +{ +	const char *e = NULL; +	return ohash_qlookupi(h, s, &e); +} + +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); +} + +#endif /*!HAVE_OHASH*/ | 
