| /* |
| * Copyright 2023 Google LLC |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| #include "src/core/SkChecksum.h" |
| |
| #include <cstring> |
| |
| // wyhash, a fast and good hash function, from https://github.com/wangyi-fudan/wyhash |
| |
| // likely and unlikely macros |
| #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__) |
| #define _likely_(x) __builtin_expect(x, 1) |
| #define _unlikely_(x) __builtin_expect(x, 0) |
| #else |
| #define _likely_(x) (x) |
| #define _unlikely_(x) (x) |
| #endif |
| |
| // 128bit multiply function |
| static inline void _wymum(uint64_t* A, uint64_t* B) { |
| #if defined(__SIZEOF_INT128__) |
| __uint128_t r = *A; |
| r *= *B; |
| *A = (uint64_t)r; |
| *B = (uint64_t)(r >> 64); |
| #elif defined(_MSC_VER) && defined(_M_X64) |
| *A = _umul128(*A, *B, B); |
| #else |
| uint64_t ha = *A >> 32, hb = *B >> 32, la = (uint32_t)*A, lb = (uint32_t)*B, hi, lo; |
| uint64_t rh = ha * hb, rm0 = ha * lb, rm1 = hb * la, rl = la * lb, t = rl + (rm0 << 32), |
| c = t < rl; |
| lo = t + (rm1 << 32); |
| c += lo < t; |
| hi = rh + (rm0 >> 32) + (rm1 >> 32) + c; |
| *A = lo; |
| *B = hi; |
| #endif |
| } |
| |
| // multiply and xor mix function, aka MUM |
| static inline uint64_t _wymix(uint64_t A, uint64_t B) { |
| _wymum(&A, &B); |
| return A ^ B; |
| } |
| |
| // read functions |
| static inline uint64_t _wyr8(const uint8_t* p) { |
| uint64_t v; |
| memcpy(&v, p, 8); |
| return v; |
| } |
| |
| static inline uint64_t _wyr4(const uint8_t* p) { |
| uint32_t v; |
| memcpy(&v, p, 4); |
| return v; |
| } |
| |
| static inline uint64_t _wyr3(const uint8_t* p, size_t k) { |
| return (((uint64_t)p[0]) << 16) | (((uint64_t)p[k >> 1]) << 8) | p[k - 1]; |
| } |
| |
| // wyhash main function |
| static inline uint64_t wyhash(const void* key, size_t len, uint64_t seed, const uint64_t* secret) { |
| const uint8_t* p = (const uint8_t*)key; |
| seed ^= _wymix(seed ^ secret[0], secret[1]); |
| uint64_t a, b; |
| if (_likely_(len <= 16)) { |
| if (_likely_(len >= 4)) { |
| a = (_wyr4(p) << 32) | _wyr4(p + ((len >> 3) << 2)); |
| b = (_wyr4(p + len - 4) << 32) | _wyr4(p + len - 4 - ((len >> 3) << 2)); |
| } else if (_likely_(len > 0)) { |
| a = _wyr3(p, len); |
| b = 0; |
| } else |
| a = b = 0; |
| } else { |
| size_t i = len; |
| if (_unlikely_(i > 48)) { |
| uint64_t see1 = seed, see2 = seed; |
| do { |
| seed = _wymix(_wyr8(p) ^ secret[1], _wyr8(p + 8) ^ seed); |
| see1 = _wymix(_wyr8(p + 16) ^ secret[2], _wyr8(p + 24) ^ see1); |
| see2 = _wymix(_wyr8(p + 32) ^ secret[3], _wyr8(p + 40) ^ see2); |
| p += 48; |
| i -= 48; |
| } while (_likely_(i > 48)); |
| seed ^= see1 ^ see2; |
| } |
| while (_unlikely_(i > 16)) { |
| seed = _wymix(_wyr8(p) ^ secret[1], _wyr8(p + 8) ^ seed); |
| i -= 16; |
| p += 16; |
| } |
| a = _wyr8(p + i - 16); |
| b = _wyr8(p + i - 8); |
| } |
| a ^= secret[1]; |
| b ^= seed; |
| _wymum(&a, &b); |
| return _wymix(a ^ secret[0] ^ len, b ^ secret[1]); |
| } |
| |
| // the default secret parameters |
| static const uint64_t _wyp[4] = { |
| 0xa0761d6478bd642full, 0xe7037ed1a0b428dbull, 0x8ebc6af09c88c6e3ull, 0x589965cc75374cc3ull}; |
| |
| namespace SkChecksum { |
| |
| uint32_t Hash32(const void *data, size_t bytes, uint32_t seed) { |
| return static_cast<uint32_t>(wyhash(data, bytes, seed, _wyp)); |
| } |
| |
| uint64_t Hash64(const void *data, size_t bytes, uint64_t seed) { |
| return wyhash(data, bytes, seed, _wyp); |
| } |
| |
| } // namespace SkChecksum |