/usr/include/hphp/util/hash.h is in hhvm-dev 3.21.0+dfsg-2ubuntu2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 | /*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#ifndef incl_HPHP_HASH_H_
#define incl_HPHP_HASH_H_
#include <stdint.h>
#include <cstring>
#include "hphp/util/portability.h"
#ifndef FACEBOOK
# include "hphp/util/hphp-config.h"
#endif
#if defined(__x86_64__) && !defined(_MSC_VER)
# if (!defined USE_HWCRC)
# define USE_HWCRC
# endif
#elif defined __aarch64__ && defined ENABLE_AARCH64_CRC
# if (!defined USE_HWCRC)
# define USE_HWCRC
# endif
#else
# undef USE_HWCRC
#endif
// Killswitch
#if NO_HWCRC
# undef USE_HWCRC
#endif
namespace HPHP {
bool IsHWHashSupported();
///////////////////////////////////////////////////////////////////////////////
using strhash_t = int32_t;
using inthash_t = int32_t;
constexpr strhash_t STRHASH_MASK = 0x7fffffff;
constexpr strhash_t STRHASH_MSB = 0x80000000;
inline size_t hash_int64_fallback(int64_t key) {
// "64 bit Mix Functions", from Thomas Wang's "Integer Hash Function."
// http://www.concentric.net/~ttwang/tech/inthash.htm
key = (~key) + (key << 21); // key = (key << 21) - key - 1;
key = key ^ ((unsigned long long)key >> 24);
key = (key + (key << 3)) + (key << 8); // key * 265
key = key ^ ((unsigned long long)key >> 14);
key = (key + (key << 2)) + (key << 4); // key * 21
key = key ^ ((unsigned long long)key >> 28);
return static_cast<size_t>(static_cast<uint32_t>(key));
}
ALWAYS_INLINE size_t hash_int64(int64_t k) {
#if defined(USE_HWCRC) && defined(__SSE4_2__)
size_t h = 0;
__asm("crc32q %1, %0\n" : "+r"(h) : "rm"(k));
return h;
#elif defined(USE_HWCRC) && defined(ENABLE_AARCH64_CRC)
size_t res;
__asm("crc32cx %w0, wzr, %x1\n" : "=r"(res) : "r"(k));
return res;
#else
return hash_int64_fallback(k);
#endif
}
inline size_t hash_int64_pair(int64_t k1, int64_t k2) {
#if defined(USE_HWCRC) && defined(__SSE4_2__)
// crc32 is commutative, so we need to perturb k1 so that (k1, k2) hashes
// differently from (k2, k1).
k1 += k1;
__asm("crc32q %1, %0\n" : "+r" (k1) : "rm"(k2));
return k1;
#elif defined(USE_HWCRC) && defined(ENABLE_AARCH64_CRC)
size_t res;
k1 += k1;
__asm("crc32cx %w0, %w1, %x2\n" : "=r"(res) : "r"(k2), "r"(k1));
return res;
#else
return (hash_int64(k1) << 1) ^ hash_int64(k2);
#endif
}
namespace MurmurHash3 {
///////////////////////////////////////////////////////////////////////////////
// The following code is based on MurmurHash3:
// http://code.google.com/p/smhasher/wiki/MurmurHash3
//
// The case-insensitive version converts lowercase characters to uppercase
// under the assumption that character data are 7-bit ASCII. This should work
// as identifiers usually only contain alphanumeric characters and the
// underscore. Although PHP allows higher ASCII characters (> 127) in an
// identifier, they should be very rare, and do not change the correctness.
#define ROTL64(x,y) rotl64(x,y)
#define BIG_CONSTANT(x) (x##LLU)
ALWAYS_INLINE uint64_t rotl64(uint64_t x, int8_t r) {
return (x << r) | (x >> (64 - r));
}
template <bool caseSensitive>
ALWAYS_INLINE uint64_t getblock64(const uint64_t *p, int i) {
uint64_t block = p[i];
if (!caseSensitive) {
block &= 0xdfdfdfdfdfdfdfdfLLU; // a-z => A-Z
}
return block;
}
template <bool caseSensitive>
ALWAYS_INLINE uint8_t getblock8(const uint8_t *p, int i) {
uint8_t block = p[i];
if (!caseSensitive) {
block &= 0xdfU; // a-z => A-Z
}
return block;
}
//-----------------------------------------------------------------------------
// Finalization mix - force all bits of a hash block to avalanche
ALWAYS_INLINE uint64_t fmix64(uint64_t k) {
k ^= k >> 33;
k *= BIG_CONSTANT(0xff51afd7ed558ccd);
k ^= k >> 33;
k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
k ^= k >> 33;
return k;
}
// Optimized for 64-bit architectures. MurmurHash3 also implements a 128-bit
// hash that is optimized for 32-bit architectures (omitted here).
template <bool caseSensitive>
ALWAYS_INLINE void hash128(const void *key, size_t len, uint64_t seed,
uint64_t out[2]) {
const uint8_t *data = (const uint8_t *)key;
const size_t nblocks = len / 16;
uint64_t h1 = seed;
uint64_t h2 = seed;
const uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5);
const uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f);
//----------
// body
const uint64_t *blocks = (const uint64_t *)(data);
for(size_t i = 0; i < nblocks; i++)
{
uint64_t k1 = getblock64<caseSensitive>(blocks,i*2+0);
uint64_t k2 = getblock64<caseSensitive>(blocks,i*2+1);
k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;
k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
}
//----------
// tail
const uint8_t *tail = (const uint8_t*)(data + nblocks*16);
uint64_t k1 = 0;
uint64_t k2 = 0;
switch(len & 15)
{
case 15: k2 ^= uint64_t(getblock8<caseSensitive>(tail, 14)) << 48;
case 14: k2 ^= uint64_t(getblock8<caseSensitive>(tail, 13)) << 40;
case 13: k2 ^= uint64_t(getblock8<caseSensitive>(tail, 12)) << 32;
case 12: k2 ^= uint64_t(getblock8<caseSensitive>(tail, 11)) << 24;
case 11: k2 ^= uint64_t(getblock8<caseSensitive>(tail, 10)) << 16;
case 10: k2 ^= uint64_t(getblock8<caseSensitive>(tail, 9)) << 8;
case 9: k2 ^= uint64_t(getblock8<caseSensitive>(tail, 8)) << 0;
k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
case 8: k1 ^= uint64_t(getblock8<caseSensitive>(tail, 7)) << 56;
case 7: k1 ^= uint64_t(getblock8<caseSensitive>(tail, 6)) << 48;
case 6: k1 ^= uint64_t(getblock8<caseSensitive>(tail, 5)) << 40;
case 5: k1 ^= uint64_t(getblock8<caseSensitive>(tail, 4)) << 32;
case 4: k1 ^= uint64_t(getblock8<caseSensitive>(tail, 3)) << 24;
case 3: k1 ^= uint64_t(getblock8<caseSensitive>(tail, 2)) << 16;
case 2: k1 ^= uint64_t(getblock8<caseSensitive>(tail, 1)) << 8;
case 1: k1 ^= uint64_t(getblock8<caseSensitive>(tail, 0)) << 0;
k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
};
//----------
// finalization
h1 ^= len; h2 ^= len;
h1 += h2;
h2 += h1;
h1 = fmix64(h1);
h2 = fmix64(h2);
h1 += h2;
h2 += h1;
((uint64_t*)out)[0] = h1;
((uint64_t*)out)[1] = h2;
}
#undef ROTL64
#undef BIG_CONSTANT
///////////////////////////////////////////////////////////////////////////////
} // namespace MurmurHash3
// Four functions for hashing: hash_string_(cs|i)(_unsafe)?.
// cs: case-sensitive;
// i: case-insensitive;
// unsafe: safe for strings aligned at 8-byte boundary;
#if defined USE_HWCRC && (defined __SSE4_2__ || defined ENABLE_AARCH64_CRC)
// We will surely use CRC32, these are implemented directly in hash-crc-*.S
strhash_t hash_string_cs_unsafe(const char *arKey, uint32_t nKeyLength);
strhash_t hash_string_i_unsafe(const char *arKey, uint32_t nKeyLength);
strhash_t hash_string_cs(const char *arKey, uint32_t nKeyLength);
strhash_t hash_string_i(const char *arKey, uint32_t nKeyLength);
#else
strhash_t hash_string_cs_fallback(const char*, uint32_t);
strhash_t hash_string_i_fallback(const char*, uint32_t);
// We may need to do CPUID checks in the fallback versions, only when we are not
// sure CRC hash is used.
inline strhash_t hash_string_cs(const char *arKey, uint32_t nKeyLength) {
return hash_string_cs_fallback(arKey, nKeyLength);
}
inline
strhash_t hash_string_cs_unsafe(const char *arKey, uint32_t nKeyLength) {
return hash_string_cs_fallback(arKey, nKeyLength);
}
inline strhash_t hash_string_i(const char *arKey, uint32_t nKeyLength) {
return hash_string_i_fallback(arKey, nKeyLength);
}
inline
strhash_t hash_string_i_unsafe(const char *arKey, uint32_t nKeyLength) {
return hash_string_i_fallback(arKey, nKeyLength);
}
#endif
// This function returns true and sets the res parameter if arKey
// is a non-empty string that matches one of the following conditions:
// 1) The string is "0".
// 2) The string starts with a non-zero digit, followed by at most
// 18 more digits, and is less than or equal to 2^63 - 1.
// 3) The string starts with a negative sign, followed by a non-zero
// digit, followed by at most 18 more digits, and is greater than
// or equal to -2^63.
inline bool is_strictly_integer(const char* arKey, size_t nKeyLength,
int64_t& res) {
if ((unsigned char)(arKey[0] - '-') > ('9' - '-'))
return false;
if (nKeyLength <= 19 ||
(arKey[0] == '-' && nKeyLength == 20)) {
unsigned long long num = 0;
bool neg = false;
unsigned i = 0;
if (arKey[0] == '-') {
neg = true;
i = 1;
// The string "-" is NOT strictly an integer
if (nKeyLength == 1)
return false;
// A string that starts with "-0" is NOT strictly an integer
if (arKey[1] == '0')
return false;
} else if (arKey[0] == '0') {
// The string "0" is strictly an integer
if (nKeyLength == 1) {
res = 0;
return true;
}
// A string that starts with "0" followed by at least one digit
// is NOT strictly an integer
return false;
}
bool good = true;
for (; i < nKeyLength; ++i) {
if (arKey[i] >= '0' && arKey[i] <= '9') {
num = 10*num + (arKey[i] - '0');
}
else {
good = false;
break;
}
}
if (good) {
if (num <= 0x7FFFFFFFFFFFFFFFULL ||
(neg && num == 0x8000000000000000ULL)) {
res = neg ? 0 - num : (long long)num;
return true;
}
}
}
return false;
}
struct StringData;
///////////////////////////////////////////////////////////////////////////////
}
#if defined(USE_HWCRC) && !defined(__SSE4_2__) && !defined(_MSC_VER)
// The following functions are implemented in ASM directly for x86_64 and ARM
extern "C" {
HPHP::strhash_t hash_string_cs_crc(const char*, uint32_t);
HPHP::strhash_t hash_string_i_crc(const char*, uint32_t);
HPHP::strhash_t hash_string_cs_unaligned_crc(const char*, uint32_t);
HPHP::strhash_t hash_string_i_unaligned_crc(const char*, uint32_t);
}
#endif
#endif // incl_HPHP_HASH_H_
|