2017-08-23 00:36:49 +02:00
|
|
|
/*
|
|
|
|
* Utilities for working with hash values.
|
|
|
|
*
|
2024-01-04 02:49:05 +01:00
|
|
|
* Portions Copyright (c) 2017-2024, PostgreSQL Global Development Group
|
2017-08-23 00:36:49 +02:00
|
|
|
*/
|
|
|
|
|
2020-02-27 04:55:41 +01:00
|
|
|
#ifndef HASHFN_H
|
|
|
|
#define HASHFN_H
|
2017-08-23 00:36:49 +02:00
|
|
|
|
2019-03-11 17:17:50 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Rotate the high 32 bits and the low 32 bits separately. The standard
|
|
|
|
* hash function sometimes rotates the low 32 bits by one bit when
|
|
|
|
* combining elements. We want extended hash functions to be compatible with
|
|
|
|
* that algorithm when the seed is 0, so we can't just do a normal rotation.
|
|
|
|
* This works, though.
|
|
|
|
*/
|
|
|
|
#define ROTATE_HIGH_AND_LOW_32BITS(v) \
|
|
|
|
((((v) << 1) & UINT64CONST(0xfffffffefffffffe)) | \
|
|
|
|
(((v) >> 31) & UINT64CONST(0x100000001)))
|
|
|
|
|
|
|
|
|
Adapt hashfn.c and hashutils.h for frontend use.
hash_any() and its various variants are defined to return Datum,
which is a backend-only concept, but the underlying functions
actually want to return uint32 and uint64, and only return Datum
because it's convenient for callers who are using them to
implement a hash function for some SQL datatype.
However, changing these functions to return uint32 and uint64
seems like it might lead to programming errors or back-patching
difficulties, both because they are widely used and because
failure to use UInt{32,64}GetDatum() might not provoke a
compilation error. Instead, rename the existing functions as
well as changing the return type, and add static inline wrappers
for those callers that need the previous behavior.
Although this commit adapts hashutils.h and hashfn.c so that they
can be compiled as frontend code, it does not actually do
anything that would cause them to be so compiled. That is left
for another commit.
Patch by me, reviewed by Suraj Kharage and Mark Dilger.
Discussion: http://postgr.es/m/CA+TgmoaRiG4TXND8QuM6JXFRkM_1wL2ZNhzaUKsuec9-4yrkgw@mail.gmail.com
2020-02-24 12:57:15 +01:00
|
|
|
extern uint32 hash_bytes(const unsigned char *k, int keylen);
|
|
|
|
extern uint64 hash_bytes_extended(const unsigned char *k,
|
|
|
|
int keylen, uint64 seed);
|
|
|
|
extern uint32 hash_bytes_uint32(uint32 k);
|
|
|
|
extern uint64 hash_bytes_uint32_extended(uint32 k, uint64 seed);
|
|
|
|
|
|
|
|
#ifndef FRONTEND
|
|
|
|
static inline Datum
|
|
|
|
hash_any(const unsigned char *k, int keylen)
|
|
|
|
{
|
|
|
|
return UInt32GetDatum(hash_bytes(k, keylen));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline Datum
|
|
|
|
hash_any_extended(const unsigned char *k, int keylen, uint64 seed)
|
|
|
|
{
|
|
|
|
return UInt64GetDatum(hash_bytes_extended(k, keylen, seed));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline Datum
|
|
|
|
hash_uint32(uint32 k)
|
|
|
|
{
|
|
|
|
return UInt32GetDatum(hash_bytes_uint32(k));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline Datum
|
|
|
|
hash_uint32_extended(uint32 k, uint64 seed)
|
|
|
|
{
|
|
|
|
return UInt64GetDatum(hash_bytes_uint32_extended(k, seed));
|
|
|
|
}
|
|
|
|
#endif
|
2019-03-11 17:17:50 +01:00
|
|
|
|
2020-02-24 12:52:45 +01:00
|
|
|
extern uint32 string_hash(const void *key, Size keysize);
|
|
|
|
extern uint32 tag_hash(const void *key, Size keysize);
|
|
|
|
extern uint32 uint32_hash(const void *key, Size keysize);
|
|
|
|
|
|
|
|
#define oid_hash uint32_hash /* Remove me eventually */
|
|
|
|
|
2017-08-23 00:36:49 +02:00
|
|
|
/*
|
2017-10-29 08:11:43 +01:00
|
|
|
* Combine two 32-bit hash values, resulting in another hash value, with
|
|
|
|
* decent bit mixing.
|
2017-08-23 00:36:49 +02:00
|
|
|
*
|
|
|
|
* Similar to boost's hash_combine().
|
|
|
|
*/
|
|
|
|
static inline uint32
|
|
|
|
hash_combine(uint32 a, uint32 b)
|
|
|
|
{
|
|
|
|
a ^= b + 0x9e3779b9 + (a << 6) + (a >> 2);
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
2017-10-29 08:11:43 +01:00
|
|
|
/*
|
|
|
|
* Combine two 64-bit hash values, resulting in another hash value, using the
|
|
|
|
* same kind of technique as hash_combine(). Testing shows that this also
|
|
|
|
* produces good bit mixing.
|
|
|
|
*/
|
|
|
|
static inline uint64
|
|
|
|
hash_combine64(uint64 a, uint64 b)
|
|
|
|
{
|
|
|
|
/* 0x49a0f4dd15e5a8e3 is 64bit random data */
|
2017-11-07 19:54:36 +01:00
|
|
|
a ^= b + UINT64CONST(0x49a0f4dd15e5a8e3) + (a << 54) + (a >> 7);
|
2017-10-29 08:11:43 +01:00
|
|
|
return a;
|
|
|
|
}
|
2017-09-22 22:38:42 +02:00
|
|
|
|
|
|
|
/*
|
2017-09-30 00:52:55 +02:00
|
|
|
* Simple inline murmur hash implementation hashing a 32 bit integer, for
|
2017-09-22 22:38:42 +02:00
|
|
|
* performance.
|
|
|
|
*/
|
|
|
|
static inline uint32
|
|
|
|
murmurhash32(uint32 data)
|
|
|
|
{
|
|
|
|
uint32 h = data;
|
|
|
|
|
|
|
|
h ^= h >> 16;
|
|
|
|
h *= 0x85ebca6b;
|
|
|
|
h ^= h >> 13;
|
|
|
|
h *= 0xc2b2ae35;
|
|
|
|
h ^= h >> 16;
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
2023-11-08 12:30:52 +01:00
|
|
|
/* 64-bit variant */
|
|
|
|
static inline uint64
|
|
|
|
murmurhash64(uint64 data)
|
|
|
|
{
|
|
|
|
uint64 h = data;
|
|
|
|
|
|
|
|
h ^= h >> 33;
|
|
|
|
h *= 0xff51afd7ed558ccd;
|
|
|
|
h ^= h >> 33;
|
|
|
|
h *= 0xc4ceb9fe1a85ec53;
|
|
|
|
h ^= h >> 33;
|
|
|
|
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
2020-02-27 04:55:41 +01:00
|
|
|
#endif /* HASHFN_H */
|