A while back this question proposed a constexpr
compile-time Sieve of Eratosthenes. It also linked to another SO question about compile-time computation of CRCs. I've found a place where I'd like to precompute the hash of a few C-strings, so I used those previous questions as a base.
I'm implementing the one-at-a-time hash algorithm for C-style strings. I'm stuck to using C++11, so the function has to be recursive and without any local state:
namespace ct
{
constexpr std::uint32_t stringLength(const char * cstr)
{
return (*cstr != '\0') ? (stringLength(cstr + 1) + 1) : 0;
}
constexpr std::uint32_t sumSHL(std::uint32_t h, std::uint32_t shift) { return h + (h << shift); }
constexpr std::uint32_t sumSHR(std::uint32_t h, std::uint32_t shift) { return h + (h >> shift); }
constexpr std::uint32_t xorSHR(std::uint32_t h, std::uint32_t shift) { return h ^ (h >> shift); }
constexpr std::uint32_t hashFinishImpl(std::uint32_t h)
{
// h += (h << 3)
// h ^= (h >> 11)
// h += (h << 15)
return sumSHL(xorSHR(sumSHL(h, 3), 11), 15);
}
constexpr std::uint32_t hashStepImpl(std::uint32_t h, std::uint32_t c)
{
// h += c
// h += (h << 10)
// h ^= (h >> 6)
return xorSHR(sumSHL(h + c, 10), 6);
}
constexpr std::uint32_t hashImpl(const char * cstr, std::uint32_t length, std::uint32_t h)
{
return (length != 0) ? hashImpl(cstr + 1, length - 1, hashStepImpl(h, *cstr)) : hashFinishImpl(h);
}
constexpr std::uint32_t hashCString(const char * cstr)
{
return hashImpl(cstr, stringLength(cstr), 0);
}
} // namespace ct {}
I'm thinking it looks a bit convoluted, but couldn't think of a better way of handling it... Any suggestions are appreciated.