/** * Copyright (c) 2015 Daniel Kirchner * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * * --------------------------------------------------------------------------- * \file dnn/src/common/hash_ct.h * * \brief compile time hash for strings * * MegEngine is Licensed under the Apache License, Version 2.0 (the "License") * * Copyright (c) 2014-2020 Megvii Inc. All rights reserved. * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. * * This file has been modified by Megvii ("Megvii Modifications"). * All Megvii Modifications are Copyright (C) 2014-2019 Megvii Inc. All rights * reserved. * * --------------------------------------------------------------------------- * */ #pragma once #include namespace megdnn { /*! * \brief compile-time XX64 hash implementation * * see https://github.com/ekpyron/xxhashct/blob/master/xxh64.hpp */ class XXHash64CT { public: static constexpr uint64_t hash(const char* p, uint64_t len, uint64_t seed) { return finalize( (len >= 32 ? h32bytes(p, len, seed) : seed + PRIME5) + len, p + (len & ~0x1F), len & 0x1F); } private: static constexpr uint64_t PRIME1 = 11400714785074694791ULL; static constexpr uint64_t PRIME2 = 14029467366897019727ULL; static constexpr uint64_t PRIME3 = 1609587929392839161ULL; static constexpr uint64_t PRIME4 = 9650029242287828579ULL; static constexpr uint64_t PRIME5 = 2870177450012600261ULL; static constexpr uint64_t rotl(uint64_t x, int r) { return ((x << r) | (x >> (64 - r))); } static constexpr uint64_t mix1(const uint64_t h, const uint64_t prime, int rshift) { return (h ^ (h >> rshift)) * prime; } static constexpr uint64_t mix2(const uint64_t p, const uint64_t v = 0) { return rotl(v + p * PRIME2, 31) * PRIME1; } static constexpr uint64_t mix3(const uint64_t h, const uint64_t v) { return (h ^ mix2(v)) * PRIME1 + PRIME4; } #ifdef XXH64_BIG_ENDIAN static constexpr uint32_t endian32(const char* v) { return uint32_t(uint8_t(v[3])) | (uint32_t(uint8_t(v[2])) << 8) | (uint32_t(uint8_t(v[1])) << 16) | (uint32_t(uint8_t(v[0])) << 24); } static constexpr uint64_t endian64(const char* v) { return uint64_t(uint8_t(v[7])) | (uint64_t(uint8_t(v[6])) << 8) | (uint64_t(uint8_t(v[5])) << 16) | (uint64_t(uint8_t(v[4])) << 24) | (uint64_t(uint8_t(v[3])) << 32) | (uint64_t(uint8_t(v[2])) << 40) | (uint64_t(uint8_t(v[1])) << 48) | (uint64_t(uint8_t(v[0])) << 56); } #else static constexpr uint32_t endian32(const char* v) { return uint32_t(uint8_t(v[0])) | (uint32_t(uint8_t(v[1])) << 8) | (uint32_t(uint8_t(v[2])) << 16) | (uint32_t(uint8_t(v[3])) << 24); } static constexpr uint64_t endian64(const char* v) { return uint64_t(uint8_t(v[0])) | (uint64_t(uint8_t(v[1])) << 8) | (uint64_t(uint8_t(v[2])) << 16) | (uint64_t(uint8_t(v[3])) << 24) | (uint64_t(uint8_t(v[4])) << 32) | (uint64_t(uint8_t(v[5])) << 40) | (uint64_t(uint8_t(v[6])) << 48) | (uint64_t(uint8_t(v[7])) << 56); } #endif static constexpr uint64_t fetch64(const char* p, const uint64_t v = 0) { return mix2(endian64(p), v); } static constexpr uint64_t fetch32(const char* p) { return uint64_t(endian32(p)) * PRIME1; } static constexpr uint64_t fetch8(const char* p) { return uint8_t(*p) * PRIME5; } // clang-format off static constexpr uint64_t finalize (const uint64_t h, const char *p, uint64_t len) { return (len >= 8) ? (finalize (rotl (h ^ fetch64 (p), 27) * PRIME1 + PRIME4, p + 8, len - 8)) : ((len >= 4) ? (finalize (rotl (h ^ fetch32 (p), 23) * PRIME2 + PRIME3, p + 4, len - 4)) : ((len > 0) ? (finalize (rotl (h ^ fetch8 (p), 11) * PRIME1, p + 1, len - 1)) : (mix1 (mix1 (mix1 (h, PRIME2, 33), PRIME3, 29), 1, 32)))); } static constexpr uint64_t h32bytes (const char *p, uint64_t len, const uint64_t v1,const uint64_t v2, const uint64_t v3, const uint64_t v4) { return (len >= 32) ? h32bytes (p + 32, len - 32, fetch64 (p, v1), fetch64 (p + 8, v2), fetch64 (p + 16, v3), fetch64 (p + 24, v4)) : mix3 (mix3 (mix3 (mix3 (rotl (v1, 1) + rotl (v2, 7) + rotl (v3, 12) + rotl (v4, 18), v1), v2), v3), v4); } static constexpr uint64_t h32bytes (const char *p, uint64_t len, const uint64_t seed) { return h32bytes (p, len, seed + PRIME1 + PRIME2, seed + PRIME2, seed, seed - PRIME1); } // clang-format on }; } // namespace megdnn // vim: syntax=cpp.doxygen foldmethod=marker foldmarker=f{{{,f}}}