Coverage Report

Created: 2026-08-14 07:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/solidity/test/evmc/hex.hpp
Line
Count
Source
1
// EVMC: Ethereum Client-VM Connector API.
2
// Copyright 2021 The EVMC Authors.
3
// Licensed under the Apache License, Version 2.0.
4
#pragma once
5
6
#include <evmc/bytes.hpp>
7
#include <evmc/filter_iterator.hpp>
8
#include <cstdint>
9
#include <optional>
10
#include <string>
11
#include <string_view>
12
13
namespace evmc
14
{
15
/// Encode a byte to a hex string.
16
inline std::string hex(uint8_t b) noexcept
17
0
{
18
0
    static constexpr auto hex_digits = "0123456789abcdef";
19
0
    return {hex_digits[b >> 4], hex_digits[b & 0xf]};
20
0
}
21
22
/// Encodes bytes as hex string.
23
inline std::string hex(bytes_view bs)
24
0
{
25
0
    std::string str;
26
0
    str.reserve(bs.size() * 2);
27
0
    for (const auto b : bs)
28
0
        str += hex(b);
29
0
    return str;
30
0
}
31
32
namespace internal
33
{
34
/// Extracts the nibble value out of a hex digit.
35
/// Returns -1 in case of invalid hex digit.
36
inline constexpr int from_hex_digit(char h) noexcept
37
97.0M
{
38
97.0M
    if (h >= '0' && h <= '9')
39
89.8M
        return h - '0';
40
7.25M
    else if (h >= 'a' && h <= 'f')
41
7.25M
        return h - 'a' + 10;
42
0
    else if (h >= 'A' && h <= 'F')
43
0
        return h - 'A' + 10;
44
0
    else
45
0
        return -1;
46
97.0M
}
47
}  // namespace internal
48
49
/// Decodes hex-encoded sequence of characters.
50
///
51
/// It is guaranteed that the output will not be longer than half of the input length.
52
///
53
/// @param begin  The input begin iterator. It only must satisfy input iterator concept.
54
/// @param end    The input end iterator. It only must satisfy input iterator concept.
55
/// @param out    The output iterator. It must satisfy output iterator concept.
56
/// @return       True if successful, false if input is invalid hex.
57
template <typename InputIt, typename OutputIt>
58
inline constexpr bool from_hex(InputIt begin, InputIt end, OutputIt out) noexcept
59
2.22M
{
60
2.22M
    int hi_nibble = -1;  // Init with invalid value, should never be used.
61
2.22M
    size_t i = 0;
62
99.2M
    for (auto it = begin; it != end; ++it, ++i)
63
97.0M
    {
64
97.0M
        const auto h = *it;
65
97.0M
        const int v = evmc::internal::from_hex_digit(h);
66
97.0M
        if (v < 0)
67
0
        {
68
0
            if (i == 1 && hi_nibble == 0 && h == 'x')  // 0x prefix
69
0
                continue;
70
0
            return false;
71
0
        }
72
73
97.0M
        if (i % 2 == 0)
74
48.5M
            hi_nibble = v << 4;
75
48.5M
        else
76
48.5M
            *out++ = static_cast<uint8_t>(hi_nibble | v);
77
97.0M
    }
78
79
2.22M
    return i % 2 == 0;
80
2.22M
}
bool evmc::from_hex<char const*, unsigned char*>(char const*, char const*, unsigned char*)
Line
Count
Source
59
2.22M
{
60
2.22M
    int hi_nibble = -1;  // Init with invalid value, should never be used.
61
2.22M
    size_t i = 0;
62
99.2M
    for (auto it = begin; it != end; ++it, ++i)
63
97.0M
    {
64
97.0M
        const auto h = *it;
65
97.0M
        const int v = evmc::internal::from_hex_digit(h);
66
97.0M
        if (v < 0)
67
0
        {
68
0
            if (i == 1 && hi_nibble == 0 && h == 'x')  // 0x prefix
69
0
                continue;
70
0
            return false;
71
0
        }
72
73
97.0M
        if (i % 2 == 0)
74
48.5M
            hi_nibble = v << 4;
75
48.5M
        else
76
48.5M
            *out++ = static_cast<uint8_t>(hi_nibble | v);
77
97.0M
    }
78
79
2.22M
    return i % 2 == 0;
80
2.22M
}
Unexecuted instantiation: bool evmc::from_hex<char const*, evmc::validate_hex(std::__1::basic_string_view<char, std::__1::char_traits<char> >)::noop_output_iterator>(char const*, char const*, evmc::validate_hex(std::__1::basic_string_view<char, std::__1::char_traits<char> >)::noop_output_iterator)
Unexecuted instantiation: bool evmc::from_hex<char const*, std::__1::back_insert_iterator<std::__1::basic_string<unsigned char, evmc::byte_traits<unsigned char>, std::__1::allocator<unsigned char> > > >(char const*, char const*, std::__1::back_insert_iterator<std::__1::basic_string<unsigned char, evmc::byte_traits<unsigned char>, std::__1::allocator<unsigned char> > >)
Unexecuted instantiation: bool evmc::from_hex<evmc::skip_space_iterator<char const*>, std::__1::back_insert_iterator<std::__1::basic_string<unsigned char, evmc::byte_traits<unsigned char>, std::__1::allocator<unsigned char> > > >(evmc::skip_space_iterator<char const*>, evmc::skip_space_iterator<char const*>, std::__1::back_insert_iterator<std::__1::basic_string<unsigned char, evmc::byte_traits<unsigned char>, std::__1::allocator<unsigned char> > >)
81
82
/// Validates hex encoded string.
83
///
84
/// @return  True if the input is valid hex.
85
inline bool validate_hex(std::string_view hex) noexcept
86
0
{
87
0
    struct noop_output_iterator
88
0
    {
89
0
        uint8_t sink = {};
90
0
        uint8_t& operator*() noexcept { return sink; }
91
0
        noop_output_iterator operator++(int) noexcept { return *this; }  // NOLINT(cert-dcl21-cpp)
92
0
    };
93
0
94
0
    return from_hex(hex.begin(), hex.end(), noop_output_iterator{});
95
0
}
96
97
/// Decodes hex encoded string to bytes.
98
///
99
/// In case the input is invalid the returned value is std::nullopt.
100
/// This can happen if a non-hex digit or odd number of digits is encountered.
101
inline std::optional<bytes> from_hex(std::string_view hex)
102
0
{
103
0
    bytes bs;
104
0
    bs.reserve(hex.size() / 2);
105
0
    if (!from_hex(hex.begin(), hex.end(), std::back_inserter(bs)))
106
0
        return {};
107
0
    return bs;
108
0
}
109
110
/// Decodes hex-encoded string into custom type T with .bytes array of uint8_t.
111
///
112
/// When the input is smaller than the result type, the result is padded with zeros on the left
113
/// (the result bytes of lowest indices are filled with zeros).
114
/// TODO: Support optional left alignment.
115
template <typename T>
116
constexpr std::optional<T> from_hex(std::string_view s) noexcept
117
2.22M
{
118
    // Omit the optional 0x prefix.
119
2.22M
    if (s.size() >= 2 && s[0] == '0' && s[1] == 'x')
120
2.22M
        s.remove_prefix(2);
121
122
2.22M
    T r{};  // The T must have .bytes array. This may be lifted if std::bit_cast is available.
123
2.22M
    constexpr auto num_out_bytes = std::size(r.bytes);
124
2.22M
    const auto num_in_bytes = s.length() / 2;
125
2.22M
    if (num_in_bytes > num_out_bytes)
126
0
        return {};
127
2.22M
    if (!from_hex(s.begin(), s.end(), &r.bytes[num_out_bytes - num_in_bytes]))
128
0
        return {};
129
2.22M
    return r;
130
2.22M
}
std::__1::optional<evmc::bytes32> evmc::from_hex<evmc::bytes32>(std::__1::basic_string_view<char, std::__1::char_traits<char> >)
Line
Count
Source
117
327k
{
118
    // Omit the optional 0x prefix.
119
327k
    if (s.size() >= 2 && s[0] == '0' && s[1] == 'x')
120
327k
        s.remove_prefix(2);
121
122
327k
    T r{};  // The T must have .bytes array. This may be lifted if std::bit_cast is available.
123
327k
    constexpr auto num_out_bytes = std::size(r.bytes);
124
327k
    const auto num_in_bytes = s.length() / 2;
125
327k
    if (num_in_bytes > num_out_bytes)
126
0
        return {};
127
327k
    if (!from_hex(s.begin(), s.end(), &r.bytes[num_out_bytes - num_in_bytes]))
128
0
        return {};
129
327k
    return r;
130
327k
}
std::__1::optional<evmc::address> evmc::from_hex<evmc::address>(std::__1::basic_string_view<char, std::__1::char_traits<char> >)
Line
Count
Source
117
1.90M
{
118
    // Omit the optional 0x prefix.
119
1.90M
    if (s.size() >= 2 && s[0] == '0' && s[1] == 'x')
120
1.90M
        s.remove_prefix(2);
121
122
1.90M
    T r{};  // The T must have .bytes array. This may be lifted if std::bit_cast is available.
123
1.90M
    constexpr auto num_out_bytes = std::size(r.bytes);
124
1.90M
    const auto num_in_bytes = s.length() / 2;
125
1.90M
    if (num_in_bytes > num_out_bytes)
126
0
        return {};
127
1.90M
    if (!from_hex(s.begin(), s.end(), &r.bytes[num_out_bytes - num_in_bytes]))
128
0
        return {};
129
1.90M
    return r;
130
1.90M
}
131
132
/// Decodes hex encoded string to bytes. The whitespace in the input is ignored.
133
///
134
/// In case the input is invalid the returned value is std::nullopt.
135
/// This can happen if a non-hex digit or odd number of digits is encountered.
136
/// The whitespace (as defined by std::isspace) in the input is ignored.
137
template <typename InputIterator>
138
std::optional<bytes> from_spaced_hex(InputIterator begin, InputIterator end) noexcept
139
0
{
140
0
    bytes bs;
141
0
    if (!from_hex(skip_space_iterator{begin, end}, skip_space_iterator{end, end},
142
0
                  std::back_inserter(bs)))
143
0
        return {};
144
0
    return bs;
145
0
}
146
147
/// @copydoc from_spaced_hex
148
inline std::optional<bytes> from_spaced_hex(std::string_view hex) noexcept
149
0
{
150
0
    return from_spaced_hex(hex.begin(), hex.end());
151
0
}
152
}  // namespace evmc