32 constexpr std::size_t kMaxLength = 64;
33 if (s.empty() || s.size() > kMaxLength) {
36 return std::all_of(s.begin(), s.end(), [](
const char c) {
37 return (c >=
'A' && c <=
'Z') || (c >=
'a' && c <=
'z') || (c >=
'0' && c <=
'9') || c ==
'.' ||
55 std::from_chars_result r;
56 if (s.size() >= 2 && (s[0] ==
'0' || s[0] ==
'#') && (s[1] ==
'x' || s[1] ==
'X')) {
57 r = std::from_chars(s.data() + 2, s.data() + s.size(), value, 16);
59 r = std::from_chars(s.data(), s.data() + s.size(), value);
61 if (r.ec != std::errc{} || r.ptr != s.data() + s.size()) {
75inline std::string
toHex(std::span<const uint8_t> bytes, std::string_view separator = {}) {
77 out.reserve(bytes.size() * (2 + separator.size()));
78 for (std::size_t i = 0; i < bytes.size(); ++i) {
82 out += std::format(
"{:02X}", bytes[i]);
100inline std::optional<std::vector<uint8_t>>
fromHex(std::string_view hex) {
101 if (hex.size() % 2 != 0) {
104 const auto digit = [](
char c) ->
int {
105 if (c >=
'0' && c <=
'9') {
108 if (c >=
'a' && c <=
'f') {
111 if (c >=
'A' && c <=
'F') {
116 std::vector<uint8_t> out;
117 out.reserve(hex.size() / 2);
118 for (std::size_t i = 0; i < hex.size(); i += 2) {
119 const int hi = digit(hex[i]);
120 const int lo = digit(hex[i + 1]);
121 if (hi < 0 || lo < 0) {
124 out.push_back(
static_cast<uint8_t
>((hi << 4) | lo));
143std::array<uint8_t,
sizeof(T)>
toBytes(T value, std::endian order = std::endian::little) {
144 static_assert(std::is_integral_v<T>,
"toBytes is for integral types");
145 using U = std::make_unsigned_t<T>;
146 const auto u =
static_cast<U
>(value);
147 std::array<uint8_t,
sizeof(T)> out{};
148 for (std::size_t i = 0; i <
sizeof(T); ++i) {
149 const std::size_t
byte = (order == std::endian::little) ? i : (
sizeof(T) - 1 - i);
150 out[byte] =
static_cast<uint8_t
>((u >> (8 * i)) & 0xFFu);
167T
fromBytes(std::span<const uint8_t> bytes, std::endian order = std::endian::little) {
168 static_assert(std::is_integral_v<T>,
"fromBytes is for integral types");
169 using U = std::make_unsigned_t<T>;
171 const std::size_t n = std::min(
sizeof(T), bytes.size());
172 for (std::size_t i = 0; i < n; ++i) {
173 const std::size_t shift = (order == std::endian::little) ? (8 * i) : (8 * (n - 1 - i));
174 v |=
static_cast<U
>(bytes[i]) << shift;
176 return static_cast<T
>(v);
Definition http_server.h:25
std::optional< std::vector< uint8_t > > fromHex(std::string_view hex)
Decodes a continuous hexadecimal string into bytes — the inverse of toHex.
Definition util.h:100
std::optional< T > parseHexOrDec(std::string_view s)
Parses an unsigned integer from a string in decimal or hexadecimal notation.
Definition util.h:53
std::array< uint8_t, sizeof(T)> toBytes(T value, std::endian order=std::endian::little)
Encodes an integer into a fixed-width byte array in the given byte order.
Definition util.h:143
bool isUrlSafeId(std::string_view s)
Whether s is a valid URL-safe identifier usable as a path segment and pub/sub topic.
Definition util.h:31
std::string toHex(std::span< const uint8_t > bytes, std::string_view separator={})
Formats bytes as uppercase hexadecimal.
Definition util.h:75
T fromBytes(std::span< const uint8_t > bytes, std::endian order=std::endian::little)
Decodes an integer from a raw byte buffer interpreted in the given byte order.
Definition util.h:167