EVMC
hex.hpp
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/filter_iterator.hpp>
7#include <cstdint>
8#include <optional>
9#include <string>
10#include <string_view>
11
12namespace evmc
13{
15using bytes = std::basic_string<uint8_t>;
16
18using bytes_view = std::basic_string_view<uint8_t>;
19
20
22inline std::string hex(uint8_t b) noexcept
23{
24 static constexpr auto hex_digits = "0123456789abcdef";
25 return {hex_digits[b >> 4], hex_digits[b & 0xf]};
26}
27
29inline std::string hex(bytes_view bs)
30{
31 std::string str;
32 str.reserve(bs.size() * 2);
33 for (const auto b : bs)
34 str += hex(b);
35 return str;
36}
37
38namespace internal
39{
42inline constexpr int from_hex_digit(char h) noexcept
43{
44 if (h >= '0' && h <= '9')
45 return h - '0';
46 else if (h >= 'a' && h <= 'f')
47 return h - 'a' + 10;
48 else if (h >= 'A' && h <= 'F')
49 return h - 'A' + 10;
50 else
51 return -1;
52}
53} // namespace internal
54
63template <typename InputIt, typename OutputIt>
64inline constexpr bool from_hex(InputIt begin, InputIt end, OutputIt out) noexcept
65{
66 int hi_nibble = -1; // Init with invalid value, should never be used.
67 size_t i = 0;
68 for (auto it = begin; it != end; ++it, ++i)
69 {
70 const auto h = *it;
71 const int v = evmc::internal::from_hex_digit(h);
72 if (v < 0)
73 {
74 if (i == 1 && hi_nibble == 0 && h == 'x') // 0x prefix
75 continue;
76 return false;
77 }
78
79 if (i % 2 == 0)
80 hi_nibble = v << 4;
81 else
82 *out++ = static_cast<uint8_t>(hi_nibble | v);
83 }
84
85 return i % 2 == 0;
86}
87
91inline bool validate_hex(std::string_view hex) noexcept
92{
93 struct noop_output_iterator
94 {
95 uint8_t sink = {};
96 uint8_t& operator*() noexcept { return sink; }
97 noop_output_iterator operator++(int) noexcept { return *this; } // NOLINT(cert-dcl21-cpp)
98 };
99
100 return from_hex(hex.begin(), hex.end(), noop_output_iterator{});
101}
102
107inline std::optional<bytes> from_hex(std::string_view hex)
108{
109 bytes bs;
110 bs.reserve(hex.size() / 2);
111 if (!from_hex(hex.begin(), hex.end(), std::back_inserter(bs)))
112 return {};
113 return bs;
114}
115
121template <typename T>
122constexpr std::optional<T> from_hex(std::string_view s) noexcept
123{
124 // Omit the optional 0x prefix.
125 if (s.size() >= 2 && s[0] == '0' && s[1] == 'x')
126 s.remove_prefix(2);
127
128 T r{}; // The T must have .bytes array. This may be lifted if std::bit_cast is available.
129 constexpr auto num_out_bytes = std::size(r.bytes);
130 const auto num_in_bytes = s.length() / 2;
131 if (num_in_bytes > num_out_bytes)
132 return {};
133 if (!from_hex(s.begin(), s.end(), &r.bytes[num_out_bytes - num_in_bytes]))
134 return {};
135 return r;
136}
137
143template <typename InputIterator>
144std::optional<bytes> from_spaced_hex(InputIterator begin, InputIterator end) noexcept
145{
146 bytes bs;
147 if (!from_hex(skip_space_iterator{begin, end}, skip_space_iterator{end, end},
148 std::back_inserter(bs)))
149 return {};
150 return bs;
151}
152
154inline std::optional<bytes> from_spaced_hex(std::string_view hex) noexcept
155{
156 return from_spaced_hex(hex.begin(), hex.end());
157}
158} // namespace evmc
EVMC C++ API - wrappers and bindings for C++.
Definition: evmc.hpp:22
std::basic_string< uint8_t > bytes
String of uint8_t chars.
Definition: hex.hpp:15
std::string hex(uint8_t b) noexcept
Encode a byte to a hex string.
Definition: hex.hpp:22
bool validate_hex(std::string_view hex) noexcept
Validates hex encoded string.
Definition: hex.hpp:91
constexpr bool from_hex(InputIt begin, InputIt end, OutputIt out) noexcept
Decodes hex-encoded sequence of characters.
Definition: hex.hpp:64
std::basic_string_view< uint8_t > bytes_view
String view of uint8_t chars.
Definition: evmc.hpp:24
std::optional< bytes > from_spaced_hex(InputIterator begin, InputIterator end) noexcept
Decodes hex encoded string to bytes.
Definition: hex.hpp:144
The input filter iterator which skips whitespace characters from the base input iterator.