Skip to content
This repository was archived by the owner on Apr 8, 2026. It is now read-only.

Commit 8020d35

Browse files
committed
cpp: Use simpler 3a + b folding in std::hash
1 parent 104542f commit 8020d35

File tree

2 files changed

+12
-30
lines changed

2 files changed

+12
-30
lines changed

include/evmc/evmc.hpp

Lines changed: 6 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -143,18 +143,6 @@ inline constexpr uint32_t load32le(const uint8_t* bytes) noexcept
143143
(uint32_t{bytes[3]} << 24);
144144
}
145145

146-
namespace fnv
147-
{
148-
constexpr auto prime = 0x100000001b3; ///< The 64-bit FNV prime number.
149-
constexpr auto offset_basis = 0xcbf29ce484222325; ///< The 64-bit FNV offset basis.
150-
151-
/// The hashing transformation for 64-bit inputs based on the FNV-1a formula.
152-
inline constexpr uint64_t fnv1a_by64(uint64_t h, uint64_t x) noexcept
153-
{
154-
return (h ^ x) * prime;
155-
}
156-
} // namespace fnv
157-
158146

159147
/// The "equal to" comparison operator for the evmc::address type.
160148
inline constexpr bool operator==(const address& a, const address& b) noexcept
@@ -827,31 +815,25 @@ namespace std
827815
template <>
828816
struct hash<evmc::address>
829817
{
830-
/// Hash operator using FNV1a-based folding.
818+
/// Hash operator using (3a + b) folding of the address "words".
831819
constexpr size_t operator()(const evmc::address& s) const noexcept
832820
{
833821
using namespace evmc;
834-
using namespace fnv;
835-
return static_cast<size_t>(fnv1a_by64(
836-
fnv1a_by64(fnv1a_by64(fnv::offset_basis, load64le(&s.bytes[0])), load64le(&s.bytes[8])),
837-
load32le(&s.bytes[16])));
822+
return static_cast<size_t>(3 * (3 * load64le(&s.bytes[0]) + load64le(&s.bytes[8])) +
823+
load32le(&s.bytes[16]));
838824
}
839825
};
840826

841827
/// Hash operator template specialization for evmc::bytes32. Needed for unordered containers.
842828
template <>
843829
struct hash<evmc::bytes32>
844830
{
845-
/// Hash operator using FNV1a-based folding.
831+
/// Hash operator using (3a + b) folding of the bytes32 64-bit words.
846832
constexpr size_t operator()(const evmc::bytes32& s) const noexcept
847833
{
848834
using namespace evmc;
849-
using namespace fnv;
850-
return static_cast<size_t>(
851-
fnv1a_by64(fnv1a_by64(fnv1a_by64(fnv1a_by64(fnv::offset_basis, load64le(&s.bytes[0])),
852-
load64le(&s.bytes[8])),
853-
load64le(&s.bytes[16])),
854-
load64le(&s.bytes[24])));
835+
return static_cast<size_t>(3 * (3 * load64le(&s.bytes[0]) + load64le(&s.bytes[8])) +
836+
(3 * load64le(&s.bytes[16]) + load64le(&s.bytes[24])));
855837
}
856838
};
857839
} // namespace std

test/unittests/cpp_test.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,19 +111,19 @@ TEST(cpp, std_hash)
111111
#pragma warning(disable : 4307 /* integral constant overflow */)
112112
#pragma warning(disable : 4309 /* 'static_cast': truncation of constant value */)
113113

114-
static_assert(std::hash<evmc::address>{}({}) == static_cast<size_t>(0xd94d12186c0f2fb7), "");
115-
static_assert(std::hash<evmc::bytes32>{}({}) == static_cast<size_t>(0x4d25767f9dce13f5), "");
114+
static_assert(std::hash<evmc::address>{}({}) == 0, "");
115+
static_assert(std::hash<evmc::bytes32>{}({}) == 0, "");
116116

117-
EXPECT_EQ(std::hash<evmc::address>{}({}), static_cast<size_t>(0xd94d12186c0f2fb7));
118-
EXPECT_EQ(std::hash<evmc::bytes32>{}({}), static_cast<size_t>(0x4d25767f9dce13f5));
117+
EXPECT_EQ(std::hash<evmc::address>{}({}), size_t{0});
118+
EXPECT_EQ(std::hash<evmc::bytes32>{}({}), size_t{0});
119119

120120
auto ea = evmc::address{};
121121
std::fill_n(ea.bytes, sizeof(ea), uint8_t{0xee});
122-
EXPECT_EQ(std::hash<evmc::address>{}(ea), static_cast<size_t>(0x41dc0178e01b7cd9));
122+
EXPECT_EQ(std::hash<evmc::address>{}(ea), static_cast<size_t>(0x3333333422222216));
123123

124124
auto eb = evmc::bytes32{};
125125
std::fill_n(eb.bytes, sizeof(eb), uint8_t{0xee});
126-
EXPECT_EQ(std::hash<evmc::bytes32>{}(eb), static_cast<size_t>(0xbb14e5c56b477375));
126+
EXPECT_EQ(std::hash<evmc::bytes32>{}(eb), static_cast<size_t>(0xeeeeeeeeeeeeeee0));
127127

128128
#pragma warning(pop)
129129
}

0 commit comments

Comments
 (0)