Files
smartdns/src/include/hash.h

247 lines
11 KiB
C

/*************************************************************************
*
* Copyright (C) 2018-2023 Ruilin Peng (Nick) <pymumu@gmail.com>.
*
* smartdns is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* smartdns is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _GENERIC_HASH_H
#define _GENERIC_HASH_H
#include "bitmap.h"
#include "jhash.h"
/* Fast hashing routine for ints, longs and pointers.
(C) 2002 Nadia Yvette Chambers, IBM */
#ifndef __WORDSIZE
#define __WORDSIZE (__SIZEOF_LONG__ * 8)
#endif
#ifndef BITS_PER_LONG
#define BITS_PER_LONG __WORDSIZE
#endif
/*
* non-constant log of base 2 calculators
* - the arch may override these in asm/bitops.h if they can be implemented
* more efficiently than using fls() and fls64()
* - the arch is not required to handle n==0 if implementing the fallback
*/
static inline __attribute__((const)) int __ilog2_u32(uint32_t n)
{
return fls(n) - 1;
}
static inline __attribute__((const)) int __ilog2_u64(uint64_t n)
{
return fls64(n) - 1;
}
/**
* ilog2 - log of base 2 of 32-bit or a 64-bit unsigned value
* @n - parameter
*
* constant-capable log of base 2 calculation
* - this can be used to initialise global variables from constant data, hence
* the massive ternary operator construction
*
* selects the appropriately-sized optimised version depending on sizeof(n)
*/
#define ilog2(n) \
(__builtin_constant_p(n) ? ((n) < 2 ? 0 \
: (n) & (1ULL << 63) ? 63 \
: (n) & (1ULL << 62) ? 62 \
: (n) & (1ULL << 61) ? 61 \
: (n) & (1ULL << 60) ? 60 \
: (n) & (1ULL << 59) ? 59 \
: (n) & (1ULL << 58) ? 58 \
: (n) & (1ULL << 57) ? 57 \
: (n) & (1ULL << 56) ? 56 \
: (n) & (1ULL << 55) ? 55 \
: (n) & (1ULL << 54) ? 54 \
: (n) & (1ULL << 53) ? 53 \
: (n) & (1ULL << 52) ? 52 \
: (n) & (1ULL << 51) ? 51 \
: (n) & (1ULL << 50) ? 50 \
: (n) & (1ULL << 49) ? 49 \
: (n) & (1ULL << 48) ? 48 \
: (n) & (1ULL << 47) ? 47 \
: (n) & (1ULL << 46) ? 46 \
: (n) & (1ULL << 45) ? 45 \
: (n) & (1ULL << 44) ? 44 \
: (n) & (1ULL << 43) ? 43 \
: (n) & (1ULL << 42) ? 42 \
: (n) & (1ULL << 41) ? 41 \
: (n) & (1ULL << 40) ? 40 \
: (n) & (1ULL << 39) ? 39 \
: (n) & (1ULL << 38) ? 38 \
: (n) & (1ULL << 37) ? 37 \
: (n) & (1ULL << 36) ? 36 \
: (n) & (1ULL << 35) ? 35 \
: (n) & (1ULL << 34) ? 34 \
: (n) & (1ULL << 33) ? 33 \
: (n) & (1ULL << 32) ? 32 \
: (n) & (1ULL << 31) ? 31 \
: (n) & (1ULL << 30) ? 30 \
: (n) & (1ULL << 29) ? 29 \
: (n) & (1ULL << 28) ? 28 \
: (n) & (1ULL << 27) ? 27 \
: (n) & (1ULL << 26) ? 26 \
: (n) & (1ULL << 25) ? 25 \
: (n) & (1ULL << 24) ? 24 \
: (n) & (1ULL << 23) ? 23 \
: (n) & (1ULL << 22) ? 22 \
: (n) & (1ULL << 21) ? 21 \
: (n) & (1ULL << 20) ? 20 \
: (n) & (1ULL << 19) ? 19 \
: (n) & (1ULL << 18) ? 18 \
: (n) & (1ULL << 17) ? 17 \
: (n) & (1ULL << 16) ? 16 \
: (n) & (1ULL << 15) ? 15 \
: (n) & (1ULL << 14) ? 14 \
: (n) & (1ULL << 13) ? 13 \
: (n) & (1ULL << 12) ? 12 \
: (n) & (1ULL << 11) ? 11 \
: (n) & (1ULL << 10) ? 10 \
: (n) & (1ULL << 9) ? 9 \
: (n) & (1ULL << 8) ? 8 \
: (n) & (1ULL << 7) ? 7 \
: (n) & (1ULL << 6) ? 6 \
: (n) & (1ULL << 5) ? 5 \
: (n) & (1ULL << 4) ? 4 \
: (n) & (1ULL << 3) ? 3 \
: (n) & (1ULL << 2) ? 2 \
: 1) \
: (sizeof(n) <= 4) ? __ilog2_u32(n) \
: __ilog2_u64(n))
#if BITS_PER_LONG == 32
#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_32
#define hash_long(val, bits) hash_32(val, bits)
#elif BITS_PER_LONG == 64
#define hash_long(val, bits) hash_64(val, bits)
#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_64
#else
#error Wordsize not 32 or 64
#endif
/*
* This hash multiplies the input by a large odd number and takes the
* high bits. Since multiplication propagates changes to the most
* significant end only, it is essential that the high bits of the
* product be used for the hash value.
*
* Chuck Lever verified the effectiveness of this technique:
* http://www.citi.umich.edu/techreports/reports/citi-tr-00-1.pdf
*
* Although a random odd number will do, it turns out that the golden
* ratio phi = (sqrt(5)-1)/2, or its negative, has particularly nice
* properties. (See Knuth vol 3, section 6.4, exercise 9.)
*
* These are the negative, (1 - phi) = phi**2 = (3 - sqrt(5))/2,
* which is very slightly easier to multiply by and makes no
* difference to the hash distribution.
*/
#define GOLDEN_RATIO_32 0x61C88647
#define GOLDEN_RATIO_64 0x61C8864680B583EBull
/*
* The _generic versions exist only so lib/test_hash.c can compare
* the arch-optimized versions with the generic.
*
* Note that if you change these, any <asm/hash.h> that aren't updated
* to match need to have their HAVE_ARCH_* define values updated so the
* self-test will not false-positive.
*/
#ifndef HAVE_ARCH__HASH_32
#define __hash_32 __hash_32_generic
#endif
static inline uint32_t __hash_32_generic(uint32_t val)
{
return val * GOLDEN_RATIO_32;
}
#ifndef HAVE_ARCH_HASH_32
#define hash_32 hash_32_generic
#endif
static inline uint32_t hash_32_generic(uint32_t val, unsigned int bits)
{
/* High bits are more random, so use them. */
return __hash_32(val) >> (32 - bits);
}
#ifndef HAVE_ARCH_HASH_64
#define hash_64 hash_64_generic
#endif
static inline uint32_t hash_64(uint64_t val, unsigned int bits)
{
#if BITS_PER_LONG == 64
/* 64x64-bit multiply is efficient on all 64-bit processors */
return val * GOLDEN_RATIO_64 >> (64 - bits);
#else
/* Hash 64 bits using only 32x32-bit multiply. */
return hash_32((uint32_t)val ^ __hash_32(val >> 32), bits);
#endif
}
static inline uint32_t hash_ptr(const void *ptr, unsigned int bits)
{
return hash_long((unsigned long)ptr, bits);
}
/* This really should be called fold32_ptr; it does no hashing to speak of. */
static inline uint32_t hash32_ptr(const void *ptr)
{
unsigned long val = (unsigned long)ptr;
#if BITS_PER_LONG == 64
val ^= (val >> 32);
#endif
return (uint32_t)val;
}
static inline uint32_t hash_string_initval(const char *s, uint32_t initval)
{
uint32_t h = initval;
while (*s) {
h = h * 31 + *s;
s++;
}
return h;
}
static inline uint32_t hash_string(const char *s)
{
return hash_string_initval(s, 0);
}
static inline uint32_t hash_string_array(const char **a)
{
uint32_t h = 0;
const char *s;
while ((s = *a++)) {
while (*s) {
h = h * 31 + *s;
s++;
}
}
return h;
}
#endif /* _GENERIC_HASH_H */