veselink1 / refl-cpp

Static reflection for C++17 (compile-time enumeration, attributes, proxies, overloads, template functions, metaprogramming).
https://veselink1.github.io/refl-cpp/md__introduction.html
MIT License
1.05k stars 76 forks source link

Q: Calculating signature and checksum using constexpr in C++17 #45

Closed caiwan closed 3 years ago

caiwan commented 3 years ago

Hi,

Recently I have implemented a simple serialization using this library, but I came across a problem that I wasn't able to solve. My application relies on C++17 with MSVC which limits my choices of what I'm able to do with constexpr magic.

I'd like to create a template struct that is able to calculate the hash of the members in a structure based on their name and type. I could create an SFINAE template to return with the name of the phase types, even some STL containers, but I wasn't able to accumulate a const_string in a way to have the signature in one piece in compile-time and to hash it later. I could do that in runtime, but the purpose of that is to have a constant value generated from that not runtime.

My questions are how exactly accumulation works, and how can it be utilized in such a way to generate a signature string from the reflected type? (I even can skip the string concatenation and directly jump to the CRC32 accumulation, but the problem is the same still.)

My Crc32 algorithm looks like this. How can I possibly extract the reflected value to feed a structure in a similar way?

    template <Checksum CRC, char... Chars> struct Crc32Impl
    {
    };

    template <Checksum CRC, char Head, char... Tail> struct Crc32Impl<CRC, Head, Tail...>
    {
        static constexpr Checksum value = Crc32Impl<crcTable[static_cast<unsigned char>(CRC) ^ static_cast<unsigned char>(Head)] ^ (CRC >> 8), Tail...>::value;
    };

    template <Checksum CRC> struct Crc32Impl<CRC>
    {
        static constexpr Checksum value = CRC ^ 0xFFFFFFFF;
    };

    template <char... Chars> using Crc32 = Crc32Impl<0xFFFFFFFF, Chars...>;

    constexpr Checksum Crc32Rec(const char * s, const Checksum crc = 0xFFFFFFFF) noexcept
    {
        return *s == 0 ? crc ^ 0xFFFFFFFF : Crc32Rec(s + 1, crcTable[static_cast<unsigned char>(crc) ^ static_cast<unsigned char>(*s)] ^ (crc >> 8));
    }
caiwan commented 3 years ago

Fortunately, I was able to work out a solution for this issue, the key was to utilize filter to filter out non-fields from reflection - and it does not support properties though.

Ii can be found here https://github.com/caiwan/ReflectionPOC/blob/master/include/Serialization/Crc32.h and here https://github.com/caiwan/ReflectionPOC/blob/master/include/Serialization/Signature.h