/*************************************************************************
 *
 * 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 */
