mirror of https://github.com/oxen-io/oxen-mq.git
Make lokimq::is_hex check for size being a multiple of 2
`is_hex()` is a bit misleading as `from_hex()` requires an even-length hex string, but `is_hex()` also allows odd-length hex strings, which means currently callers should be doing `if (lokimq::is_hex(str) && str.size() % 2 == 0)`, but probably aren't. Since the main point of `lokimq/hex.h` is for byte<->hex conversions it doesn't make much sense to allow `is_hex()` to return true for something that can't be validly decoded via `from_hex()`, thus this PR changes it to return false. If someone *really* wants to test for an odd-length hex string (though I'm skeptical that there is a need for this), this also exposes `is_hex_digit` so that they could use: bool all_hex = std::all_of(str.begin(), str.end(), lokimq::is_hex_digit<char>)
This commit is contained in:
parent
178bd4f674
commit
90701e5d62
28
lokimq/hex.h
28
lokimq/hex.h
|
@ -87,14 +87,31 @@ template <typename CharT>
|
|||
std::string to_hex(std::basic_string_view<CharT> s) { return to_hex(s.begin(), s.end()); }
|
||||
inline std::string to_hex(std::string_view s) { return to_hex<>(s); }
|
||||
|
||||
/// Returns true if all elements in the range are hex characters
|
||||
/// Returns true if the given value is a valid hex digit.
|
||||
template <typename CharT>
|
||||
constexpr bool is_hex_digit(CharT c) {
|
||||
static_assert(sizeof(CharT) == 1, "is_hex requires chars/bytes");
|
||||
return detail::hex_lut.from_hex(static_cast<unsigned char>(c)) != 0 || static_cast<unsigned char>(c) == '0';
|
||||
}
|
||||
|
||||
/// Returns true if all elements in the range are hex characters *and* the string length is a
|
||||
/// multiple of 2, and thus suitable to pass to from_hex().
|
||||
template <typename It>
|
||||
constexpr bool is_hex(It begin, It end) {
|
||||
static_assert(sizeof(decltype(*begin)) == 1, "is_hex requires chars/bytes");
|
||||
constexpr bool ra = std::is_base_of_v<std::random_access_iterator_tag, typename std::iterator_traits<It>::iterator_category>;
|
||||
if constexpr (ra)
|
||||
if (std::distance(begin, end) % 2 != 0)
|
||||
return false;
|
||||
|
||||
size_t count = 0;
|
||||
for (; begin != end; ++begin) {
|
||||
if (detail::hex_lut.from_hex(static_cast<unsigned char>(*begin)) == 0 && static_cast<unsigned char>(*begin) != '0')
|
||||
if constexpr (!ra) ++count;
|
||||
if (!is_hex_digit(*begin))
|
||||
return false;
|
||||
}
|
||||
if constexpr (!ra)
|
||||
return count % 2 == 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -112,12 +129,13 @@ constexpr char from_hex_digit(unsigned char x) noexcept {
|
|||
constexpr char from_hex_pair(unsigned char a, unsigned char b) noexcept { return (from_hex_digit(a) << 4) | from_hex_digit(b); }
|
||||
|
||||
/// Converts a sequence of hex digits to bytes. Undefined behaviour if any characters are not in
|
||||
/// [0-9a-fA-F] or if the input sequence length is not even. It is permitted for the input and
|
||||
/// output ranges to overlap as long as out is no earlier than begin.
|
||||
/// [0-9a-fA-F] or if the input sequence length is not even: call `is_hex` first if you need to
|
||||
/// check. It is permitted for the input and output ranges to overlap as long as out is no earlier
|
||||
/// than begin.
|
||||
template <typename InputIt, typename OutputIt>
|
||||
void from_hex(InputIt begin, InputIt end, OutputIt out) {
|
||||
using std::distance;
|
||||
assert(distance(begin, end) % 2 == 0);
|
||||
assert(is_hex(begin, end));
|
||||
while (begin != end) {
|
||||
auto a = *begin++;
|
||||
auto b = *begin++;
|
||||
|
|
|
@ -24,8 +24,15 @@ TEST_CASE("hex encoding/decoding", "[encoding][decoding][hex]") {
|
|||
|
||||
REQUIRE( lokimq::is_hex("1234567890abcdefABCDEF1234567890abcdefABCDEF") );
|
||||
REQUIRE_FALSE( lokimq::is_hex("1234567890abcdefABCDEF1234567890aGcdefABCDEF") );
|
||||
// ^
|
||||
REQUIRE_FALSE( lokimq::is_hex("1234567890abcdefABCDEF1234567890agcdefABCDEF") );
|
||||
// ^
|
||||
REQUIRE_FALSE( lokimq::is_hex("\x11\xff") );
|
||||
constexpr auto odd_hex = "1234567890abcdefABCDEF1234567890abcdefABCDE"sv;
|
||||
REQUIRE_FALSE( lokimq::is_hex(odd_hex) );
|
||||
REQUIRE_FALSE( lokimq::is_hex("0") );
|
||||
|
||||
REQUIRE( std::all_of(odd_hex.begin(), odd_hex.end(), lokimq::is_hex_digit<char>) );
|
||||
|
||||
REQUIRE( lokimq::from_hex(pk_hex) == pk );
|
||||
REQUIRE( lokimq::to_hex(pk) == pk_hex );
|
||||
|
|
Loading…
Reference in New Issue