Skip to content

Commit 4fa9b27

Browse files
committed
C++: Rework hex literals parsing
1 parent a573243 commit 4fa9b27

File tree

2 files changed

+22
-57
lines changed

2 files changed

+22
-57
lines changed

include/evmc/evmc.hpp

Lines changed: 10 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <evmc/evmc.h>
77
#include <evmc/helpers.h>
8+
#include <evmc/hex.hpp>
89

910
#include <functional>
1011
#include <initializer_list>
@@ -280,71 +281,25 @@ inline constexpr bytes32::operator bool() const noexcept
280281

281282
namespace literals
282283
{
283-
namespace internal
284-
{
285-
constexpr int from_hex(char c) noexcept
286-
{
287-
return (c >= 'a' && c <= 'f') ? c - ('a' - 10) :
288-
(c >= 'A' && c <= 'F') ? c - ('A' - 10) :
289-
c - '0';
290-
}
291-
292-
constexpr uint8_t byte(const char* s, size_t i) noexcept
293-
{
294-
return static_cast<uint8_t>((from_hex(s[2 * i]) << 4) | from_hex(s[2 * i + 1]));
295-
}
296-
284+
/// Converts a raw literal into value of type T.
285+
///
286+
/// This function is expected to be used on literals in constexpr context only.
297287
template <typename T>
298-
T from_hex(const char*) noexcept;
299-
300-
template <>
301-
constexpr bytes32 from_hex<bytes32>(const char* s) noexcept
288+
constexpr T parse(std::string_view s) noexcept
302289
{
303-
return {
304-
{{byte(s, 0), byte(s, 1), byte(s, 2), byte(s, 3), byte(s, 4), byte(s, 5), byte(s, 6),
305-
byte(s, 7), byte(s, 8), byte(s, 9), byte(s, 10), byte(s, 11), byte(s, 12), byte(s, 13),
306-
byte(s, 14), byte(s, 15), byte(s, 16), byte(s, 17), byte(s, 18), byte(s, 19), byte(s, 20),
307-
byte(s, 21), byte(s, 22), byte(s, 23), byte(s, 24), byte(s, 25), byte(s, 26), byte(s, 27),
308-
byte(s, 28), byte(s, 29), byte(s, 30), byte(s, 31)}}};
290+
return (s == "0") ? T{} : from_hex<T>(s).value();
309291
}
310292

311-
template <>
312-
constexpr address from_hex<address>(const char* s) noexcept
313-
{
314-
return {
315-
{{byte(s, 0), byte(s, 1), byte(s, 2), byte(s, 3), byte(s, 4), byte(s, 5), byte(s, 6),
316-
byte(s, 7), byte(s, 8), byte(s, 9), byte(s, 10), byte(s, 11), byte(s, 12), byte(s, 13),
317-
byte(s, 14), byte(s, 15), byte(s, 16), byte(s, 17), byte(s, 18), byte(s, 19)}}};
318-
}
319-
320-
template <typename T, char... c>
321-
constexpr T from_literal() noexcept
322-
{
323-
constexpr auto size = sizeof...(c);
324-
constexpr char literal[] = {c...};
325-
constexpr bool is_simple_zero = size == 1 && literal[0] == '0';
326-
327-
static_assert(is_simple_zero || (literal[0] == '0' && literal[1] == 'x'),
328-
"literal must be in hexadecimal notation");
329-
static_assert(is_simple_zero || size == 2 * sizeof(T) + 2,
330-
"literal must match the result type size");
331-
332-
return is_simple_zero ? T{} : from_hex<T>(&literal[2]);
333-
}
334-
} // namespace internal
335-
336293
/// Literal for evmc::address.
337-
template <char... c>
338-
constexpr address operator""_address() noexcept
294+
constexpr address operator""_address(const char* s) noexcept
339295
{
340-
return internal::from_literal<address, c...>();
296+
return parse<address>(s);
341297
}
342298

343299
/// Literal for evmc::bytes32.
344-
template <char... c>
345-
constexpr bytes32 operator""_bytes32() noexcept
300+
constexpr bytes32 operator""_bytes32(const char* s) noexcept
346301
{
347-
return internal::from_literal<bytes32, c...>();
302+
return parse<bytes32>(s);
348303
}
349304
} // namespace literals
350305

test/unittests/cpp_test.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,10 @@ TEST(cpp, literals)
361361
static_assert(zero_address == evmc::address{});
362362
static_assert(zero_hash == evmc::bytes32{});
363363

364+
static_assert(0x00_address == 0x0000000000000000000000000000000000000000_address);
365+
static_assert(0x01_address == 0x0000000000000000000000000000000000000001_address);
366+
static_assert(0xf101_address == 0x000000000000000000000000000000000000f101_address);
367+
364368
EXPECT_EQ(0_address, evmc::address{});
365369
EXPECT_EQ(0_bytes32, evmc::bytes32{});
366370

@@ -820,7 +824,10 @@ TEST(cpp, status_code_to_string)
820824

821825
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
822826
#define TEST_CASE(NAME) \
823-
TestCase { NAME, #NAME }
827+
TestCase \
828+
{ \
829+
NAME, #NAME \
830+
}
824831
constexpr TestCase test_cases[]{
825832
TEST_CASE(EVMC_SUCCESS),
826833
TEST_CASE(EVMC_FAILURE),
@@ -871,7 +878,10 @@ TEST(cpp, revision_to_string)
871878

872879
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
873880
#define TEST_CASE(NAME) \
874-
TestCase { NAME, #NAME }
881+
TestCase \
882+
{ \
883+
NAME, #NAME \
884+
}
875885
constexpr TestCase test_cases[]{
876886
TEST_CASE(EVMC_FRONTIER),
877887
TEST_CASE(EVMC_HOMESTEAD),

0 commit comments

Comments
 (0)