From ee3abdbe6f116bf8072fb8ba5218d278c8449da8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 12 May 2022 22:54:08 +0200 Subject: [PATCH] C++: Rework hex literals parsing --- include/evmc/evmc.hpp | 69 +++++++++++-------------------------------- include/evmc/hex.hpp | 8 ++--- 2 files changed, 22 insertions(+), 55 deletions(-) diff --git a/include/evmc/evmc.hpp b/include/evmc/evmc.hpp index 57f0faa9d..7afffacd4 100644 --- a/include/evmc/evmc.hpp +++ b/include/evmc/evmc.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -280,71 +281,37 @@ 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((from_hex(s[2 * i]) << 4) | from_hex(s[2 * i + 1])); -} +/// Breaks compilation and reports error string in constexpr context. +inline void error([[maybe_unused]] const char* message) noexcept {} +/// Converts a raw literal into value of type T. template -T from_hex(const char*) noexcept; - -template <> -constexpr bytes32 from_hex(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
(const char* s) noexcept +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 -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(&literal[2]); + T r{}; + internal::from_hex(s, r.bytes); + return r; } -} // namespace internal /// Literal for evmc::address. -template -constexpr address operator""_address() noexcept +constexpr address operator""_address(const char* s) noexcept { - return internal::from_literal(); + return to
(s); } /// Literal for evmc::bytes32. -template -constexpr bytes32 operator""_bytes32() noexcept +constexpr bytes32 operator""_bytes32(const char* s) noexcept { - return internal::from_literal(); + return to(s); } } // namespace literals diff --git a/include/evmc/hex.hpp b/include/evmc/hex.hpp index 1a6ee4fec..47cd61413 100644 --- a/include/evmc/hex.hpp +++ b/include/evmc/hex.hpp @@ -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. @@ -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. /// @@ -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. @@ -114,7 +114,7 @@ inline std::optional 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; }