blob: bf01c00f49931bae19494aec4b873936d843df21 [file] [edit]
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Helpers for parsing hexadecimal numbers in network address strings.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC___SUPPORT_NET_HEX_H
#define LLVM_LIBC_SRC___SUPPORT_NET_HEX_H
#include "hdr/types/size_t.h"
#include "src/__support/CPP/optional.h"
#include "src/__support/CPP/string_view.h"
#include "src/__support/CPP/type_traits.h"
#include "src/__support/common.h"
#include "src/__support/ctype_utils.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
namespace net {
/// Returns the value of the hexadecimal digit \p ch, or -1 if \p ch is not a
/// hexadecimal digit.
LIBC_INLINE constexpr int hex_digit_value(char ch) {
if (!internal::isalnum(ch))
return -1;
int val = internal::b36_char_to_int(ch);
return val < 16 ? val : -1;
}
/// Parses a hexadecimal number at the start of \p src and removes the parsed
/// characters from it. At most `2 * sizeof(T)` digits (i.e., as many as can
/// always fit into a T) are consumed. Any following characters (including
/// further hexadecimal digits) are left in \p src for the caller to deal with.
/// Unlike strtointeger, this does not accept leading whitespace, signs or
/// base prefixes. Returns nullopt (leaving \p src unchanged) if \p src does not
/// start with a hexadecimal digit.
template <typename T>
LIBC_INLINE constexpr cpp::optional<T> consume_hex(cpp::string_view &src) {
static_assert(cpp::is_unsigned_v<T>, "T must be an unsigned integer type");
constexpr size_t MAX_DIGITS = 2 * sizeof(T);
T result = 0;
size_t len = 0;
for (; len < MAX_DIGITS && len < src.size(); ++len) {
int digit = hex_digit_value(src[len]);
if (digit < 0)
break;
result = static_cast<T>(result << 4 | digit);
}
if (len == 0)
return cpp::nullopt;
src.remove_prefix(len);
return result;
}
} // namespace net
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC___SUPPORT_NET_HEX_H