Xxhash: C++20 em tempo de compilação XXH32() cálculo

Criado em 3 fev. 2021  ·  3Comentários  ·  Fonte: Cyan4973/xxHash

Isto não é um problema. Só por compartilhar meu experimento. A postagem a seguir demonstra o cálculo de hash XXH32() em tempo de compilação em C++20 e seu constexpr .

Mas se você quiser usar o xxHash em tempo de compilação agora , dê uma olhada na excelente implementação C++11 de tempo de compilação XXH64() do @ekpyron . É melhor que meu código em muitos aspectos.

announcement

Comentários muito úteis

O que é isso?

Este código demonstra o cálculo de hash XXH32 em tempo de compilação em C++20.

  • Ele calcula o valor de hash da string "xxHash - Extremely Fast Hash algorithm" .
  • Ele também verifica o valor de hash esperado por XXH32() genuíno quando você define INCLUDE_XXHASH .

Qual é o ponto deste código?

Quando o valor de hash se torna constante em tempo de compilação:

  • Você pode usá-lo mais livremente.

    • Por exemplo, usando dentro do rótulo case static_assert() , expressão static_assert(), etc.

    • if constexpr () também é útil.

  • O código de cálculo de hash desaparece. Veja o resultado no Compiler Explorer.

Como o C++ 17/20 relaxou muitas restrições de constexpr , esse código é uma versão ingênua de XXH32() .

Então, meu ponto é que é sempre bom ter uma versão ingênua/simples do código para clareza e teste.
Também incentivará outros desenvolvedores a implementar o algoritmo em diferentes formas e linguagens.

Veja também

Todos 3 comentários

O que é isso?

Este código demonstra o cálculo de hash XXH32 em tempo de compilação em C++20.

  • Ele calcula o valor de hash da string "xxHash - Extremely Fast Hash algorithm" .
  • Ele também verifica o valor de hash esperado por XXH32() genuíno quando você define INCLUDE_XXHASH .

Qual é o ponto deste código?

Quando o valor de hash se torna constante em tempo de compilação:

  • Você pode usá-lo mais livremente.

    • Por exemplo, usando dentro do rótulo case static_assert() , expressão static_assert(), etc.

    • if constexpr () também é útil.

  • O código de cálculo de hash desaparece. Veja o resultado no Compiler Explorer.

Como o C++ 17/20 relaxou muitas restrições de constexpr , esse código é uma versão ingênua de XXH32() .

Então, meu ponto é que é sempre bom ter uma versão ingênua/simples do código para clareza e teste.
Também incentivará outros desenvolvedores a implementar o algoritmo em diferentes formas e linguagens.

Veja também

O código e o resultado

Código, resultado e desmontagem no Compiler Explorer

versão gist do código por conveniência

Pré-requisitos

  • Compiladores compatíveis com C++20

    • g++ (10.x, também conhecido g++-10 )

    • clang (10.x)

    • VC++2019 (19.28.x)

Código

// C++20 Compile-time XXH32()
//
// g++-10 (10.2.0)          g++-10 -std=c++20 -DINCLUDE_XXHASH ./cxx20_ct_xxhash.cpp
// Clang (10.0.0)           clang  -std=c++20 -DINCLUDE_XXHASH ./cxx20_ct_xxhash.cpp
// Visual C++ 2019 (19.28)  cl /std:c++latest /DINCLUDE_XXHASH .\cxx20_ct_xxhash.cpp
//
// Result at Compiler Explorer
// https://godbolt.org/z/bGv7Mh

#include <stdio.h>  // printf()
#include <stdint.h> // uint8_t, uint32_t
#include <bit>      // std::rotl() ( https://en.cppreference.com/w/cpp/numeric/rotl )

// "private" utility functions
namespace compiletime_xxhash::detail {
    constexpr uint32_t rotl(uint32_t v, int x) {
        return std::rotl(v, x);
    }

    constexpr uint8_t read_u8(const char* input, int pos) {
        return static_cast<uint8_t>(input[pos]);
    }

    constexpr uint32_t read_u32le(const char* input, int pos) {
        const uint32_t b0 = read_u8(input, pos + 0);
        const uint32_t b1 = read_u8(input, pos + 1);
        const uint32_t b2 = read_u8(input, pos + 2);
        const uint32_t b3 = read_u8(input, pos + 3);
        return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24);
    }
}

// "private" XXH32 functions
namespace compiletime_xxhash::detail::xxh32 {
    constexpr uint32_t prime32_1 = 0x9E3779B1U;
    constexpr uint32_t prime32_2 = 0x85EBCA77U;
    constexpr uint32_t prime32_3 = 0xC2B2AE3DU;
    constexpr uint32_t prime32_4 = 0x27D4EB2FU;
    constexpr uint32_t prime32_5 = 0x165667B1U;

    constexpr uint32_t xxh32_avalanche(uint32_t h32) {
        h32 ^= h32 >> 15;
        h32 *= prime32_2;
        h32 ^= h32 >> 13;
        h32 *= prime32_3;
        h32 ^= h32 >> 16;
        return h32;
    }

    constexpr uint32_t xxh32_finalize(const char* input, int inputLen, int pos, uint32_t h32) {
        // XXH_PROCESS4
        while((inputLen - pos) >= 4) {
            h32 += read_u32le(input, pos) * prime32_3;
            h32 = rotl(h32, 17) * prime32_4;
            pos += 4;
        }
        // XXH_PROCESS1
        while((inputLen - pos) > 0) {
            h32 += read_u8(input, pos) * prime32_5;
            h32 = rotl(h32, 11) * prime32_1;
            pos += 1;
        }
        return h32;
    }

    constexpr uint32_t xxh32_digest(
        const char* input, int inputLen, int pos,
        uint32_t v1, uint32_t v2, uint32_t v3, uint32_t v4
    ) {
        uint32_t h32 = 0;
        if(inputLen >= 16) {
            h32 = rotl(v1, 1) + rotl(v2, 7) + rotl(v3, 12) + rotl(v4, 18);
        } else {
            h32 = v3 + prime32_5;
        }
        h32 += inputLen;
        h32 = xxh32_finalize(input, inputLen, pos, h32);
        return xxh32_avalanche(h32);
    }

    constexpr uint32_t xxh32_round(uint32_t acc, const char* input, int pos) {
        const uint32_t d = read_u32le(input, pos);
        acc += d * prime32_2;
        acc = rotl(acc, 13) * prime32_1;
        return acc;
    }

    constexpr uint32_t xxh32(const char* input, int inputLen, uint32_t seed) {
        uint32_t v1 = seed + prime32_1 + prime32_2;
        uint32_t v2 = seed + prime32_2;
        uint32_t v3 = seed;
        uint32_t v4 = seed - prime32_1;
        int pos = 0;
        while(pos+16 <= inputLen) {
            v1 = xxh32_round(v1, input, pos + 0*4);
            v2 = xxh32_round(v2, input, pos + 1*4);
            v3 = xxh32_round(v3, input, pos + 2*4);
            v4 = xxh32_round(v4, input, pos + 3*4);
            pos += 16;
        }
        return xxh32_digest(input, inputLen, pos, v1, v2, v3, v4);
    }
}

// "public" function
namespace compiletime_xxhash {
    constexpr uint32_t xxh32(const char* input, int inputLen, uint32_t seed) {
        return detail::xxh32::xxh32(input, inputLen, seed);
    }
}

constexpr int compiletime_strlen(const char* input) {
    int i = 0;
    while(input[i] != 0) { ++i; }
    return i;
}

#if defined(INCLUDE_XXHASH)
#  define XXH_INLINE_ALL
#  include "./xxHash/xxhash.h"  // XXH32()
#endif

int main() {
    constexpr const char* input = "xxHash - Extremely Fast Hash algorithm";
    constexpr const int inputLen = compiletime_strlen(input);
    constexpr uint32_t seed = 0;

    constexpr uint32_t h0 = compiletime_xxhash::xxh32(input, inputLen, seed);

    // Since h0 is compile-time constant value, we can use static_assert().
    static_assert(h0 == 0xd75d048b, "Wrong hash value");

    printf("input     = %s\n"    , input);
    printf("inputLen  = %d\n"    , inputLen);
    printf("constexpr = 0x%08x\n", h0);

#if defined(INCLUDE_XXHASH)
    const uint32_t h1 = XXH32(input, inputLen, seed);
    printf("XXH32()   = 0x%08x\n", h1);
    printf("%s\n"                , (h0 == h1) ? "OK" : "NG");
#endif
}

Construir

# Testing C++20 Compile-time XXH32
cd
mkdir my-ct-xxhash-test
cd my-ct-xxhash-test
curl -JOL https://gist.github.com/t-mat/9a7d258324079fd4307b3698b4d109eb/raw/42f5917944fcb29b823416496060a932adb6603f/cxx20_ct_xxhash.cpp
git clone --depth=1 https://github.com/Cyan4973/xxHash

# g++-10
g++-10 -std=c++20 -DINCLUDE_XXHASH ./cxx20_ct_xxhash.cpp
./a.out
rm ./a.out

# clang
clang  -std=c++20 -DINCLUDE_XXHASH ./cxx20_ct_xxhash.cpp
./a.out
rm ./a.out

# output
#
# > input     = xxHash - Extremely Fast Hash algorithm
# > inputLen  = 38
# > constexpr = 0xd75d048b
# > XXH32()   = 0xd75d048b
# > OK

Também incentivará outros desenvolvedores a implementar o algoritmo em diferentes formas e linguagens.

por favor tem pequena correção de digitação: ↥.

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

easyaspi314 picture easyaspi314  ·  7Comentários

shuffle2 picture shuffle2  ·  6Comentários

make-github-pseudonymous-again picture make-github-pseudonymous-again  ·  3Comentários

jtoivainen picture jtoivainen  ·  4Comentários

boazsegev picture boazsegev  ·  6Comentários