Coverage Report

Created: 2026-06-30 06:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/lib/common/hash.cpp
Line
Count
Source
1
#include "common/hash.h"
2
3
#include <array>
4
#include <cstring>
5
6
namespace {
7
8
using namespace WasmEdge;
9
10
// rapidhash v3 secrets — only the 4 used by the Nano variant.
11
// Indices match upstream rapid_secret[]: [0], [1], [2], [7].
12
static constexpr std::array<uint64_t, 4> Secret = {
13
    0x2d358dccaa6c78a5ull, // rapid_secret[0]
14
    0x8bb84b93962eacc9ull, // rapid_secret[1]
15
    0x4b33a62ed433d4a3ull, // rapid_secret[2]
16
    0xaaaaaaaaaaaaaaaaull, // rapid_secret[7]
17
};
18
19
static const uint64_t RandomSeed = Hash::RandEngine();
20
21
// Intentional: assumes little-endian. Trades platform-independent hash
22
// values for speed by skipping byte-swap on big-endian targets.
23
4.07M
inline uint64_t read(Span<const std::byte, 8> Data) noexcept {
24
4.07M
  uint64_t V;
25
4.07M
  std::memcpy(&V, Data.data(), 8);
26
4.07M
  return V;
27
4.07M
}
28
24.5k
inline uint64_t read(Span<const std::byte, 4> Data) noexcept {
29
24.5k
  uint32_t V;
30
24.5k
  std::memcpy(&V, Data.data(), 4);
31
24.5k
  return V;
32
24.5k
}
33
34
} // namespace
35
36
namespace WasmEdge::Hash {
37
38
574k
WASMEDGE_EXPORT uint64_t Hash::rapidHash(Span<const std::byte> Data) noexcept {
39
574k
  uint64_t Seed = RandomSeed;
40
574k
  Seed ^= rapidMix(Seed ^ Secret[2], Secret[1]);
41
574k
  uint64_t A = 0, B = 0;
42
574k
  if (likely(Data.size() <= 16)) {
43
547k
    if (Data.size() >= 4) {
44
102k
      Seed ^= Data.size();
45
102k
      if (Data.size() >= 8) {
46
90.5k
        A = read(Data.first<8>());
47
90.5k
        B = read(Data.last<8>());
48
90.5k
      } else {
49
12.2k
        A = read(Data.first<4>());
50
12.2k
        B = read(Data.last<4>());
51
12.2k
      }
52
444k
    } else if (Data.size() > 0) {
53
444k
      A = (static_cast<uint64_t>(Data[0]) << 45) |
54
444k
          static_cast<uint64_t>(Data[Data.size() - 1]);
55
444k
      B = static_cast<uint64_t>(Data[Data.size() >> 1]);
56
444k
    } else {
57
65
      A = B = 0;
58
65
    }
59
547k
  } else {
60
26.8k
    if (Data.size() > 48) {
61
245
      uint64_t See1 = Seed, See2 = Seed;
62
630k
      do {
63
630k
        Seed = rapidMix(read(Data.first<8>()) ^ Secret[0],
64
630k
                        read(Data.subspan<8>().first<8>()) ^ Seed);
65
630k
        See1 = rapidMix(read(Data.subspan<16>().first<8>()) ^ Secret[1],
66
630k
                        read(Data.subspan<24>().first<8>()) ^ See1);
67
630k
        See2 = rapidMix(read(Data.subspan<32>().first<8>()) ^ Secret[2],
68
630k
                        read(Data.subspan<40>().first<8>()) ^ See2);
69
630k
        Data = Data.subspan<48>();
70
630k
      } while (Data.size() > 48);
71
245
      Seed ^= See1;
72
245
      Seed ^= See2;
73
245
    }
74
26.8k
    if (Data.size() > 16) {
75
26.7k
      Seed = rapidMix(read(Data.first<8>()) ^ Secret[2],
76
26.7k
                      read(Data.subspan<8>().first<8>()) ^ Seed);
77
26.7k
      if (Data.size() > 32) {
78
2.08k
        Seed = rapidMix(read(Data.subspan<16>().first<8>()) ^ Secret[2],
79
2.08k
                        read(Data.subspan<24>().first<8>()) ^ Seed);
80
2.08k
      }
81
26.7k
    }
82
26.8k
    A = read(Data.last<16>().first<8>()) ^ Data.size();
83
26.8k
    B = read(Data.last<8>());
84
26.8k
  }
85
574k
  A ^= Secret[1];
86
574k
  B ^= Seed;
87
574k
  rapidMum(A, B);
88
574k
  return rapidMix(A ^ Secret[3], B ^ Secret[1] ^ Data.size());
89
574k
}
90
91
} // namespace WasmEdge::Hash