Coverage Report

Created: 2026-07-16 07:09

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.02M
inline uint64_t read(Span<const std::byte, 8> Data) noexcept {
24
4.02M
  uint64_t V;
25
4.02M
  std::memcpy(&V, Data.data(), 8);
26
4.02M
  return V;
27
4.02M
}
28
24.9k
inline uint64_t read(Span<const std::byte, 4> Data) noexcept {
29
24.9k
  uint32_t V;
30
24.9k
  std::memcpy(&V, Data.data(), 4);
31
24.9k
  return V;
32
24.9k
}
33
34
} // namespace
35
36
namespace WasmEdge::Hash {
37
38
841k
WASMEDGE_EXPORT uint64_t Hash::rapidHash(Span<const std::byte> Data) noexcept {
39
841k
  uint64_t Seed = RandomSeed;
40
841k
  Seed ^= rapidMix(Seed ^ Secret[2], Secret[1]);
41
841k
  uint64_t A = 0, B = 0;
42
841k
  if (likely(Data.size() <= 16)) {
43
814k
    if (Data.size() >= 4) {
44
104k
      Seed ^= Data.size();
45
104k
      if (Data.size() >= 8) {
46
91.8k
        A = read(Data.first<8>());
47
91.8k
        B = read(Data.last<8>());
48
91.8k
      } else {
49
12.4k
        A = read(Data.first<4>());
50
12.4k
        B = read(Data.last<4>());
51
12.4k
      }
52
710k
    } else if (Data.size() > 0) {
53
709k
      A = (static_cast<uint64_t>(Data[0]) << 45) |
54
709k
          static_cast<uint64_t>(Data[Data.size() - 1]);
55
709k
      B = static_cast<uint64_t>(Data[Data.size() >> 1]);
56
709k
    } else {
57
119
      A = B = 0;
58
119
    }
59
814k
  } else {
60
27.2k
    if (Data.size() > 48) {
61
250
      uint64_t See1 = Seed, See2 = Seed;
62
621k
      do {
63
621k
        Seed = rapidMix(read(Data.first<8>()) ^ Secret[0],
64
621k
                        read(Data.subspan<8>().first<8>()) ^ Seed);
65
621k
        See1 = rapidMix(read(Data.subspan<16>().first<8>()) ^ Secret[1],
66
621k
                        read(Data.subspan<24>().first<8>()) ^ See1);
67
621k
        See2 = rapidMix(read(Data.subspan<32>().first<8>()) ^ Secret[2],
68
621k
                        read(Data.subspan<40>().first<8>()) ^ See2);
69
621k
        Data = Data.subspan<48>();
70
621k
      } while (Data.size() > 48);
71
250
      Seed ^= See1;
72
250
      Seed ^= See2;
73
250
    }
74
27.2k
    if (Data.size() > 16) {
75
27.1k
      Seed = rapidMix(read(Data.first<8>()) ^ Secret[2],
76
27.1k
                      read(Data.subspan<8>().first<8>()) ^ Seed);
77
27.1k
      if (Data.size() > 32) {
78
2.10k
        Seed = rapidMix(read(Data.subspan<16>().first<8>()) ^ Secret[2],
79
2.10k
                        read(Data.subspan<24>().first<8>()) ^ Seed);
80
2.10k
      }
81
27.1k
    }
82
27.2k
    A = read(Data.last<16>().first<8>()) ^ Data.size();
83
27.2k
    B = read(Data.last<8>());
84
27.2k
  }
85
841k
  A ^= Secret[1];
86
841k
  B ^= Seed;
87
841k
  rapidMum(A, B);
88
841k
  return rapidMix(A ^ Secret[3], B ^ Secret[1] ^ Data.size());
89
841k
}
90
91
} // namespace WasmEdge::Hash