Skip to content

Commit

Permalink
C++: Rework hex literals parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
chfast committed May 13, 2022
1 parent 1366a05 commit deff644
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 55 deletions.
67 changes: 16 additions & 51 deletions include/evmc/evmc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <evmc/evmc.h>
#include <evmc/helpers.h>
#include <evmc/hex.hpp>

#include <functional>
#include <initializer_list>
Expand Down Expand Up @@ -280,71 +281,35 @@ inline constexpr bytes32::operator bool() const noexcept

namespace literals
{
namespace internal
{
constexpr int from_hex(char c) noexcept
{
return (c >= 'a' && c <= 'f') ? c - ('a' - 10) :
(c >= 'A' && c <= 'F') ? c - ('A' - 10) :
c - '0';
}

constexpr uint8_t byte(const char* s, size_t i) noexcept
{
return static_cast<uint8_t>((from_hex(s[2 * i]) << 4) | from_hex(s[2 * i + 1]));
}
inline void error(const char*) noexcept {}

template <typename T>
T from_hex(const char*) noexcept;

template <>
constexpr bytes32 from_hex<bytes32>(const char* s) noexcept
{
return {
{{byte(s, 0), byte(s, 1), byte(s, 2), byte(s, 3), byte(s, 4), byte(s, 5), byte(s, 6),
byte(s, 7), byte(s, 8), byte(s, 9), byte(s, 10), byte(s, 11), byte(s, 12), byte(s, 13),
byte(s, 14), byte(s, 15), byte(s, 16), byte(s, 17), byte(s, 18), byte(s, 19), byte(s, 20),
byte(s, 21), byte(s, 22), byte(s, 23), byte(s, 24), byte(s, 25), byte(s, 26), byte(s, 27),
byte(s, 28), byte(s, 29), byte(s, 30), byte(s, 31)}}};
}

template <>
constexpr address from_hex<address>(const char* s) noexcept
inline constexpr T to(std::string_view s) noexcept
{
return {
{{byte(s, 0), byte(s, 1), byte(s, 2), byte(s, 3), byte(s, 4), byte(s, 5), byte(s, 6),
byte(s, 7), byte(s, 8), byte(s, 9), byte(s, 10), byte(s, 11), byte(s, 12), byte(s, 13),
byte(s, 14), byte(s, 15), byte(s, 16), byte(s, 17), byte(s, 18), byte(s, 19)}}};
}
if (s == "0")
return T{};

template <typename T, char... c>
constexpr T from_literal() noexcept
{
constexpr auto size = sizeof...(c);
constexpr char literal[] = {c...};
constexpr bool is_simple_zero = size == 1 && literal[0] == '0';
if (s[0] != '0' || s[1] != 'x')
error("literal must be in hexadecimal notation");

static_assert(is_simple_zero || (literal[0] == '0' && literal[1] == 'x'),
"literal must be in hexadecimal notation");
static_assert(is_simple_zero || size == 2 * sizeof(T) + 2,
"literal must match the result type size");
if (s.length() != 2 * sizeof(T) + 2)
error("literal must match the result type size");

return is_simple_zero ? T{} : from_hex<T>(&literal[2]);
T r{};
internal::from_hex(s, r.bytes);
return r;
}
} // namespace internal

/// Literal for evmc::address.
template <char... c>
constexpr address operator""_address() noexcept
constexpr address operator""_address(const char* s) noexcept
{
return internal::from_literal<address, c...>();
return to<address>(s);
}

/// Literal for evmc::bytes32.
template <char... c>
constexpr bytes32 operator""_bytes32() noexcept
constexpr bytes32 operator""_bytes32(const char* s) noexcept
{
return internal::from_literal<bytes32, c...>();
return to<bytes32>(s);
}
} // namespace literals

Expand Down
8 changes: 4 additions & 4 deletions include/evmc/hex.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ inline std::string hex(bytes_view bs)
return str;
}

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

return b == empty_byte_mark;
}
} // namespace internal_hex
} // namespace internal

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

return internal_hex::from_hex(hex, noop_output_iterator{});
return internal::from_hex(hex, noop_output_iterator{});
}

/// Decodes hex encoded string to bytes.
Expand All @@ -114,7 +114,7 @@ inline std::optional<bytes> from_hex(std::string_view hex)
{
bytes bs;
bs.reserve(hex.size() / 2);
if (!internal_hex::from_hex(hex, std::back_inserter(bs)))
if (!internal::from_hex(hex, std::back_inserter(bs)))
return {};
return bs;
}
Expand Down

0 comments on commit deff644

Please sign in to comment.