From ae27c7a4bc810b04daef024ff4647ee71a9547a8 Mon Sep 17 00:00:00 2001 From: Corentin Wallez Date: Mon, 7 May 2018 17:33:48 -0400 Subject: [PATCH] Move HashCombine to HashUtils and make it work better on 64bits HashCombine will be used in more than just BindGroupLayout caching so we extract it to a separate header. Add a better mixing constant for 64bit systems. --- src/backend/BindGroupLayout.cpp | 24 ++------------ src/common/CMakeLists.txt | 1 + src/common/HashUtils.h | 55 +++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 22 deletions(-) create mode 100644 src/common/HashUtils.h diff --git a/src/backend/BindGroupLayout.cpp b/src/backend/BindGroupLayout.cpp index 64d4941470..e9f6704392 100644 --- a/src/backend/BindGroupLayout.cpp +++ b/src/backend/BindGroupLayout.cpp @@ -15,39 +15,19 @@ #include "backend/BindGroupLayout.h" #include "backend/Device.h" +#include "common/HashUtils.h" #include namespace backend { namespace { - - // Workaround for Chrome's stdlib having a broken std::hash for enums and bitsets - template - typename std::enable_if::value, size_t>::type Hash(T value) { - using Integral = typename nxt::UnderlyingType::type; - return std::hash()(static_cast(value)); - } - - template - size_t Hash(const std::bitset& value) { - static_assert(N <= sizeof(unsigned long long) * 8, ""); - return std::hash()(value.to_ullong()); - } - - // TODO(cwallez@chromium.org): see if we can use boost's hash combined or some equivalent - // this currently assumes that size_t is 64 bits - void CombineHashes(size_t* h1, size_t h2) { - *h1 ^= (h2 << 7) + (h2 >> (sizeof(size_t) * 8 - 7)) + 0x304975; - } - size_t HashBindingInfo(const BindGroupLayoutBase::LayoutBindingInfo& info) { size_t hash = Hash(info.mask); for (size_t binding = 0; binding < kMaxBindingsPerGroup; ++binding) { if (info.mask[binding]) { - CombineHashes(&hash, Hash(info.visibilities[binding])); - CombineHashes(&hash, Hash(info.types[binding])); + HashCombine(&hash, info.visibilities[binding], info.types[binding]); } } diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 7eed43c19e..91e8a03f50 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -21,6 +21,7 @@ list(APPEND COMMON_SOURCES ${COMMON_DIR}/Compiler.h ${COMMON_DIR}/DynamicLib.cpp ${COMMON_DIR}/DynamicLib.h + ${COMMON_DIR}/HashUtils.h ${COMMON_DIR}/Math.cpp ${COMMON_DIR}/Math.h ${COMMON_DIR}/Platform.h diff --git a/src/common/HashUtils.h b/src/common/HashUtils.h new file mode 100644 index 0000000000..34d15982c8 --- /dev/null +++ b/src/common/HashUtils.h @@ -0,0 +1,55 @@ +// Copyright 2018 The NXT Authors +// +// 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. + +#ifndef COMMON_HASHUTILS_H_ +#define COMMON_HASHUTILS_H_ + +#include "common/Platform.h" + +#include + +// Wrapper around std::hash to make it a templated function instead of a functor. It is marginally +// nicer, and avoids adding to the std namespace to add hashing of other types. +template +size_t Hash(const T& value) { + return std::hash()(value); +} + +// When hashing sparse structures we want to iteratively build a hash value with only parts of the +// data. HashCombine "hashes" together an existing hash and hashable values. +// +// Example usage to compute the hash of a mask and values corresponding to the mask: +// +// size_t hash = Hash(mask): +// for (uint32_t i : IterateBitSet(mask)) { HashCombine(&hash, hashables[i]); } +// return hash; +template +void HashCombine(size_t* hash, const T& value) { +#if defined(NXT_PLATFORM_64_BIT) + const size_t offset = 0x9e3779b97f4a7c16; +#elif defined(NXT_PLATFORM_32_BIT) + const size_t offset = 0x9e3779b9; +#else +# error "Unsupported platform" +#endif + *hash ^= Hash(value) + offset + (*hash << 6) + (*hash >> 2); +} + +template +void HashCombine(size_t* hash, const T& value, const Args&... args) { + HashCombine(hash, value); + HashCombine(hash, args...); +} + +#endif // COMMON_HASHUTILS_H_