/* * xxHash - Fast Hash algorithm * Copyright (C) 2012-2020 Yann Collet * Copyright (C) 2019-2020 Devin Hussey (easyaspi314) * * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * You can contact the author at : * - xxHash homepage: http://www.xxhash.com * - xxHash source repository : https://github.com/Cyan4973/xxHash */ /* This is a compact, 100% standalone reference XXH32 single-run implementation. * Instead of focusing on performance hacks, this focuses on cleanliness, * conformance, portability and simplicity. * * This file aims to be 100% compatible with C90/C++98, with the additional * requirement of stdint.h. No library functions are used. */ #include /* size_t, NULL */ #include /* uint8_t, uint32_t */ #include "xxhash32.h" static uint32_t const PRIME32_1 = 0x9E3779B1U; /* 0b10011110001101110111100110110001 */ static uint32_t const PRIME32_2 = 0x85EBCA77U; /* 0b10000101111010111100101001110111 */ static uint32_t const PRIME32_3 = 0xC2B2AE3DU; /* 0b11000010101100101010111000111101 */ static uint32_t const PRIME32_4 = 0x27D4EB2FU; /* 0b00100111110101001110101100101111 */ static uint32_t const PRIME32_5 = 0x165667B1U; /* 0b00010110010101100110011110110001 */ /* Rotates value left by amt. */ static uint32_t XXH_rotl32(uint32_t const value, uint32_t const amt) { return (value << (amt % 32)) | (value >> (32 - (amt % 32))); } /* Portably reads a 32-bit little endian integer from data at the given offset. */ static uint32_t XXH_read32(uint8_t const *const data, size_t const offset) { return (uint32_t) data[offset + 0] | ((uint32_t) data[offset + 1] << 8) | ((uint32_t) data[offset + 2] << 16) | ((uint32_t) data[offset + 3] << 24); } /* Mixes input into acc. */ static uint32_t XXH32_round(uint32_t acc, uint32_t const input) { acc += input * PRIME32_2; acc = XXH_rotl32(acc, 13); acc *= PRIME32_1; return acc; } /* Mixes all bits to finalize the hash. */ static uint32_t XXH32_avalanche(uint32_t hash) { hash ^= hash >> 15; hash *= PRIME32_2; hash ^= hash >> 13; hash *= PRIME32_3; hash ^= hash >> 16; return hash; } /* The XXH32 hash function. * input: The data to hash. * length: The length of input. It is undefined behavior to have length larger than the * capacity of input. * seed: A 32-bit value to seed the hash with. * returns: The 32-bit calculated hash value. */ uint32_t XXH32(void const *const input, size_t const length, uint32_t const seed) { uint8_t const *const data = (uint8_t const *) input; uint32_t hash; size_t remaining = length; size_t offset = 0; /* Don't dereference a null pointer. The reference implementation notably doesn't * check for this by default. */ if (input == NULL) { return XXH32_avalanche(seed + PRIME32_5); } if (remaining >= 16) { /* Initialize our accumulators */ uint32_t acc1 = seed + PRIME32_1 + PRIME32_2; uint32_t acc2 = seed + PRIME32_2; uint32_t acc3 = seed + 0; uint32_t acc4 = seed - PRIME32_1; while (remaining >= 16) { acc1 = XXH32_round(acc1, XXH_read32(data, offset)); offset += 4; acc2 = XXH32_round(acc2, XXH_read32(data, offset)); offset += 4; acc3 = XXH32_round(acc3, XXH_read32(data, offset)); offset += 4; acc4 = XXH32_round(acc4, XXH_read32(data, offset)); offset += 4; remaining -= 16; } hash = XXH_rotl32(acc1, 1) + XXH_rotl32(acc2, 7) + XXH_rotl32(acc3, 12) + XXH_rotl32(acc4, 18); } else { /* Not enough data for the main loop, put something in there instead. */ hash = seed + PRIME32_5; } hash += (uint32_t) length; /* Process the remaining data. */ while (remaining >= 4) { hash += XXH_read32(data, offset) * PRIME32_3; hash = XXH_rotl32(hash, 17); hash *= PRIME32_4; offset += 4; remaining -= 4; } while (remaining != 0) { hash += (uint32_t) data[offset] * PRIME32_5; hash = XXH_rotl32(hash, 11); hash *= PRIME32_1; --remaining; ++offset; } return XXH32_avalanche(hash); }