hash_func.c revision 92905
11573Srgrimes/*-
21573Srgrimes * Copyright (c) 1990, 1993
31573Srgrimes *	The Regents of the University of California.  All rights reserved.
41573Srgrimes *
51573Srgrimes * This code is derived from software contributed to Berkeley by
61573Srgrimes * Margo Seltzer.
71573Srgrimes *
81573Srgrimes * Redistribution and use in source and binary forms, with or without
91573Srgrimes * modification, are permitted provided that the following conditions
101573Srgrimes * are met:
111573Srgrimes * 1. Redistributions of source code must retain the above copyright
121573Srgrimes *    notice, this list of conditions and the following disclaimer.
131573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141573Srgrimes *    notice, this list of conditions and the following disclaimer in the
151573Srgrimes *    documentation and/or other materials provided with the distribution.
161573Srgrimes * 3. All advertising materials mentioning features or use of this software
171573Srgrimes *    must display the following acknowledgement:
181573Srgrimes *	This product includes software developed by the University of
191573Srgrimes *	California, Berkeley and its contributors.
201573Srgrimes * 4. Neither the name of the University nor the names of its contributors
211573Srgrimes *    may be used to endorse or promote products derived from this software
221573Srgrimes *    without specific prior written permission.
231573Srgrimes *
241573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341573Srgrimes * SUCH DAMAGE.
351573Srgrimes */
361573Srgrimes
371573Srgrimes#if defined(LIBC_SCCS) && !defined(lint)
381573Srgrimesstatic char sccsid[] = "@(#)hash_func.c	8.2 (Berkeley) 2/21/94";
391573Srgrimes#endif /* LIBC_SCCS and not lint */
4092889Sobrien#include <sys/cdefs.h>
4192889Sobrien__FBSDID("$FreeBSD: head/lib/libc/db/hash/hash_func.c 92905 2002-03-21 22:49:10Z obrien $");
421573Srgrimes
431573Srgrimes#include <sys/types.h>
441573Srgrimes
451573Srgrimes#include <db.h>
461573Srgrimes#include "hash.h"
471573Srgrimes#include "page.h"
481573Srgrimes#include "extern.h"
491573Srgrimes
5092905Sobrienstatic u_int32_t hash1(const void *, size_t);
5192905Sobrienstatic u_int32_t hash2(const void *, size_t);
5292905Sobrienstatic u_int32_t hash3(const void *, size_t);
5392905Sobrienstatic u_int32_t hash4(const void *, size_t);
541573Srgrimes
551573Srgrimes/* Global default hash function */
561573Srgrimesu_int32_t (*__default_hash) __P((const void *, size_t)) = hash4;
571573Srgrimes
581573Srgrimes/*
591573Srgrimes * HASH FUNCTIONS
601573Srgrimes *
611573Srgrimes * Assume that we've already split the bucket to which this key hashes,
621573Srgrimes * calculate that bucket, and check that in fact we did already split it.
631573Srgrimes *
641573Srgrimes * This came from ejb's hsearch.
651573Srgrimes */
661573Srgrimes
671573Srgrimes#define PRIME1		37
681573Srgrimes#define PRIME2		1048583
691573Srgrimes
701573Srgrimesstatic u_int32_t
711573Srgrimeshash1(keyarg, len)
721573Srgrimes	const void *keyarg;
7392889Sobrien	size_t len;
741573Srgrimes{
7592889Sobrien	const u_char *key;
7692889Sobrien	u_int32_t h;
771573Srgrimes
781573Srgrimes	/* Convert string to integer */
791573Srgrimes	for (key = keyarg, h = 0; len--;)
801573Srgrimes		h = h * PRIME1 ^ (*key++ - ' ');
811573Srgrimes	h %= PRIME2;
821573Srgrimes	return (h);
831573Srgrimes}
841573Srgrimes
851573Srgrimes/*
861573Srgrimes * Phong's linear congruential hash
871573Srgrimes */
881573Srgrimes#define dcharhash(h, c)	((h) = 0x63c63cd9*(h) + 0x9c39c33d + (c))
891573Srgrimes
901573Srgrimesstatic u_int32_t
911573Srgrimeshash2(keyarg, len)
921573Srgrimes	const void *keyarg;
931573Srgrimes	size_t len;
941573Srgrimes{
9592889Sobrien	const u_char *e, *key;
9692889Sobrien	u_int32_t h;
9792889Sobrien	u_char c;
981573Srgrimes
991573Srgrimes	key = keyarg;
1001573Srgrimes	e = key + len;
1011573Srgrimes	for (h = 0; key != e;) {
1021573Srgrimes		c = *key++;
1031573Srgrimes		if (!c && key > e)
1041573Srgrimes			break;
1051573Srgrimes		dcharhash(h, c);
1061573Srgrimes	}
1071573Srgrimes	return (h);
1081573Srgrimes}
1091573Srgrimes
1101573Srgrimes/*
1111573Srgrimes * This is INCREDIBLY ugly, but fast.  We break the string up into 8 byte
1121573Srgrimes * units.  On the first time through the loop we get the "leftover bytes"
1131573Srgrimes * (strlen % 8).  On every other iteration, we perform 8 HASHC's so we handle
1141573Srgrimes * all 8 bytes.  Essentially, this saves us 7 cmp & branch instructions.  If
1151573Srgrimes * this routine is heavily used enough, it's worth the ugly coding.
1161573Srgrimes *
1171573Srgrimes * OZ's original sdbm hash
1181573Srgrimes */
1191573Srgrimesstatic u_int32_t
1201573Srgrimeshash3(keyarg, len)
1211573Srgrimes	const void *keyarg;
12292889Sobrien	size_t len;
1231573Srgrimes{
12492889Sobrien	const u_char *key;
12592889Sobrien	size_t loop;
12692889Sobrien	u_int32_t h;
1271573Srgrimes
1281573Srgrimes#define HASHC   h = *key++ + 65599 * h
1291573Srgrimes
1301573Srgrimes	h = 0;
1311573Srgrimes	key = keyarg;
1321573Srgrimes	if (len > 0) {
1331573Srgrimes		loop = (len + 8 - 1) >> 3;
1341573Srgrimes
1351573Srgrimes		switch (len & (8 - 1)) {
1361573Srgrimes		case 0:
1371573Srgrimes			do {
1381573Srgrimes				HASHC;
1391573Srgrimes				/* FALLTHROUGH */
1401573Srgrimes		case 7:
1411573Srgrimes				HASHC;
1421573Srgrimes				/* FALLTHROUGH */
1431573Srgrimes		case 6:
1441573Srgrimes				HASHC;
1451573Srgrimes				/* FALLTHROUGH */
1461573Srgrimes		case 5:
1471573Srgrimes				HASHC;
1481573Srgrimes				/* FALLTHROUGH */
1491573Srgrimes		case 4:
1501573Srgrimes				HASHC;
1511573Srgrimes				/* FALLTHROUGH */
1521573Srgrimes		case 3:
1531573Srgrimes				HASHC;
1541573Srgrimes				/* FALLTHROUGH */
1551573Srgrimes		case 2:
1561573Srgrimes				HASHC;
1571573Srgrimes				/* FALLTHROUGH */
1581573Srgrimes		case 1:
1591573Srgrimes				HASHC;
1601573Srgrimes			} while (--loop);
1611573Srgrimes		}
1621573Srgrimes	}
1631573Srgrimes	return (h);
1641573Srgrimes}
1651573Srgrimes
1661573Srgrimes/* Hash function from Chris Torek. */
1671573Srgrimesstatic u_int32_t
1681573Srgrimeshash4(keyarg, len)
1691573Srgrimes	const void *keyarg;
17092889Sobrien	size_t len;
1711573Srgrimes{
17292889Sobrien	const u_char *key;
17392889Sobrien	size_t loop;
17492889Sobrien	u_int32_t h;
1751573Srgrimes
1761573Srgrimes#define HASH4a   h = (h << 5) - h + *key++;
1771573Srgrimes#define HASH4b   h = (h << 5) + h + *key++;
1781573Srgrimes#define HASH4 HASH4b
1791573Srgrimes
1801573Srgrimes	h = 0;
1811573Srgrimes	key = keyarg;
1821573Srgrimes	if (len > 0) {
1831573Srgrimes		loop = (len + 8 - 1) >> 3;
1841573Srgrimes
1851573Srgrimes		switch (len & (8 - 1)) {
1861573Srgrimes		case 0:
1871573Srgrimes			do {
1881573Srgrimes				HASH4;
1891573Srgrimes				/* FALLTHROUGH */
1901573Srgrimes		case 7:
1911573Srgrimes				HASH4;
1921573Srgrimes				/* FALLTHROUGH */
1931573Srgrimes		case 6:
1941573Srgrimes				HASH4;
1951573Srgrimes				/* FALLTHROUGH */
1961573Srgrimes		case 5:
1971573Srgrimes				HASH4;
1981573Srgrimes				/* FALLTHROUGH */
1991573Srgrimes		case 4:
2001573Srgrimes				HASH4;
2011573Srgrimes				/* FALLTHROUGH */
2021573Srgrimes		case 3:
2031573Srgrimes				HASH4;
2041573Srgrimes				/* FALLTHROUGH */
2051573Srgrimes		case 2:
2061573Srgrimes				HASH4;
2071573Srgrimes				/* FALLTHROUGH */
2081573Srgrimes		case 1:
2091573Srgrimes				HASH4;
2101573Srgrimes			} while (--loop);
2111573Srgrimes		}
2121573Srgrimes	}
2131573Srgrimes	return (h);
2141573Srgrimes}
215