1*795d594fSAndroid Build Coastguard Worker /* 2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2018 The Android Open Source Project 3*795d594fSAndroid Build Coastguard Worker * 4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*795d594fSAndroid Build Coastguard Worker * 8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*795d594fSAndroid Build Coastguard Worker * 10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*795d594fSAndroid Build Coastguard Worker * limitations under the License. 15*795d594fSAndroid Build Coastguard Worker */ 16*795d594fSAndroid Build Coastguard Worker 17*795d594fSAndroid Build Coastguard Worker #ifndef ART_LIBARTBASE_BASE_DATA_HASH_H_ 18*795d594fSAndroid Build Coastguard Worker #define ART_LIBARTBASE_BASE_DATA_HASH_H_ 19*795d594fSAndroid Build Coastguard Worker 20*795d594fSAndroid Build Coastguard Worker #include <type_traits> 21*795d594fSAndroid Build Coastguard Worker 22*795d594fSAndroid Build Coastguard Worker #include "base/globals.h" 23*795d594fSAndroid Build Coastguard Worker #include "base/macros.h" 24*795d594fSAndroid Build Coastguard Worker 25*795d594fSAndroid Build Coastguard Worker namespace art { 26*795d594fSAndroid Build Coastguard Worker 27*795d594fSAndroid Build Coastguard Worker // Note: Touching this file or any #included file causes too many files to be rebuilt, so 28*795d594fSAndroid Build Coastguard Worker // we want to avoid #including any files that are not necessary. Therefore we use templates 29*795d594fSAndroid Build Coastguard Worker // (and std::enable_if<>) to avoid `#including headers for `ArrayRef<>` or `BitMemoryRegion`. 30*795d594fSAndroid Build Coastguard Worker class BitMemoryRegion; 31*795d594fSAndroid Build Coastguard Worker 32*795d594fSAndroid Build Coastguard Worker class DataHash { 33*795d594fSAndroid Build Coastguard Worker private: 34*795d594fSAndroid Build Coastguard Worker static constexpr bool kUseMurmur3Hash = true; 35*795d594fSAndroid Build Coastguard Worker 36*795d594fSAndroid Build Coastguard Worker public: 37*795d594fSAndroid Build Coastguard Worker template <class Container, 38*795d594fSAndroid Build Coastguard Worker typename = std::enable_if_t<!std::is_same_v<Container, BitMemoryRegion>>> operator()39*795d594fSAndroid Build Coastguard Worker size_t operator()(const Container& array) const { 40*795d594fSAndroid Build Coastguard Worker // Containers that provide the data() function use contiguous storage. 41*795d594fSAndroid Build Coastguard Worker const uint8_t* data = reinterpret_cast<const uint8_t*>(array.data()); 42*795d594fSAndroid Build Coastguard Worker uint32_t length_in_bytes = sizeof(typename Container::value_type) * array.size(); 43*795d594fSAndroid Build Coastguard Worker if (kUseMurmur3Hash) { 44*795d594fSAndroid Build Coastguard Worker uint32_t hash = Murmur3Start(); 45*795d594fSAndroid Build Coastguard Worker 46*795d594fSAndroid Build Coastguard Worker const size_t nblocks = length_in_bytes / 4; 47*795d594fSAndroid Build Coastguard Worker using unaligned_uint32_t __attribute__((__aligned__(1))) = uint32_t; 48*795d594fSAndroid Build Coastguard Worker const unaligned_uint32_t* blocks = reinterpret_cast<const unaligned_uint32_t*>(data); 49*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i != nblocks; ++i) { 50*795d594fSAndroid Build Coastguard Worker hash = Murmur3Update(hash, blocks[i]); 51*795d594fSAndroid Build Coastguard Worker } 52*795d594fSAndroid Build Coastguard Worker 53*795d594fSAndroid Build Coastguard Worker const uint8_t* tail = reinterpret_cast<const uint8_t*>(data + nblocks * 4); 54*795d594fSAndroid Build Coastguard Worker uint32_t last_block = 0; 55*795d594fSAndroid Build Coastguard Worker 56*795d594fSAndroid Build Coastguard Worker switch (length_in_bytes & 3) { 57*795d594fSAndroid Build Coastguard Worker case 3: 58*795d594fSAndroid Build Coastguard Worker last_block ^= tail[2] << 16; 59*795d594fSAndroid Build Coastguard Worker FALLTHROUGH_INTENDED; 60*795d594fSAndroid Build Coastguard Worker case 2: 61*795d594fSAndroid Build Coastguard Worker last_block ^= tail[1] << 8; 62*795d594fSAndroid Build Coastguard Worker FALLTHROUGH_INTENDED; 63*795d594fSAndroid Build Coastguard Worker case 1: 64*795d594fSAndroid Build Coastguard Worker last_block ^= tail[0]; 65*795d594fSAndroid Build Coastguard Worker hash = Murmur3UpdatePartial(hash, last_block); 66*795d594fSAndroid Build Coastguard Worker } 67*795d594fSAndroid Build Coastguard Worker 68*795d594fSAndroid Build Coastguard Worker hash = Murmur3Finish(hash, length_in_bytes); 69*795d594fSAndroid Build Coastguard Worker return hash; 70*795d594fSAndroid Build Coastguard Worker } else { 71*795d594fSAndroid Build Coastguard Worker return HashBytes(data, length_in_bytes); 72*795d594fSAndroid Build Coastguard Worker } 73*795d594fSAndroid Build Coastguard Worker } 74*795d594fSAndroid Build Coastguard Worker 75*795d594fSAndroid Build Coastguard Worker // Hash bytes using a relatively fast hash. HashBytes(const uint8_t * data,size_t length_in_bytes)76*795d594fSAndroid Build Coastguard Worker static inline size_t HashBytes(const uint8_t* data, size_t length_in_bytes) { 77*795d594fSAndroid Build Coastguard Worker size_t hash = HashBytesStart(); 78*795d594fSAndroid Build Coastguard Worker for (uint32_t i = 0; i != length_in_bytes; ++i) { 79*795d594fSAndroid Build Coastguard Worker hash = HashBytesUpdate(hash, data[i]); 80*795d594fSAndroid Build Coastguard Worker } 81*795d594fSAndroid Build Coastguard Worker return HashBytesFinish(hash); 82*795d594fSAndroid Build Coastguard Worker } 83*795d594fSAndroid Build Coastguard Worker 84*795d594fSAndroid Build Coastguard Worker template <typename BMR, 85*795d594fSAndroid Build Coastguard Worker typename = std::enable_if_t<std::is_same_v<BMR, BitMemoryRegion>>> operator()86*795d594fSAndroid Build Coastguard Worker size_t operator()(BMR region) const { 87*795d594fSAndroid Build Coastguard Worker if (kUseMurmur3Hash) { 88*795d594fSAndroid Build Coastguard Worker size_t num_full_blocks = region.size_in_bits() / kMurmur3BlockBits; 89*795d594fSAndroid Build Coastguard Worker size_t num_end_bits = region.size_in_bits() % kMurmur3BlockBits; 90*795d594fSAndroid Build Coastguard Worker size_t hash = Murmur3Start(); 91*795d594fSAndroid Build Coastguard Worker for (uint32_t i = 0; i != num_full_blocks; ++i) { 92*795d594fSAndroid Build Coastguard Worker uint32_t block = region.LoadBits(i * kMurmur3BlockBits, kMurmur3BlockBits); 93*795d594fSAndroid Build Coastguard Worker hash = Murmur3Update(hash, block); 94*795d594fSAndroid Build Coastguard Worker } 95*795d594fSAndroid Build Coastguard Worker if (num_end_bits != 0u) { 96*795d594fSAndroid Build Coastguard Worker uint32_t end_bits = region.LoadBits(num_full_blocks * kMurmur3BlockBits, num_end_bits); 97*795d594fSAndroid Build Coastguard Worker hash = Murmur3UpdatePartial(hash, end_bits); 98*795d594fSAndroid Build Coastguard Worker } 99*795d594fSAndroid Build Coastguard Worker return HashBytesFinish(hash); 100*795d594fSAndroid Build Coastguard Worker } else { 101*795d594fSAndroid Build Coastguard Worker size_t num_full_bytes = region.size_in_bits() / kBitsPerByte; 102*795d594fSAndroid Build Coastguard Worker size_t num_end_bits = region.size_in_bits() % kBitsPerByte; 103*795d594fSAndroid Build Coastguard Worker size_t hash = HashBytesStart(); 104*795d594fSAndroid Build Coastguard Worker for (uint32_t i = 0; i != num_full_bytes; ++i) { 105*795d594fSAndroid Build Coastguard Worker uint8_t byte = region.LoadBits(i * kBitsPerByte, kBitsPerByte); 106*795d594fSAndroid Build Coastguard Worker hash = HashBytesUpdate(hash, byte); 107*795d594fSAndroid Build Coastguard Worker } 108*795d594fSAndroid Build Coastguard Worker if (num_end_bits != 0u) { 109*795d594fSAndroid Build Coastguard Worker uint32_t end_bits = region.LoadBits(num_full_bytes * kBitsPerByte, num_end_bits); 110*795d594fSAndroid Build Coastguard Worker hash = HashBytesUpdate(hash, end_bits); 111*795d594fSAndroid Build Coastguard Worker } 112*795d594fSAndroid Build Coastguard Worker return HashBytesFinish(hash); 113*795d594fSAndroid Build Coastguard Worker } 114*795d594fSAndroid Build Coastguard Worker } 115*795d594fSAndroid Build Coastguard Worker 116*795d594fSAndroid Build Coastguard Worker private: 117*795d594fSAndroid Build Coastguard Worker ALWAYS_INLINE HashBytesStart()118*795d594fSAndroid Build Coastguard Worker static constexpr size_t HashBytesStart() { 119*795d594fSAndroid Build Coastguard Worker return 0x811c9dc5; 120*795d594fSAndroid Build Coastguard Worker } 121*795d594fSAndroid Build Coastguard Worker 122*795d594fSAndroid Build Coastguard Worker ALWAYS_INLINE HashBytesUpdate(size_t hash,uint8_t value)123*795d594fSAndroid Build Coastguard Worker static constexpr size_t HashBytesUpdate(size_t hash, uint8_t value) { 124*795d594fSAndroid Build Coastguard Worker return (hash * 16777619) ^ value; 125*795d594fSAndroid Build Coastguard Worker } 126*795d594fSAndroid Build Coastguard Worker 127*795d594fSAndroid Build Coastguard Worker ALWAYS_INLINE HashBytesFinish(size_t hash)128*795d594fSAndroid Build Coastguard Worker static constexpr size_t HashBytesFinish(size_t hash) { 129*795d594fSAndroid Build Coastguard Worker hash += hash << 13; 130*795d594fSAndroid Build Coastguard Worker hash ^= hash >> 7; 131*795d594fSAndroid Build Coastguard Worker hash += hash << 3; 132*795d594fSAndroid Build Coastguard Worker hash ^= hash >> 17; 133*795d594fSAndroid Build Coastguard Worker hash += hash << 5; 134*795d594fSAndroid Build Coastguard Worker return hash; 135*795d594fSAndroid Build Coastguard Worker } 136*795d594fSAndroid Build Coastguard Worker 137*795d594fSAndroid Build Coastguard Worker static constexpr uint32_t kMurmur3Seed = 0u; 138*795d594fSAndroid Build Coastguard Worker static constexpr uint32_t kMurmur3BlockBits = 32u; 139*795d594fSAndroid Build Coastguard Worker static constexpr uint32_t kMurmur3C1 = 0xcc9e2d51; 140*795d594fSAndroid Build Coastguard Worker static constexpr uint32_t kMurmur3C2 = 0x1b873593; 141*795d594fSAndroid Build Coastguard Worker static constexpr uint32_t kMurmur3R1 = 15; 142*795d594fSAndroid Build Coastguard Worker static constexpr uint32_t kMurmur3R2 = 13; 143*795d594fSAndroid Build Coastguard Worker static constexpr uint32_t kMurmur3M = 5; 144*795d594fSAndroid Build Coastguard Worker static constexpr uint32_t kMurmur3N = 0xe6546b64; 145*795d594fSAndroid Build Coastguard Worker 146*795d594fSAndroid Build Coastguard Worker ALWAYS_INLINE Murmur3Start()147*795d594fSAndroid Build Coastguard Worker static constexpr uint32_t Murmur3Start() { 148*795d594fSAndroid Build Coastguard Worker return kMurmur3Seed; 149*795d594fSAndroid Build Coastguard Worker } 150*795d594fSAndroid Build Coastguard Worker 151*795d594fSAndroid Build Coastguard Worker ALWAYS_INLINE Murmur3Update(uint32_t hash,uint32_t block)152*795d594fSAndroid Build Coastguard Worker static constexpr uint32_t Murmur3Update(uint32_t hash, uint32_t block) { 153*795d594fSAndroid Build Coastguard Worker uint32_t k = block; 154*795d594fSAndroid Build Coastguard Worker k *= kMurmur3C1; 155*795d594fSAndroid Build Coastguard Worker k = (k << kMurmur3R1) | (k >> (32 - kMurmur3R1)); 156*795d594fSAndroid Build Coastguard Worker k *= kMurmur3C2; 157*795d594fSAndroid Build Coastguard Worker hash ^= k; 158*795d594fSAndroid Build Coastguard Worker hash = ((hash << kMurmur3R2) | (hash >> (32 - kMurmur3R2))) * kMurmur3M + kMurmur3N; 159*795d594fSAndroid Build Coastguard Worker return hash; 160*795d594fSAndroid Build Coastguard Worker } 161*795d594fSAndroid Build Coastguard Worker 162*795d594fSAndroid Build Coastguard Worker ALWAYS_INLINE Murmur3UpdatePartial(uint32_t hash,uint32_t block)163*795d594fSAndroid Build Coastguard Worker static constexpr uint32_t Murmur3UpdatePartial(uint32_t hash, uint32_t block) { 164*795d594fSAndroid Build Coastguard Worker uint32_t k = block; 165*795d594fSAndroid Build Coastguard Worker k *= kMurmur3C1; 166*795d594fSAndroid Build Coastguard Worker k = (k << kMurmur3R1) | (k >> (32 - kMurmur3R1)); 167*795d594fSAndroid Build Coastguard Worker k *= kMurmur3C2; 168*795d594fSAndroid Build Coastguard Worker hash ^= k; 169*795d594fSAndroid Build Coastguard Worker // Note: Unlike full block, the partial block does not have `hash = hash * M + N`. 170*795d594fSAndroid Build Coastguard Worker return hash; 171*795d594fSAndroid Build Coastguard Worker } 172*795d594fSAndroid Build Coastguard Worker 173*795d594fSAndroid Build Coastguard Worker ALWAYS_INLINE Murmur3Finish(uint32_t hash,uint32_t length_in_bytes)174*795d594fSAndroid Build Coastguard Worker static constexpr uint32_t Murmur3Finish(uint32_t hash, uint32_t length_in_bytes) { 175*795d594fSAndroid Build Coastguard Worker hash ^= length_in_bytes; 176*795d594fSAndroid Build Coastguard Worker hash ^= (hash >> 16); 177*795d594fSAndroid Build Coastguard Worker hash *= 0x85ebca6b; 178*795d594fSAndroid Build Coastguard Worker hash ^= (hash >> 13); 179*795d594fSAndroid Build Coastguard Worker hash *= 0xc2b2ae35; 180*795d594fSAndroid Build Coastguard Worker hash ^= (hash >> 16); 181*795d594fSAndroid Build Coastguard Worker return hash; 182*795d594fSAndroid Build Coastguard Worker } 183*795d594fSAndroid Build Coastguard Worker }; 184*795d594fSAndroid Build Coastguard Worker 185*795d594fSAndroid Build Coastguard Worker } // namespace art 186*795d594fSAndroid Build Coastguard Worker 187*795d594fSAndroid Build Coastguard Worker #endif // ART_LIBARTBASE_BASE_DATA_HASH_H_ 188