Skip to content

Commit ee3abdb

Browse files
committed
C++: Rework hex literals parsing
1 parent 1366a05 commit ee3abdb

File tree

2 files changed

+22
-55
lines changed

2 files changed

+22
-55
lines changed

include/evmc/evmc.hpp

Lines changed: 18 additions & 51 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,37 @@ 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-
}
284+
/// Breaks compilation and reports error string in constexpr context.
285+
inline void error([[maybe_unused]] const char* message) noexcept {}
296286

287+
/// Converts a raw literal into value of type T.
297288
template <typename T>
298-
T from_hex(const char*) noexcept;
299-
300-
template <>
301-
constexpr bytes32 from_hex<bytes32>(const char* s) noexcept
302-
{
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)}}};
309-
}
310-
311-
template <>
312-
constexpr address from_hex<address>(const char* s) noexcept
289+
constexpr T to(std::string_view s) noexcept
313290
{
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-
}
291+
if (s == "0")
292+
return T{};
319293

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';
294+
if (s[0] != '0' || s[1] != 'x')
295+
error("literal must be in hexadecimal notation");
326296

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");
297+
if (s.length() != 2 * sizeof(T) + 2)
298+
error("literal must match the result type size");
331299

332-
return is_simple_zero ? T{} : from_hex<T>(&literal[2]);
300+
T r{};
301+
internal::from_hex(s, r.bytes);
302+
return r;
333303
}
334-
} // namespace internal
335304

336305
/// Literal for evmc::address.
337-
template <char... c>
338-
constexpr address operator""_address() noexcept
306+
constexpr address operator""_address(const char* s) noexcept
339307
{
340-
return internal::from_literal<address, c...>();
308+
return to<address>(s);
341309
}
342310

343311
/// Literal for evmc::bytes32.
344-
template <char... c>
345-
constexpr bytes32 operator""_bytes32() noexcept
312+
constexpr bytes32 operator""_bytes32(const char* s) noexcept
346313
{
347-
return internal::from_literal<bytes32, c...>();
314+
return to<bytes32>(s);
348315
}
349316
} // namespace literals
350317

include/evmc/hex.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ inline std::string hex(bytes_view bs)
3535
return str;
3636
}
3737

38-
namespace internal_hex
38+
namespace internal
3939
{
4040
/// Extracts the nibble value out of a hex digit.
4141
/// Returns -1 in case of invalid hex degit.
@@ -88,7 +88,7 @@ inline constexpr bool from_hex(std::string_view hex, OutputIt result) noexcept
8888

8989
return b == empty_byte_mark;
9090
}
91-
} // namespace internal_hex
91+
} // namespace internal
9292

9393
/// Validates hex encoded string.
9494
///
@@ -102,7 +102,7 @@ inline bool validate_hex(std::string_view hex) noexcept
102102
noop_output_iterator operator++(int) noexcept { return *this; } // NOLINT(cert-dcl21-cpp)
103103
};
104104

105-
return internal_hex::from_hex(hex, noop_output_iterator{});
105+
return internal::from_hex(hex, noop_output_iterator{});
106106
}
107107

108108
/// Decodes hex encoded string to bytes.
@@ -114,7 +114,7 @@ inline std::optional<bytes> from_hex(std::string_view hex)
114114
{
115115
bytes bs;
116116
bs.reserve(hex.size() / 2);
117-
if (!internal_hex::from_hex(hex, std::back_inserter(bs)))
117+
if (!internal::from_hex(hex, std::back_inserter(bs)))
118118
return {};
119119
return bs;
120120
}

0 commit comments

Comments
 (0)