C++ does not allow using string literals as case values in a switch statement. In modern C++ this restriction can be worked around with constexpr hash values.
E.g. instead of using string literals, we will be using their hash codes, computed during compilation and matched agains a hash code of a varable string.
First we define a hash function:
#pragma once #include <cstdint> #include <string_view> namespace fnv1b { /* FNV-1b hash function with extra rotation * https://en.wikipedia.org/wiki/Fowler–Noll–Vo_hash_function */ template<typename T = std::size_t> inline T hash(const char* str, std::size_t size) noexcept; template<typename T> inline constexpr T ror(T x, unsigned N) noexcept { return (x << (sizeof(T)*8 - N)) | ((x) >> (N)); } template<> inline constexpr uint32_t hash<uint32_t>(const char* str, std::size_t size) noexcept { constexpr uint32_t val32 = 0x811c9dc5; constexpr uint32_t prime32 = 16777619; uint32_t result = val32; while(size--) { result ^= uint32_t(*str); result = ror(result, (8+(0xF&(*str++)))); /* added rotation 8-23 bits */ result *= prime32; } return result; } template<> inline constexpr uint64_t hash<uint64_t>(const char* str, std::size_t size) noexcept { constexpr uint64_t val64 = 0xcbf29ce484222325; constexpr uint64_t prime64 = 1099511628211ULL; uint64_t result = val64; while(size--) { result ^= uint64_t(*str); result = ror(result, (8+(*str++)%48)); /* added rotation 8-55 bits */ result *= prime64; } return result; } template<typename T = std::size_t> inline constexpr T hash(const std::string_view str) noexcept { return hash<T>(str.data(), str.size()); } }
Also available on gist
For easy of use we define a literal operator, computing hash from a string literal:
constexpr uint32_t operator "" _h(const char* str, size_t size) noexcept { return fnv1b::hash<uint32_t>(str, size); }
Usage
#include <iostream> #include <string> #include "hash_fnv1b.hpp" using namespace std; int main() { auto s = "hello"; switch(fnv1b::hash<uint32_t>(string_view(s))) { case "world"_h: cout << "World"; break; case "hello"_h: cout << "Hello"; break; } cout << endl; }
This example is aslo available live at https://onlinegdb.com/BJydy3XvN
Post a Comment