0

I have a constexpr function that calculates CRC at compile time. I need to create a map between CRCs that are generated by this function and string inputs and use them in runtime (Even better if it is also possible to use it in compile time too).

The map creation process should be from withing this constexpr function so it automatically logs all CRCs that are generated. Also it doesn't necessarily needs to be a map. Only key value pairs that could be looked up.

I'm using C++ 17 by the way.

This is my function signature:

template <size_t length>
static constexpr unsigned int getCrc32(const char (&str)[length])
{
        //calculate compile time CRC

        // What I need should happen here: saving the calculated
        // CRC and string to be accessed outside later
}

I tried different ways with templates and other things but I either end up with compiling code with undefined behavior or unmodifiable contexpr wall.

11
  • 2
    You cannot have constexpr std::map, you can have constexpr std::array<std::pair<unsigned int, const char*>> (with pointer with static storage). Commented Oct 24, 2024 at 9:06
  • @Jarod42 I know, the question is how to fill it by each call to this function? Commented Oct 24, 2024 at 9:10
  • 1
    So what did you try and what didn't work? E.g. this seems to be simple enough: constexpr Result r1{"abc", getCrc32("abc")}; assuming you have some struct Result {const char* in; unsigned int out;}; Commented Oct 24, 2024 at 9:12
  • 1
    So you don't want to provide a list/tuple of c-string pointer, but register them from the function call, right? Commented Oct 24, 2024 at 9:26
  • 1
    Now understood, but it sounds difficult (impossible?). You want the constexpr function to modify some storage while (possibly runtime dependent) calling this function. Commented Oct 24, 2024 at 9:32

1 Answer 1

0

If you have C++20 and use a slightly different function signature, there a way implement calc_hash<"string">() so that it can:

  • Calculate the hash at compile-time (the function itself is constexpr).
  • Collect all string arguments to a global std::set<std::string> variable for inspection at runtime.

(demo)

#include <iostream>
#include <cstdint>
#include <string_view>
#include <set>

constexpr uint32_t hash_impl(std::string_view view) {
    uint32_t sum = 0;
    for(uint8_t c : view) {
        sum = sum * 269 + c;
    }
    return sum;
}

template <size_t N>
struct string_literal {
    char data[N+1] = {};

    constexpr string_literal(char const (&str)[N+1]) {
        for (size_t i = 0; i < N+1; ++i) {
            data[i] = str[i];
        }
    }

    constexpr std::string_view view() const {
        return { data, data + N };
    }
};

template <size_t N>
string_literal(char const (&arr)[N]) -> string_literal<N-1>;

struct Database {
    inline static std::set<std::string> m_;

    template<string_literal lit>
    inline static int reg_ = (m_.insert(std::string(lit.view())), 0);
};

template <string_literal lit>
constexpr uint32_t calc_hash() {
    (void) &Database::reg_<lit>;
    return hash_impl(lit.view());
}

void foo() {
    constexpr auto h1 = calc_hash<"hello">();
    constexpr auto h2 = calc_hash<"world">();
    std::cout << "h1 = " << h1 << std::endl;
    std::cout << "h2 = " << h2 << std::endl;
}

int main() {
    for(auto const& str : Database::m_) {
        std::cout << "db: str=" << str << ", hash=" << hash_impl(str) << std::endl;
    }
    // Print:
    // db: str=hello, hash=1068862952
    // db: str=world, hash=2496251684
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.