compile time hash (Adler-32)



  • EDIT: falschrum durch den string zu gehen, war nicht so schlau.
    Jetzt fehlt mir noch etwas, mit dem ich das parameter pack umdrehen kann.

    #include <iostream>
    #include <boost/preprocessor/repetition/repeat.hpp>
    #define GET_STR_AUX(_, i, str) (sizeof(str) > (i) ? str[(i)] : 0),
    // BOOST_PP_REPEAT verwendet hier 3 wegen des Beispiels
    // So kann ich den hash nachprüfen, sonst würden noch weitere nullen reingeschoben
    #define GET_STR(str) BOOST_PP_REPEAT(3,GET_STR_AUX,str) 0
    #define MOD_ADLER 65521
    
    template <char C, char... List> struct const_hash
    {
        const static uint32_t s1 = (const_hash<List...>::s1 + C) % MOD_ADLER;
        const static uint32_t s2 = (const_hash<List...>::s2 + s1) % MOD_ADLER;
        const static uint32_t value = (s2 << 16) | s1;
    };
    
    template <char C> struct const_hash <C> // C = '\0'
    {
        const static uint32_t s1 = 1;
        const static uint32_t s2 = 0;
        const static uint32_t value = (s2 << 16) | s1;
    };
    
    #define HASH(STRING) const_hash<GET_STR(STRING)>::value
    
    int main()
    {
        std::cout << std::hex << HASH("CBA"); // CBA für ABC, jetzt muss ich noch was zum umdrehen basteln
        return 0;
    }
    

  • Mod

    Du brauchst hier kein Boost.PP! Das ist ein Zweizeiler, den du selber schreibst!



  • Ich habe versehentlich rauseditiert, dass ich kein constexpr habe

    Sonst wäre das Kindergarten.


  • Mod

    Ich habe versehentlich rauseditiert, dass ich kein constexpr habe

    Das brauchst du dafür auch nicht. Das sind zwei Makros in diesem Beispiel, sonst ein paar mehr.



  • Zunächst erstmal zu meinem eigentlichen Problem:

    #include <iostream>
    #include <boost/preprocessor/repetition/repeat.hpp>
    #define GET_STR_AUX(_, i, str) (sizeof(str) > (i)+1 ? str[sizeof(str)-(i)-2] : 0),
    #define GET_STR(str) BOOST_PP_REPEAT(64,GET_STR_AUX,str) 0
    #define MOD_ADLER 65521
    
    template <char C, char... List> struct const_hash
    {
        const static uint32_t s1 = (C!=0)?((const_hash<List...>::s1 + C) % MOD_ADLER):(1);
        const static uint32_t s2 = (C!=0)?((const_hash<List...>::s2 + s1) % MOD_ADLER):(0);
        const static uint32_t value = (s2 << 16) | s1;
    };
    
    template <char C> struct const_hash <C>
    {
        const static uint32_t s1 = 1;
        const static uint32_t s2 = 0;
        const static uint32_t value = (s2 << 16) | s1;
    };
    
    #define HASH(STRING) const_hash<GET_STR(STRING)>::value
    
    int main()
    {
        std::cout << std::hex << HASH("ABCDEF") << "\n";
        return 0;
    }
    

    Dies reversed die Anordnung automatisch und ignoriert folgende Nullen.

    Das mit dem Makro überlege ich mir. Ich finde den Präprozessor ein wenig... anstrengend

    EDIT: ich plane nicht strings zu hashen, die ein '\0' in der Mitte haben.

    EDIT 2: Hat sich sowieso erledigt. Ein kleiner Test hat ergeben, dass

    __const_adler32<"str"[sizeof("str")-(0)-2]>::value;
    

    für Visual Studio 2013 nicht gültig ist, da "str"[sizeof("str")-(0)-2]
    keine compile-time constant expression ist 🙄


  • Mod

    keine compile-time constant expression ist

    Ist natürlich falsch.

    Der Möglichkeit nach hast du noch eine andere Option, die ist aber relativ ungünstig: Global ein char-Array deklarieren, und dann einen Zeiger darauf an das Template übergeben.


Log in to reply