mirror of https://github.com/status-im/evmc.git
Merge pull request #491 from ethereum/literals
cpp: Replace literals implementation with constexpr functions
This commit is contained in:
commit
5d456034d6
|
@ -255,108 +255,72 @@ namespace literals
|
|||
{
|
||||
namespace internal
|
||||
{
|
||||
template <typename T, T...>
|
||||
struct sequence
|
||||
constexpr size_t length(const char* s) noexcept
|
||||
{
|
||||
};
|
||||
|
||||
template <uint8_t... Bytes>
|
||||
using byte_sequence = sequence<uint8_t, Bytes...>;
|
||||
|
||||
template <char... Chars>
|
||||
using char_sequence = sequence<char, Chars...>;
|
||||
|
||||
|
||||
template <typename, typename>
|
||||
struct concatenate;
|
||||
|
||||
template <uint8_t... Bytes1, uint8_t... Bytes2>
|
||||
struct concatenate<byte_sequence<Bytes1...>, byte_sequence<Bytes2...>>
|
||||
{
|
||||
using type = byte_sequence<Bytes1..., Bytes2...>;
|
||||
};
|
||||
|
||||
template <uint8_t D>
|
||||
constexpr uint8_t parse_hex_digit() noexcept
|
||||
{
|
||||
static_assert((D >= '0' && D <= '9') || (D >= 'a' && D <= 'f') || (D >= 'A' && D <= 'F'),
|
||||
"literal must be hexadecimal integer");
|
||||
return static_cast<uint8_t>(
|
||||
(D >= '0' && D <= '9') ? D - '0' : (D >= 'a' && D <= 'f') ? D - 'a' + 10 : D - 'A' + 10);
|
||||
return (*s != '\0') ? length(s + 1) + 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
template <typename>
|
||||
struct parse_digits;
|
||||
|
||||
template <uint8_t Digit1, uint8_t Digit2>
|
||||
struct parse_digits<byte_sequence<Digit1, Digit2>>
|
||||
constexpr int from_hex(char c) noexcept
|
||||
{
|
||||
using type = byte_sequence<static_cast<uint8_t>(parse_hex_digit<Digit1>() << 4) |
|
||||
parse_hex_digit<Digit2>()>;
|
||||
};
|
||||
return (c >= 'a' && c <= 'f') ? c - ('a' - 10) :
|
||||
(c >= 'A' && c <= 'F') ? c - ('A' - 10) : c - '0';
|
||||
}
|
||||
|
||||
template <uint8_t Digit1, uint8_t Digit2, uint8_t... Rest>
|
||||
struct parse_digits<byte_sequence<Digit1, Digit2, Rest...>>
|
||||
constexpr uint8_t byte(const char* s, size_t i) noexcept
|
||||
{
|
||||
using type = typename concatenate<typename parse_digits<byte_sequence<Digit1, Digit2>>::type,
|
||||
typename parse_digits<byte_sequence<Rest...>>::type>::type;
|
||||
};
|
||||
return static_cast<uint8_t>((from_hex(s[2 * i]) << 4) | from_hex(s[2 * i + 1]));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T from_hex(const char*) noexcept;
|
||||
|
||||
template <typename, typename>
|
||||
struct parse_literal;
|
||||
|
||||
template <typename T, char Prefix1, char Prefix2, char... Literal>
|
||||
struct parse_literal<T, char_sequence<Prefix1, Prefix2, Literal...>>
|
||||
template <>
|
||||
constexpr bytes32 from_hex<bytes32>(const char* s) noexcept
|
||||
{
|
||||
static_assert(Prefix1 == '0' && Prefix2 == 'x', "literal must be in hexadecimal notation");
|
||||
static_assert(sizeof...(Literal) == sizeof(T) * 2, "literal must match the result type size");
|
||||
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 <uint8_t... Bytes>
|
||||
static constexpr T create_from(byte_sequence<Bytes...>) noexcept
|
||||
{
|
||||
return T{{{Bytes...}}};
|
||||
}
|
||||
|
||||
static constexpr T get() noexcept
|
||||
{
|
||||
return create_from(typename parse_digits<byte_sequence<Literal...>>::type{});
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, char Digit>
|
||||
struct parse_literal<T, char_sequence<Digit>>
|
||||
template <>
|
||||
constexpr address from_hex<address>(const char* s) noexcept
|
||||
{
|
||||
static_assert(Digit == '0', "only 0 is allowed as a single digit literal");
|
||||
static constexpr T get() noexcept { return {}; }
|
||||
};
|
||||
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)}}};
|
||||
}
|
||||
|
||||
template <typename T, char... Literal>
|
||||
constexpr T parse() noexcept
|
||||
template <typename T>
|
||||
constexpr T from_literal(const char* s)
|
||||
{
|
||||
return parse_literal<T, char_sequence<Literal...>>::get();
|
||||
return (s[0] == '0' && s[1] == '\0') ?
|
||||
T{} :
|
||||
!(s[0] == '0' && s[1] == 'x') ?
|
||||
throw "literal must be in hexadecimal notation" :
|
||||
(length(s + 2) != sizeof(T) * 2) ? throw "literal must match the result type size" :
|
||||
from_hex<T>(s + 2);
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
/// Literal for evmc::address.
|
||||
template <char... Literal>
|
||||
constexpr address operator"" _address() noexcept
|
||||
constexpr address operator""_address(const char* s) noexcept
|
||||
{
|
||||
return internal::parse<address, Literal...>();
|
||||
return internal::from_literal<address>(s);
|
||||
}
|
||||
|
||||
/// Literal for evmc::bytes32.
|
||||
template <char... Literal>
|
||||
constexpr bytes32 operator"" _bytes32() noexcept
|
||||
constexpr bytes32 operator""_bytes32(const char* s) noexcept
|
||||
{
|
||||
return internal::parse<bytes32, Literal...>();
|
||||
return internal::from_literal<bytes32>(s);
|
||||
}
|
||||
} // namespace literals
|
||||
|
||||
using namespace literals;
|
||||
|
||||
|
||||
/// Alias for evmc_make_result().
|
||||
constexpr auto make_result = evmc_make_result;
|
||||
|
||||
|
|
Loading…
Reference in New Issue