Files
test/source/blender/blenlib/intern/hash_mm2a.c
Campbell Barton e955c94ed3 License Headers: Set copyright to "Blender Authors", add AUTHORS
Listing the "Blender Foundation" as copyright holder implied the Blender
Foundation holds copyright to files which may include work from many
developers.

While keeping copyright on headers makes sense for isolated libraries,
Blender's own code may be refactored or moved between files in a way
that makes the per file copyright holders less meaningful.

Copyright references to the "Blender Foundation" have been replaced with
"Blender Authors", with the exception of `./extern/` since these this
contains libraries which are more isolated, any changed to license
headers there can be handled on a case-by-case basis.

Some directories in `./intern/` have also been excluded:

- `./intern/cycles/` it's own `AUTHORS` file is planned.
- `./intern/opensubdiv/`.

An "AUTHORS" file has been added, using the chromium projects authors
file as a template.

Design task: #110784

Ref !110783.
2023-08-16 00:20:26 +10:00

130 lines
2.7 KiB
C

/* SPDX-FileCopyrightText: 2014 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup bli
*
* Functions to compute Murmur2A hash key.
*
* A very fast hash generating int32 result, with few collisions and good repartition.
*
* See also:
* reference implementation:
* - https://smhasher.googlecode.com/svn-history/r130/trunk/MurmurHash2.cpp
* - http://programmers.stackexchange.com/questions/49550
*
* \warning Do not store that hash in files or such, it is not endian-agnostic,
* so you should only use it for temporary data.
*/
#include "BLI_compiler_attrs.h"
#include "BLI_hash_mm2a.h" /* own include */
/* Helpers. */
#define MM2A_M 0x5bd1e995
#define MM2A_MIX(h, k) \
{ \
(k) *= MM2A_M; \
(k) ^= (k) >> 24; \
(k) *= MM2A_M; \
(h) = ((h)*MM2A_M) ^ (k); \
} \
(void)0
#define MM2A_MIX_FINALIZE(h) \
{ \
(h) ^= (h) >> 13; \
(h) *= MM2A_M; \
(h) ^= (h) >> 15; \
} \
(void)0
static void mm2a_mix_tail(BLI_HashMurmur2A *mm2, const uchar **data, size_t *len)
{
while (*len && ((*len < 4) || mm2->count)) {
mm2->tail |= (uint32_t)(**data) << (mm2->count * 8);
mm2->count++;
(*len)--;
(*data)++;
if (mm2->count == 4) {
MM2A_MIX(mm2->hash, mm2->tail);
mm2->tail = 0;
mm2->count = 0;
}
}
}
void BLI_hash_mm2a_init(BLI_HashMurmur2A *mm2, uint32_t seed)
{
mm2->hash = seed;
mm2->tail = 0;
mm2->count = 0;
mm2->size = 0;
}
void BLI_hash_mm2a_add(BLI_HashMurmur2A *mm2, const uchar *data, size_t len)
{
mm2->size += (uint32_t)len;
mm2a_mix_tail(mm2, &data, &len);
for (; len >= 4; data += 4, len -= 4) {
uint32_t k = *(const uint32_t *)data;
MM2A_MIX(mm2->hash, k);
}
mm2a_mix_tail(mm2, &data, &len);
}
void BLI_hash_mm2a_add_int(BLI_HashMurmur2A *mm2, int data)
{
BLI_hash_mm2a_add(mm2, (const uchar *)&data, sizeof(data));
}
uint32_t BLI_hash_mm2a_end(BLI_HashMurmur2A *mm2)
{
MM2A_MIX(mm2->hash, mm2->tail);
MM2A_MIX(mm2->hash, mm2->size);
MM2A_MIX_FINALIZE(mm2->hash);
return mm2->hash;
}
uint32_t BLI_hash_mm2(const uchar *data, size_t len, uint32_t seed)
{
/* Initialize the hash to a 'random' value */
uint32_t h = seed ^ len;
/* Mix 4 bytes at a time into the hash */
for (; len >= 4; data += 4, len -= 4) {
uint32_t k = *(uint32_t *)data;
MM2A_MIX(h, k);
}
/* Handle the last few bytes of the input array */
switch (len) {
case 3:
h ^= data[2] << 16;
ATTR_FALLTHROUGH;
case 2:
h ^= data[1] << 8;
ATTR_FALLTHROUGH;
case 1:
h ^= data[0];
h *= MM2A_M;
}
/* Do a few final mixes of the hash to ensure the last few bytes are well-incorporated. */
MM2A_MIX_FINALIZE(h);
return h;
}