diff options
Diffstat (limited to 'lib/includes/hicn/util/hash.h')
-rw-r--r-- | lib/includes/hicn/util/hash.h | 368 |
1 files changed, 368 insertions, 0 deletions
diff --git a/lib/includes/hicn/util/hash.h b/lib/includes/hicn/util/hash.h new file mode 100644 index 000000000..8dbe0d680 --- /dev/null +++ b/lib/includes/hicn/util/hash.h @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * \file hash.h + * \brief Simple non-cryptographic hash implementation. + * + * Two helpers are provided : + * hash(buf, len) : hash a buffer <buf> of length <len> + * hash_struct(buf) : hash a buffer corresponding to an allocated struct + * + * This file consists in excerpts from Jenkins hash (public domain). + * http://www.burtleburtle.net/bob/c/lookup3.c + */ +#ifndef UTIL_HASH_H +#define UTIL_HASH_H + +#include <stdint.h> +#include <stddef.h> // size_t + +#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ + __BYTE_ORDER == __LITTLE_ENDIAN) || \ + (defined(i386) || defined(__i386__) || defined(__i486__) || \ + defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL)) +#define HASH_LITTLE_ENDIAN 1 +#define HASH_BIG_ENDIAN 0 +#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ + __BYTE_ORDER == __BIG_ENDIAN) || \ + (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel)) +#define HASH_LITTLE_ENDIAN 0 +#define HASH_BIG_ENDIAN 1 +#else +#define HASH_LITTLE_ENDIAN 0 +#define HASH_BIG_ENDIAN 0 +#endif + +#define hashsize(n) ((uint32_t) 1 << (n)) +#define hashmask(n) (hashsize (n) - 1) +#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k)))) + +#define mix(a, b, c) \ + { \ + a -= c; \ + a ^= rot (c, 4); \ + c += b; \ + b -= a; \ + b ^= rot (a, 6); \ + a += c; \ + c -= b; \ + c ^= rot (b, 8); \ + b += a; \ + a -= c; \ + a ^= rot (c, 16); \ + c += b; \ + b -= a; \ + b ^= rot (a, 19); \ + a += c; \ + c -= b; \ + c ^= rot (b, 4); \ + b += a; \ + } + +#define final(a, b, c) \ + { \ + c ^= b; \ + c -= rot (b, 14); \ + a ^= c; \ + a -= rot (c, 11); \ + b ^= a; \ + b -= rot (a, 25); \ + c ^= b; \ + c -= rot (b, 16); \ + a ^= c; \ + a -= rot (c, 4); \ + b ^= a; \ + b -= rot (a, 14); \ + c ^= b; \ + c -= rot (b, 24); \ + } + +static inline uint32_t +hashlittle (const void *key, size_t length, uint32_t initval) +{ + uint32_t a, b, c; /* internal state */ + union + { + const void *ptr; + size_t i; + } u; /* needed for Mac Powerbook G4 */ + + /* Set up the internal state */ + a = b = c = 0xdeadbeef + ((uint32_t) length) + initval; + + u.ptr = key; + if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) + { + const uint32_t *k = (const uint32_t *) key; /* read 32-bit chunks */ + + /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) + */ + while (length > 12) + { + a += k[0]; + b += k[1]; + c += k[2]; + mix (a, b, c); + length -= 12; + k += 3; + } + + /*----------------------------- handle the last (probably partial) + * block */ + /* + * "k[2]&0xffffff" actually reads beyond the end of the string, but + * then masks off the part it's not allowed to read. Because the + * string is aligned, the masked-off tail is in the same word as the + * rest of the string. Every machine with memory protection I've seen + * does it on word boundaries, so is OK with this. But VALGRIND will + * still catch it and complain. The masking trick does make the hash + * noticably faster for short strings (like English words). + */ +#ifndef VALGRIND + + switch (length) + { + case 12: + c += k[2]; + b += k[1]; + a += k[0]; + break; + case 11: + c += k[2] & 0xffffff; + b += k[1]; + a += k[0]; + break; + case 10: + c += k[2] & 0xffff; + b += k[1]; + a += k[0]; + break; + case 9: + c += k[2] & 0xff; + b += k[1]; + a += k[0]; + break; + case 8: + b += k[1]; + a += k[0]; + break; + case 7: + b += k[1] & 0xffffff; + a += k[0]; + break; + case 6: + b += k[1] & 0xffff; + a += k[0]; + break; + case 5: + b += k[1] & 0xff; + a += k[0]; + break; + case 4: + a += k[0]; + break; + case 3: + a += k[0] & 0xffffff; + break; + case 2: + a += k[0] & 0xffff; + break; + case 1: + a += k[0] & 0xff; + break; + case 0: + return c; /* zero length strings require no mixing */ + } + +#else /* make valgrind happy */ + + k8 = (const uint8_t *) k; + switch (length) + { + case 12: + c += k[2]; + b += k[1]; + a += k[0]; + break; + case 11: + c += ((uint32_t) k8[10]) << 16; /* fall through */ + case 10: + c += ((uint32_t) k8[9]) << 8; /* fall through */ + case 9: + c += k8[8]; /* fall through */ + case 8: + b += k[1]; + a += k[0]; + break; + case 7: + b += ((uint32_t) k8[6]) << 16; /* fall through */ + case 6: + b += ((uint32_t) k8[5]) << 8; /* fall through */ + case 5: + b += k8[4]; /* fall through */ + case 4: + a += k[0]; + break; + case 3: + a += ((uint32_t) k8[2]) << 16; /* fall through */ + case 2: + a += ((uint32_t) k8[1]) << 8; /* fall through */ + case 1: + a += k8[0]; + break; + case 0: + return c; + } + +#endif /* !valgrind */ + } + else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) + { + const uint16_t *k = (const uint16_t *) key; /* read 16-bit chunks */ + const uint8_t *k8; + + /*--------------- all but last block: aligned reads and different mixing + */ + while (length > 12) + { + a += k[0] + (((uint32_t) k[1]) << 16); + b += k[2] + (((uint32_t) k[3]) << 16); + c += k[4] + (((uint32_t) k[5]) << 16); + mix (a, b, c); + length -= 12; + k += 6; + } + + /*----------------------------- handle the last (probably partial) block + */ + k8 = (const uint8_t *) k; + switch (length) + { + case 12: + c += k[4] + (((uint32_t) k[5]) << 16); + b += k[2] + (((uint32_t) k[3]) << 16); + a += k[0] + (((uint32_t) k[1]) << 16); + break; + case 11: + c += ((uint32_t) k8[10]) << 16; /* fall through */ + case 10: + c += k[4]; + b += k[2] + (((uint32_t) k[3]) << 16); + a += k[0] + (((uint32_t) k[1]) << 16); + break; + case 9: + c += k8[8]; /* fall through */ + case 8: + b += k[2] + (((uint32_t) k[3]) << 16); + a += k[0] + (((uint32_t) k[1]) << 16); + break; + case 7: + b += ((uint32_t) k8[6]) << 16; /* fall through */ + case 6: + b += k[2]; + a += k[0] + (((uint32_t) k[1]) << 16); + break; + case 5: + b += k8[4]; /* fall through */ + case 4: + a += k[0] + (((uint32_t) k[1]) << 16); + break; + case 3: + a += ((uint32_t) k8[2]) << 16; /* fall through */ + case 2: + a += k[0]; + break; + case 1: + a += k8[0]; + break; + case 0: + return c; /* zero length requires no mixing */ + } + } + else + { /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *) key; + + /*--------------- all but the last block: affect some 32 bits of (a,b,c) + */ + while (length > 12) + { + a += k[0]; + a += ((uint32_t) k[1]) << 8; + a += ((uint32_t) k[2]) << 16; + a += ((uint32_t) k[3]) << 24; + b += k[4]; + b += ((uint32_t) k[5]) << 8; + b += ((uint32_t) k[6]) << 16; + b += ((uint32_t) k[7]) << 24; + c += k[8]; + c += ((uint32_t) k[9]) << 8; + c += ((uint32_t) k[10]) << 16; + c += ((uint32_t) k[11]) << 24; + mix (a, b, c); + length -= 12; + k += 12; + } + + /*-------------------------------- last block: affect all 32 bits of (c) + */ + switch (length) /* all the case statements fall through */ + { + case 12: + c += ((uint32_t) k[11]) << 24; + case 11: + c += ((uint32_t) k[10]) << 16; + case 10: + c += ((uint32_t) k[9]) << 8; + case 9: + c += k[8]; + case 8: + b += ((uint32_t) k[7]) << 24; + case 7: + b += ((uint32_t) k[6]) << 16; + case 6: + b += ((uint32_t) k[5]) << 8; + case 5: + b += k[4]; + case 4: + a += ((uint32_t) k[3]) << 24; + case 3: + a += ((uint32_t) k[2]) << 16; + case 2: + a += ((uint32_t) k[1]) << 8; + case 1: + a += k[0]; + break; + case 0: + return c; + } + } + + final (a, b, c); + return c; +} + +/* Helpers */ + +#define HASH_INITVAL 1 +//#define hash(buf, len) (hash_t)hashlittle(buf, len, HASH_INITVAL) +#define hash(buf, len) hashlittle (buf, len, HASH_INITVAL) +#define hash_struct(buf) hash (buf, sizeof (*buf)) + +#define str_hash(str) (hash (str, strlen (str))) +#define str_hash_eq(a, b) (str_hash (b) - str_hash (a)) + +#endif /* UTIL_JENKINS_HASH_H */ |