This is not an issue. Just for sharing my experiment. The following post demonstrates compile-time XXH32() hash calculation in C++20 and its constexpr.
But if you want to use compile-time xxHash now, please take a look at @ekpyron's excellent C++11 implementation of compile-time XXH64(). It's better than my code in many aspects.
This code demonstrates compile-time XXH32 hash calculation in C++20.
"xxHash - Extremely Fast Hash algorithm".XXH32() when you define INCLUDE_XXHASH.When hash value becomes compile-time constant:
case label, static_assert() expression, etc.if constexpr () is also useful.Since C++17/20 relaxed many restriction of constexpr, this code is a naive version of XXH32().
So my point is, it's always nice to have naive/simple version of the code for clarity and testing.
It also will encourage other developers to implmenent the algorithm in different form and language.
Code, result and disassembly at Compiler Explorer
gist version of the code for convenience
Prerequisites
g++-10)// C++20 Compile-time XXH32()
//
// g++-10 (10.2.0) g++-10 -std=c++20 -DINCLUDE_XXHASH ./cxx20_ct_xxhash.cpp
// Clang (10.0.0) clang -std=c++20 -DINCLUDE_XXHASH ./cxx20_ct_xxhash.cpp
// Visual C++ 2019 (19.28) cl /std:c++latest /DINCLUDE_XXHASH .\cxx20_ct_xxhash.cpp
//
// Result at Compiler Explorer
// https://godbolt.org/z/bGv7Mh
#include <stdio.h> // printf()
#include <stdint.h> // uint8_t, uint32_t
#include <bit> // std::rotl() ( https://en.cppreference.com/w/cpp/numeric/rotl )
// "private" utility functions
namespace compiletime_xxhash::detail {
constexpr uint32_t rotl(uint32_t v, int x) {
return std::rotl(v, x);
}
constexpr uint8_t read_u8(const char* input, int pos) {
return static_cast<uint8_t>(input[pos]);
}
constexpr uint32_t read_u32le(const char* input, int pos) {
const uint32_t b0 = read_u8(input, pos + 0);
const uint32_t b1 = read_u8(input, pos + 1);
const uint32_t b2 = read_u8(input, pos + 2);
const uint32_t b3 = read_u8(input, pos + 3);
return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24);
}
}
// "private" XXH32 functions
namespace compiletime_xxhash::detail::xxh32 {
constexpr uint32_t prime32_1 = 0x9E3779B1U;
constexpr uint32_t prime32_2 = 0x85EBCA77U;
constexpr uint32_t prime32_3 = 0xC2B2AE3DU;
constexpr uint32_t prime32_4 = 0x27D4EB2FU;
constexpr uint32_t prime32_5 = 0x165667B1U;
constexpr uint32_t xxh32_avalanche(uint32_t h32) {
h32 ^= h32 >> 15;
h32 *= prime32_2;
h32 ^= h32 >> 13;
h32 *= prime32_3;
h32 ^= h32 >> 16;
return h32;
}
constexpr uint32_t xxh32_finalize(const char* input, int inputLen, int pos, uint32_t h32) {
// XXH_PROCESS4
while((inputLen - pos) >= 4) {
h32 += read_u32le(input, pos) * prime32_3;
h32 = rotl(h32, 17) * prime32_4;
pos += 4;
}
// XXH_PROCESS1
while((inputLen - pos) > 0) {
h32 += read_u8(input, pos) * prime32_5;
h32 = rotl(h32, 11) * prime32_1;
pos += 1;
}
return h32;
}
constexpr uint32_t xxh32_digest(
const char* input, int inputLen, int pos,
uint32_t v1, uint32_t v2, uint32_t v3, uint32_t v4
) {
uint32_t h32 = 0;
if(inputLen >= 16) {
h32 = rotl(v1, 1) + rotl(v2, 7) + rotl(v3, 12) + rotl(v4, 18);
} else {
h32 = v3 + prime32_5;
}
h32 += inputLen;
h32 = xxh32_finalize(input, inputLen, pos, h32);
return xxh32_avalanche(h32);
}
constexpr uint32_t xxh32_round(uint32_t acc, const char* input, int pos) {
const uint32_t d = read_u32le(input, pos);
acc += d * prime32_2;
acc = rotl(acc, 13) * prime32_1;
return acc;
}
constexpr uint32_t xxh32(const char* input, int inputLen, uint32_t seed) {
uint32_t v1 = seed + prime32_1 + prime32_2;
uint32_t v2 = seed + prime32_2;
uint32_t v3 = seed;
uint32_t v4 = seed - prime32_1;
int pos = 0;
while(pos+16 <= inputLen) {
v1 = xxh32_round(v1, input, pos + 0*4);
v2 = xxh32_round(v2, input, pos + 1*4);
v3 = xxh32_round(v3, input, pos + 2*4);
v4 = xxh32_round(v4, input, pos + 3*4);
pos += 16;
}
return xxh32_digest(input, inputLen, pos, v1, v2, v3, v4);
}
}
// "public" function
namespace compiletime_xxhash {
constexpr uint32_t xxh32(const char* input, int inputLen, uint32_t seed) {
return detail::xxh32::xxh32(input, inputLen, seed);
}
}
constexpr int compiletime_strlen(const char* input) {
int i = 0;
while(input[i] != 0) { ++i; }
return i;
}
#if defined(INCLUDE_XXHASH)
# define XXH_INLINE_ALL
# include "./xxHash/xxhash.h" // XXH32()
#endif
int main() {
constexpr const char* input = "xxHash - Extremely Fast Hash algorithm";
constexpr const int inputLen = compiletime_strlen(input);
constexpr uint32_t seed = 0;
constexpr uint32_t h0 = compiletime_xxhash::xxh32(input, inputLen, seed);
// Since h0 is compile-time constant value, we can use static_assert().
static_assert(h0 == 0xd75d048b, "Wrong hash value");
printf("input = %s\n" , input);
printf("inputLen = %d\n" , inputLen);
printf("constexpr = 0x%08x\n", h0);
#if defined(INCLUDE_XXHASH)
const uint32_t h1 = XXH32(input, inputLen, seed);
printf("XXH32() = 0x%08x\n", h1);
printf("%s\n" , (h0 == h1) ? "OK" : "NG");
#endif
}
# Testing C++20 Compile-time XXH32
cd
mkdir my-ct-xxhash-test
cd my-ct-xxhash-test
curl -JOL https://gist.github.com/t-mat/9a7d258324079fd4307b3698b4d109eb/raw/42f5917944fcb29b823416496060a932adb6603f/cxx20_ct_xxhash.cpp
git clone --depth=1 https://github.com/Cyan4973/xxHash
# g++-10
g++-10 -std=c++20 -DINCLUDE_XXHASH ./cxx20_ct_xxhash.cpp
./a.out
rm ./a.out
# clang
clang -std=c++20 -DINCLUDE_XXHASH ./cxx20_ct_xxhash.cpp
./a.out
rm ./a.out
# output
#
# > input = xxHash - Extremely Fast Hash algorithm
# > inputLen = 38
# > constexpr = 0xd75d048b
# > XXH32() = 0xd75d048b
# > OK
It also will encourage other developers to implement the algorithm in different form and language.
pls. have tiny typo correction: ↥.
Most helpful comment
What's this?
This code demonstrates compile-time XXH32 hash calculation in C++20.
"xxHash - Extremely Fast Hash algorithm".XXH32()when you defineINCLUDE_XXHASH.What's the point of this code?
When hash value becomes compile-time constant:
caselabel,static_assert()expression, etc.if constexpr ()is also useful.Since C++17/20 relaxed many restriction of
constexpr, this code is a naive version ofXXH32().So my point is, it's always nice to have naive/simple version of the code for clarity and testing.
It also will encourage other developers to implmenent the algorithm in different form and language.
See also