aprsc/src/keyhash.c

121 lines
2.7 KiB
C

/*
* aprsc
*
* (c) Matti Aarnio, OH2MQK, <oh2mqk@sral.fi>
*
* This program is licensed under the BSD license, which can be found
* in the file LICENSE.
*
*/
/*
* Keyhash routines for the system.
*
* What is needed is _fast_ hash function. Preferrably arithmethic one,
* which does not need table lookups, and can work with aligned 32 bit
* data -- but also on unaligned, and on any byte counts...
*
* Contenders:
* http://burtleburtle.net/bob/c/lookup3.c
* http://www.ibiblio.org/pub/Linux/devel/lang/c/mph-1.2.tar.gz
* http://www.concentric.net/~Ttwang/tech/inthash.htm
* http://isthe.com/chongo/tech/comp/fnv/
*
* Currently using FNV-1a
*
*/
/*
// FNV-1a hash from http://isthe.com/chongo/tech/comp/fnv/
//
// It is algorithmic hash without memory lookups.
// Compiler seems to prefer actual multiplication over a bunch of
// fixed shifts and additions.
*/
/*
* ON A HIGHLY OPTIMIZED CRC32 HASH CALCULATION PROCESSING ALONE
* THE SYSTEM IS PUSHING AROUND 8-12 % OF CPU TIME!
*
* ... but the previous top waster, the aprsc output filters, are optimized
* to the hilt...
*
* There exists alternate implementations of CRC32 which are 1.7 - 2.3 times
* faster than this one with an expense of using 4kB / 8 kB / 16 kB of tables,
* which of course fill caches...
*
*/
#include <stdint.h>
#include <sys/types.h>
#include "keyhash.h"
#ifdef __GNUC__ // compiling with GCC ?
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#else
#define likely(x) (x)
#define unlikely(x) (x)
#define __attribute__(x)
#endif
void keyhash_init(void) { }
uint32_t __attribute__((pure)) keyhash(const void *p, int len, uint32_t hash)
{
const uint8_t *u = p;
int i;
#define FNV_32_PRIME 16777619U
#define FVN_32_OFFSET 2166136261U
if (hash == 0)
hash = (uint32_t)FVN_32_OFFSET;
for (i = 0; i < len; ++i, ++u) {
#if defined(NO_FNV_GCC_OPTIMIZATION)
hash *= FNV_32_PRIME;
#else
hash += (hash<<1) + (hash<<4) + (hash<<7) +
(hash<<8) + (hash<<24);
#endif
hash ^= (uint32_t) *u;
}
return hash;
}
/* The data material is known to contain ASCII, and if any value in there
* is a lower case letter, it is first converted to upper case one.
*/
uint32_t __attribute__((pure)) keyhashuc(const void *p, int len, uint32_t hash)
{
const uint8_t *u = p;
int i;
if (hash == 0)
hash = (uint32_t)FVN_32_OFFSET;
for (i = 0; i < len; ++i, ++u) {
#if defined(NO_FNV_GCC_OPTIMIZATION)
hash *= FNV_32_PRIME;
#else
hash += (hash<<1) + (hash<<4) + (hash<<7) +
(hash<<8) + (hash<<24);
#endif
uint32_t c = *u;
// Is it lower case ASCII letter ?
if ('a' <= c && c <= 'z') {
// convert to upper case.
c -= ('a' - 'A');
}
hash ^= c;
}
return hash;
}