OpenCAX/entry/src/main/cpp/include/opencascade/Standard_HashUtils.lxx
2026-02-19 19:05:41 +08:00

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