/usr/include/hphp/util/hash.h is in hhvm-dev 3.11.1+dfsg-1ubuntu1.
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 | /*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2015 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"
#if defined __x86_64__
# if (!defined USE_SSECRC)
# define USE_SSECRC
# endif
#else
# undef USE_SSECRC
#endif
// Killswitch
#if NO_SSECRC
# undef USE_SSECRC
#endif
namespace HPHP {
bool IsSSEHashSupported();
///////////////////////////////////////////////////////////////////////////////
typedef int32_t strhash_t;
const strhash_t STRHASH_MASK = 0x7fffffff;
const strhash_t STRHASH_MSB = 0x80000000;
inline long long hash_int64(long long 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);
key = key + (key << 31);
return key < 0 ? -key : key;
}
inline long long hash_int64_pair(long long k1, long long k2) {
// Shift the first key, so (a,b) hashes somewhere other than (b,a)
return (hash_int64(k1) << 1) ^ hash_int64(k2);
}
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;
// Fallback versions uses CRC hash when supported, and use MurmurHash otherwise.
strhash_t hash_string_cs_fallback(const char *arKey, uint32_t nKeyLength);
strhash_t hash_string_i_fallback(const char *arKey, uint32_t nKeyLength);
#if FACEBOOK && defined USE_SSECRC
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
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
inline strhash_t hash_string(const char *arKey, uint32_t nKeyLength) {
return hash_string_i(arKey, nKeyLength);
}
inline strhash_t hash_string_unsafe(const char *arKey, uint32_t nKeyLength) {
return hash_string_i_unsafe(arKey, nKeyLength);
}
/**
* We probably should get rid of this, so to detect code generation errors,
* where a binary string is treated as a NULL-terminated literal. Do we ever
* allow binary strings as array keys or symbol names?
*/
inline strhash_t hash_string(const char *arKey) {
return hash_string(arKey, strlen(arKey));
}
inline strhash_t hash_string_i(const char *arKey) {
return hash_string_i(arKey, strlen(arKey));
}
// 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;
}
class StringData;
///////////////////////////////////////////////////////////////////////////////
}
#ifdef USE_SSECRC
// The following functions are implemented in ASM directly for x86_64.
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);
HPHP::strhash_t g_hashHelper_crc(const HPHP::StringData*);
}
#endif
#endif // incl_HPHP_HASH_H_
|