There may come a time that you don’t want to leave strings in your executable but still need to do some kind of string comparison. For that I use the compile-time constexpr features of modern c++ compilers.

1
2
3
4
auto hash = CX_Fnv1a("shady_lib.dll")

// in case you need to ignore case, string will be converted to lowercase
auto hash = CX_IFnv1a("shady_lib.dll")

Check the output binary using string.exe, there will be no trace of shady_lib.dll other than a number.

fnv1a.hpp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#pragma once

#define CX_Fnv1a(s) FNV1A::FnvHash<s>::v
#define CX_IFnv1a(s) FNV1A::IFnvHash<s>::v

namespace FNV1A
{
    typedef unsigned long long fnvhash;
    constexpr fnvhash FnvValue = 14695981039346656037ull;
    constexpr fnvhash FnvPrime = 1099511628211ull;

    // CASE-SENSITIVE
    template<typename T>
    constexpr fnvhash Hash(T c) noexcept
    {
        fnvhash v = FnvValue;
        for (; *c; ++c) v = (v ^ static_cast<fnvhash>(*c)) * FnvPrime;
        return v;
    }

    template<typename T>
    constexpr fnvhash HashFixed(T c, size_t s) noexcept
    {
        fnvhash v = FnvValue;
        for (size_t i = 0; i < s; ++i) v = (v ^ static_cast<fnvhash>(c[i])) * FnvPrime;
        return v;
    }

    template <typename CharT, size_t N>
    struct FnvString
    {
        fnvhash v;
        constexpr FnvString(const CharT(&foo)[N + 1]) noexcept
            : v(Hash(foo))
        {}
    };

    template <typename CharT, size_t N>
    FnvString(const CharT(&str)[N])->FnvString<CharT, N - 1>;

    template <FnvString s>
    struct FnvHash { enum : fnvhash { v = s.v }; };

    // CASE-INSENSITIVE
    template<typename CharT>
    constexpr auto ToLower(CharT c) noexcept
    {
        return (c >= 65 && c <= 90) ? static_cast<CharT>(c + 32) : c;
    }

    template<typename T>
    constexpr fnvhash IHash(T c) noexcept
    {
        fnvhash v = FnvValue;
        for (; *c; ++c) v = (v ^ static_cast<fnvhash>(ToLower(*c))) * FnvPrime;
        return v;
    }

    template<typename T>
    constexpr fnvhash IHashFixed(T c, size_t s) noexcept
    {
        fnvhash v = FnvValue;
        for (size_t i = 0; i < s; ++i) v = (v ^ static_cast<fnvhash>(ToLower(c[i]))) * FnvPrime;
        return v;
    }

    template <typename CharT, size_t N>
    struct IFnvString
    {
        fnvhash v;
        constexpr IFnvString(const CharT(&foo)[N + 1]) noexcept
            : v(IHash(foo))
        {}
    };

    template <typename CharT, size_t N>
    IFnvString(const CharT(&str)[N])->IFnvString<CharT, N - 1>;

    template <IFnvString s>
    struct IFnvHash { enum : fnvhash { v = s.v }; };
}