161 lines
4.6 KiB
Plaintext
161 lines
4.6 KiB
Plaintext
// Copyright (c) 2023 OPEN CASCADE SAS
|
|
//
|
|
// This file is part of Open CASCADE Technology software library.
|
|
//
|
|
// This library is free software; you can redistribute it and/or modify it under
|
|
// the terms of the GNU Lesser General Public License version 2.1 as published
|
|
// by the Free Software Foundation, with special exception defined in the file
|
|
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
|
|
// distribution for complete text of the license and disclaimer of any warranty.
|
|
//
|
|
// Alternatively, this file may be used under the terms of Open CASCADE
|
|
// commercial license or contractual agreement.
|
|
|
|
#include <cstring>
|
|
|
|
namespace opencascade
|
|
{
|
|
namespace MurmurHash
|
|
{
|
|
namespace MurmurHashUtils
|
|
{
|
|
inline uint64_t shift_mix(uint64_t theV)
|
|
{
|
|
return theV ^ (theV >> 47);
|
|
}
|
|
|
|
// Loads n bytes, where 1 <= n < 8.
|
|
inline uint64_t load_bytes(const char* thePnt, int theNb)
|
|
{
|
|
uint64_t aRes = 0;
|
|
--theNb;
|
|
do
|
|
aRes = (aRes << 8) + static_cast<unsigned char>(thePnt[theNb]);
|
|
while (--theNb >= 0);
|
|
return aRes;
|
|
}
|
|
|
|
template <typename T>
|
|
inline T unaligned_load(const char* thePnt)
|
|
{
|
|
T aRes;
|
|
memcpy(&aRes, thePnt, sizeof(aRes));
|
|
return aRes;
|
|
}
|
|
} // namespace MurmurHashUtils
|
|
|
|
//=======================================================================
|
|
// function : MurmurHash64A
|
|
// purpose :
|
|
//=======================================================================
|
|
inline uint64_t MurmurHash64A(const void* theKey, int theLen, uint64_t theSeed)
|
|
{
|
|
static constexpr uint64_t aMul = (((uint64_t)0xc6a4a793UL) << 32UL) + (uint64_t)0x5bd1e995UL;
|
|
const char* const aBuf = static_cast<const char*>(theKey);
|
|
|
|
// Remove the bytes not divisible by the sizeof(uint64_t). This
|
|
// allows the main loop to process the data as 64-bit integers.
|
|
const uint64_t aLenAligned = theLen & ~(uint64_t)0x7;
|
|
const char* const anEnd = aBuf + aLenAligned;
|
|
uint64_t aHash = theSeed ^ (theLen * aMul);
|
|
for (const char* aPnt = aBuf; aPnt != anEnd; aPnt += 8)
|
|
{
|
|
const uint64_t aData =
|
|
MurmurHashUtils::shift_mix(MurmurHashUtils::unaligned_load<uint64_t>(aPnt) * aMul) * aMul;
|
|
aHash ^= aData;
|
|
aHash *= aMul;
|
|
}
|
|
if ((theLen & 0x7) != 0)
|
|
{
|
|
const uint64_t data = MurmurHashUtils::load_bytes(anEnd, theLen & 0x7);
|
|
aHash ^= data;
|
|
aHash *= aMul;
|
|
}
|
|
aHash = MurmurHashUtils::shift_mix(aHash) * aMul;
|
|
aHash = MurmurHashUtils::shift_mix(aHash);
|
|
return aHash;
|
|
}
|
|
|
|
//=======================================================================
|
|
// function : MurmurHash2A
|
|
// purpose :
|
|
//=======================================================================
|
|
inline uint32_t MurmurHash2A(const void* theKey, int theLen, uint32_t theSeed)
|
|
{
|
|
const uint32_t aMul = 0x5bd1e995;
|
|
uint32_t aHash = theSeed ^ theLen;
|
|
const char* aBuf = static_cast<const char*>(theKey);
|
|
|
|
// Mix 4 bytes at a time into the hash.
|
|
while (theLen >= 4)
|
|
{
|
|
uint32_t aKey = MurmurHashUtils::unaligned_load<uint32_t>(aBuf);
|
|
aKey *= aMul;
|
|
aKey ^= aKey >> 24;
|
|
aKey *= aMul;
|
|
aHash *= aMul;
|
|
aHash ^= aKey;
|
|
aBuf += 4;
|
|
theLen -= 4;
|
|
}
|
|
|
|
uint32_t aKey;
|
|
// Handle the last few bytes of the input array.
|
|
switch (theLen)
|
|
{
|
|
case 3:
|
|
aKey = static_cast<unsigned char>(aBuf[2]);
|
|
aHash ^= aKey << 16;
|
|
Standard_FALLTHROUGH
|
|
case 2:
|
|
aKey = static_cast<unsigned char>(aBuf[1]);
|
|
aHash ^= aKey << 8;
|
|
Standard_FALLTHROUGH
|
|
case 1:
|
|
aKey = static_cast<unsigned char>(aBuf[0]);
|
|
aHash ^= aKey;
|
|
aHash *= aMul;
|
|
};
|
|
|
|
// Do a few final mixes of the hash.
|
|
aHash ^= aHash >> 13;
|
|
aHash *= aMul;
|
|
aHash ^= aHash >> 15;
|
|
return aHash;
|
|
}
|
|
} // namespace MurmurHash
|
|
|
|
namespace FNVHash
|
|
{
|
|
//=======================================================================
|
|
// function : FNVHash1A
|
|
// purpose :
|
|
//=======================================================================
|
|
inline uint32_t FNVHash1A(const void* theKey, int theLen, uint32_t theSeed)
|
|
{
|
|
const char* cptr = static_cast<const char*>(theKey);
|
|
for (; theLen; --theLen)
|
|
{
|
|
theSeed ^= static_cast<uint32_t>(*cptr++);
|
|
theSeed *= static_cast<uint32_t>(16777619UL);
|
|
}
|
|
return theSeed;
|
|
}
|
|
|
|
//=======================================================================
|
|
// function : FNVHash64A
|
|
// purpose :
|
|
//=======================================================================
|
|
inline uint64_t FNVHash64A(const void* theKey, int theLen, uint64_t theSeed)
|
|
{
|
|
const char* cptr = static_cast<const char*>(theKey);
|
|
for (; theLen; --theLen)
|
|
{
|
|
theSeed ^= static_cast<uint64_t>(*cptr++);
|
|
theSeed *= static_cast<uint64_t>(1099511628211ULL);
|
|
}
|
|
return theSeed;
|
|
}
|
|
} // namespace FNVHash
|
|
} // namespace opencascade
|