#pragma once #include #include #include #include #include // 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(c)] = static_cast(c - '0'); } for (char c = 'a'; c <= 'f'; ++c) { values[static_cast(c)] = static_cast(c - 'a' + 10); } for (char c = 'A'; c <= 'F'; ++c) { values[static_cast(c)] = static_cast(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(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 &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> hex_decode(const std::string &hex) { if (hex.size() % 2U != 0U) { return tl::nullopt; } std::vector result; result.reserve(hex.size() / 2U); for (std::size_t i = 0; i < hex.size(); i += 2U) { auto high = kHexDecode.values[static_cast(hex[i])]; auto low = kHexDecode.values[static_cast(hex[i + 1U])]; if (high < 0 || low < 0) { return tl::nullopt; } result.push_back(static_cast((high << 4) | low)); } return result; }