Skip to content

Commit b74d8d5

Browse files
committed
refactor: Add consteval uint256(hex_str)
Complements uint256::FromHex() nicely in that it naturally does all error checking at compile time and so doesn't need to return an std::optional. Will be used in the following 2 commits to replace many calls to uint256S(). uint256S() calls taking C-string literals are littered throughout the codebase and executed at runtime to perform parsing unless a given optimizer was surprisingly efficient. While this may not be a hot spot, it's better hygiene in C++20 to store the parsed data blob directly in the binary, without any parsing at runtime.
1 parent 1afa3c8 commit b74d8d5

File tree

2 files changed

+30
-0
lines changed

2 files changed

+30
-0
lines changed

src/test/uint256_tests.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,4 +399,11 @@ BOOST_AUTO_TEST_CASE( check_ONE )
399399
BOOST_CHECK_EQUAL(one, uint256::ONE);
400400
}
401401

402+
BOOST_AUTO_TEST_CASE(FromHex_vs_uint256)
403+
{
404+
auto runtime_uint{uint256::FromHex("4A5E1E4BAAB89F3A32518A88C31BC87F618f76673e2cc77ab2127b7afdeda33b").value()};
405+
constexpr uint256 consteval_uint{ "4a5e1e4baab89f3a32518a88c31bc87f618F76673E2CC77AB2127B7AFDEDA33B"};
406+
BOOST_CHECK_EQUAL(consteval_uint, runtime_uint);
407+
}
408+
402409
BOOST_AUTO_TEST_SUITE_END()

src/uint256.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ class base_blob
4141
std::copy(vch.begin(), vch.end(), m_data.begin());
4242
}
4343

44+
consteval explicit base_blob(std::string_view hex_str);
45+
4446
constexpr bool IsNull() const
4547
{
4648
return std::all_of(m_data.begin(), m_data.end(), [](uint8_t val) {
@@ -120,6 +122,26 @@ class base_blob
120122
}
121123
};
122124

125+
template <unsigned int BITS>
126+
consteval base_blob<BITS>::base_blob(std::string_view hex_str)
127+
{
128+
// Non-lookup table version of HexDigit().
129+
auto from_hex = [](const char c) -> int8_t {
130+
if (c >= '0' && c <= '9') return c - '0';
131+
if (c >= 'a' && c <= 'f') return c - 'a' + 0xA;
132+
if (c >= 'A' && c <= 'F') return c - 'A' + 0xA;
133+
134+
assert(false); // Reached if ctor is called with an invalid hex digit.
135+
};
136+
137+
assert(hex_str.length() == m_data.size() * 2); // 2 hex digits per byte.
138+
auto str_it = hex_str.rbegin();
139+
for (auto& elem : m_data) {
140+
auto lo = from_hex(*(str_it++));
141+
elem = (from_hex(*(str_it++)) << 4) | lo;
142+
}
143+
}
144+
123145
namespace detail {
124146
/**
125147
* Writes the hex string (in reverse byte order) into a new uintN_t object
@@ -157,6 +179,7 @@ class uint256 : public base_blob<256> {
157179
public:
158180
static std::optional<uint256> FromHex(std::string_view str) { return detail::FromHex<uint256>(str); }
159181
constexpr uint256() = default;
182+
consteval explicit uint256(std::string_view hex_str) : base_blob<256>(hex_str) {}
160183
constexpr explicit uint256(uint8_t v) : base_blob<256>(v) {}
161184
constexpr explicit uint256(Span<const unsigned char> vch) : base_blob<256>(vch) {}
162185
static const uint256 ZERO;

0 commit comments

Comments
 (0)