Files
tqcq 41a30573f6
cpp-template / format (ubuntu-22.04) (push) Successful in 1m5s
cpp-template / format (ubuntu-24.04) (push) Successful in 1m6s
cpp-template / build-test (asan, ubuntu-22.04) (push) Successful in 1m48s
cpp-template / build-test (asan, ubuntu-24.04) (push) Successful in 1m53s
cpp-template / build-test (debug, ubuntu-22.04) (push) Successful in 2m11s
cpp-template / build-test (debug, ubuntu-24.04) (push) Successful in 2m16s
cpp-template / build-test (fuzz, ubuntu-22.04) (push) Successful in 7m55s
cpp-template / build-test (fuzz, ubuntu-24.04) (push) Successful in 8m14s
cpp-template / build-test (release, ubuntu-22.04) (push) Successful in 2m13s
cpp-template / build-test (release, ubuntu-24.04) (push) Successful in 2m11s
cpp-template / clang-tidy (ubuntu-22.04) (push) Successful in 1m53s
cpp-template / clang-tidy (ubuntu-24.04) (push) Successful in 1m59s
cpp-template / install-consumer (ubuntu-22.04) (push) Successful in 1m43s
cpp-template / install-consumer (ubuntu-24.04) (push) Successful in 1m45s
cpp-template / no-network-negative (ubuntu-22.04) (push) Successful in 7m9s
cpp-template / no-network-negative (ubuntu-24.04) (push) Successful in 7m24s
cpp-template / format (ubuntu-20.04) (push) Has been cancelled
cpp-template / build-test (asan, ubuntu-20.04) (push) Has been cancelled
cpp-template / build-test (debug, ubuntu-20.04) (push) Has been cancelled
cpp-template / build-test (fuzz, ubuntu-20.04) (push) Has been cancelled
cpp-template / build-test (release, ubuntu-20.04) (push) Has been cancelled
cpp-template / clang-tidy (ubuntu-20.04) (push) Has been cancelled
cpp-template / install-consumer (ubuntu-20.04) (push) Has been cancelled
cpp-template / no-network-negative (ubuntu-20.04) (push) Has been cancelled
feat: improve hex encode input ergonomics
2026-05-20 17:07:17 +08:00

74 lines
2.2 KiB
C++

#pragma once
#include <cstddef>
#include <cstdint>
#include <string>
#include <vector>
#include <tl/optional.hpp>
// Compile-time lookup table for decoding hex characters to their 0-15 value,
// or -1 for invalid characters.
struct HexDecodeTable
{
std::int8_t values[256];
constexpr HexDecodeTable() : values{}
{
for (auto &v : values) {
v = -1;
}
for (char c = '0'; c <= '9'; ++c) {
values[static_cast<std::size_t>(c)] = static_cast<std::int8_t>(c - '0');
}
for (char c = 'a'; c <= 'f'; ++c) {
values[static_cast<std::size_t>(c)] = static_cast<std::int8_t>(c - 'a' + 10);
}
for (char c = 'A'; c <= 'F'; ++c) {
values[static_cast<std::size_t>(c)] = static_cast<std::int8_t>(c - 'A' + 10);
}
}
};
namespace
{
const HexDecodeTable kHexDecode;
} // namespace
inline std::string hex_encode(const void *data, std::size_t len)
{
const auto *bytes = static_cast<const std::uint8_t *>(data);
static constexpr char kHexChars[] = "0123456789abcdef";
std::string result;
result.reserve(len * 2U);
for (std::size_t i = 0; i < len; ++i) {
result.push_back(kHexChars[(bytes[i] >> 4U) & 0x0FU]);
result.push_back(kHexChars[bytes[i] & 0x0FU]);
}
return result;
}
inline std::string hex_encode(const std::string &data) { return hex_encode(data.data(), data.size()); }
inline std::string hex_encode(const std::vector<std::uint8_t> &data) { return hex_encode(data.data(), data.size()); }
// Returns decoded bytes, or tl::nullopt on invalid input (odd length or
// non-hex characters).
inline tl::optional<std::vector<std::uint8_t>> hex_decode(const std::string &hex)
{
if (hex.size() % 2U != 0U) {
return tl::nullopt;
}
std::vector<std::uint8_t> result;
result.reserve(hex.size() / 2U);
for (std::size_t i = 0; i < hex.size(); i += 2U) {
auto high = kHexDecode.values[static_cast<std::uint8_t>(hex[i])];
auto low = kHexDecode.values[static_cast<std::uint8_t>(hex[i + 1U])];
if (high < 0 || low < 0) {
return tl::nullopt;
}
result.push_back(static_cast<std::uint8_t>((high << 4) | low));
}
return result;
}