Search code examples
c++stringconstexprlookup-tables

Fast and maintainable way of implementing string to integer lookup table


I can find many hits on the question on how to map an integer to a string constant, with the obvious solution

char const* strings[] = {"Foo", "Bar", ...};

Now, suppose I want the inverse: I have the string "Bar", and want 1. My strings are up to 4 characters and ascii null is not a valid value. There are 64 integers to map values to. Do I have to write a long if-else construct with string comparison or is there something better.

To clarify, I prefer the solution to not require runtime initialization, which as of C++17, makes ti impossible to use std::map or std::unordered_map.


Solution

  • My strings are up to 4 characters and ascii null is not a valid value.

    With this condition, you can convert your strings into an integer, and use your favourite compile-time integer-to-integer map.

    For example, with a switch:

    #include <cstddef>
    #include <cstdint>
    
    namespace detail {
        constexpr std::uint64_t string_as_int(const char* string) noexcept {
            std::uint64_t result = 0;
            std::uint64_t i = 0;
            for (; i < 4 && *string; ++string, ++i) {
                result |= static_cast<std::uint64_t>(static_cast<unsigned char>(*string)) << (i * 8u);
            }
            return result;
        }
    
        constexpr std::uint64_t operator ""_h(const char* string, std::size_t) noexcept {
            return string_as_int(string);
        }
    }
    
    constexpr int lookup(const char* string) {
        using detail::operator ""_h;
        switch (detail::string_as_int(string)) {
            case "Foo"_h: return 1;
            case "Bar"_h: return 2;
            default: return 0;
        }
    }