💨

[C++]コンパイル時に文字列のハッシュ値を計算する

に公開

文字列のハッシュ値をコンパイル時に計算したくなるときがありますよね。
C++標準ライブラリのstd::hashは現在コンパイル時計算が可能な実装ではありません。

FNV-1a

https://en.wikipedia.org/wiki/Fowler–Noll–Vo_hash_function
今回は実装が非常に簡単かつ高速なハッシュアルゴリズムであるFowler–Noll–Voハッシュを使用します。
英語版wikipediaによるとこのハッシュ関数はパブリックドメインで公開されているそうです。
記載されている疑似コードを読んでいただくとわかるように非常に簡単な実装です。

実装

コンパイル時計算が可能な実装をします。
今回は32bit/64bitを実装しました、必要であればより大きい値のハッシュ計算を実装します。

template<class T>
constexpr T fnv_prime;

template<class T>
constexpr T fnv_offset_basis;

template<>
constexpr std::uint32_t fnv_prime<std::uint32_t> = 16777619u;

template<>
constexpr std::uint64_t fnv_prime<std::uint64_t> = 1099511628211ull;

template<>
constexpr std::uint32_t fnv_offset_basis<std::uint32_t> = 2166136261u;

template<>
constexpr std::uint64_t fnv_offset_basis<std::uint64_t> = 14695981039346656037ull;


template<class T>
constexpr T fnv1a_hash(std::string_view str) noexcept
{
    T hash = fnv_offset_basis<T>;
    for (auto c : str)
    {
        hash ^= c;
        hash *= fnv_prime<T>;
    }

    return hash;
}

実際に文字列を入力することでコンパイル時にハッシュ値が計算できるようになりました。

// 1219850847
constexpr auto hash_value = fnv1a_hash<std::uint32_t>("void");

Discussion