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