microfmt
Zero-allocation C++ formatting for constrained environments
Loading...
Searching...
No Matches
net.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2026 Jarosław Pelczar <jarek@jpelczar.com>
2//
3// SPDX-License-Identifier: BSD-2-Clause
4
5#pragma once
6
9#include "../microfmt.hpp"
10#include <cstddef>
11#include <cstdint>
12#include <string_view>
13#include <type_traits>
14
15namespace microfmt {
16
17namespace detail {
18
19template <typename T, typename = void> struct is_mac_container : std::false_type {};
20
21template <typename T>
23 T, std::void_t<decltype(std::declval<const T &>().data()), decltype(std::declval<const T &>().size())>>
24 : std::integral_constant<bool, std::is_convertible_v<decltype(std::declval<const T &>().data()), const uint8_t *> &&
25 std::is_convertible_v<decltype(std::declval<const T &>().size()), size_t>> {};
26
27} // namespace detail
28
29// ============================================================================
30// MAC Address View Adapter
31// ============================================================================
32
33struct MICROFMT_API_CLASS RELOCO_POINTER mac_view {
34 span<const uint8_t> bytes{}; // 6 bytes (MAC-48/EUI-48) or 8 bytes (EUI-64)
35 char separator{':'};
36 bool uppercase{false};
37};
38
39// ============================================================================
40// Factory Helpers
41// ============================================================================
42
43// From raw byte span / pointer + length
44[[nodiscard]] constexpr mac_view mac(span<const uint8_t> bytes, char separator = ':', bool uppercase = false) noexcept {
45 return mac_view{bytes, separator, uppercase};
46}
47
48// From 6-byte C-array
49[[nodiscard]] constexpr mac_view mac(const uint8_t (&arr)[6], char separator = ':', bool uppercase = false) noexcept {
50 return mac_view{span<const uint8_t>(arr, 6), separator, uppercase};
51}
52
53// From 8-byte EUI-64 C-array
54[[nodiscard]] constexpr mac_view mac(const uint8_t (&arr)[8], char separator = ':', bool uppercase = false) noexcept {
55 return mac_view{span<const uint8_t>(arr, 8), separator, uppercase};
56}
57
58// From reloco::array or container with .data() and .size()
59template <typename ContainerT, std::enable_if_t<detail::is_mac_container<ContainerT>::value, int> = 0>
60[[nodiscard]] constexpr mac_view mac(const ContainerT &c, char separator = ':', bool uppercase = false) noexcept {
61 return mac_view{span<const uint8_t>(c.data(), c.size()), separator, uppercase};
62}
63
64template <typename ContainerT,
65 std::enable_if_t<!std::is_lvalue_reference_v<ContainerT> &&
66 detail::is_mac_container<std::remove_reference_t<ContainerT>>::value,
67 int> = 0>
68[[nodiscard]] constexpr mac_view mac(ContainerT &&, char = ':', bool = false) noexcept = delete;
69
70// ============================================================================
71// Formatter Specialization for mac_view
72// ============================================================================
73
74template <> struct formatter<mac_view> {
75 char parse_separator{'\0'};
76 bool parse_uppercase{false};
77 bool parse_case_set{false};
78
79 constexpr void parse(format_parse_context &ctx) noexcept {
80 for (char c : ctx.spec()) {
81 if (c == 'X') {
82 parse_uppercase = true;
83 parse_case_set = true;
84 } else if (c == 'x') {
85 parse_uppercase = false;
86 parse_case_set = true;
87 } else if (c == '-' || c == ':' || c == '.' || c == '_') {
88 parse_separator = c;
89 }
90 }
91 }
92
93 void format(const mac_view &mv, const sink &out) const noexcept {
94 const size_t len = mv.bytes.size();
95 if (len != 6 && len != 8) {
96 out.write("00:00:00:00:00:00");
97 return;
98 }
99
100 const char sep = (parse_separator != '\0') ? parse_separator : mv.separator;
101 const bool is_upper = parse_case_set ? parse_uppercase : mv.uppercase;
102 const auto &hex_digits = is_upper ? detail::hex_digits_upper : detail::hex_digits_lower;
103
104 for (size_t i = 0; i < len; ++i) {
105 const uint8_t b = mv.bytes[i];
106 out.put(hex_digits[(b >> 4) & 0x0F]);
107 out.put(hex_digits[b & 0x0F]);
108
109 if (sep != '\0' && (i + 1) < len) {
110 out.put(sep);
111 }
112 }
113 }
114};
115
116} // namespace microfmt
Definition microfmt.hpp:881
#define MICROFMT_API_CLASS
Definition compat.hpp:181
Definition assert.hpp:19
reloco::sink sink
Type-erased, zero-allocation output sink.
Definition microfmt.hpp:46
constexpr mac_view mac(span< const uint8_t > bytes, char separator=':', bool uppercase=false) noexcept
Definition net.hpp:44
constexpr bytes_view bytes(uint64_t count) noexcept
Definition format_helpers.hpp:82
constexpr void parse(format_parse_context &ctx) noexcept
Definition net.hpp:79
void format(const mac_view &mv, const sink &out) const noexcept
Definition net.hpp:93
Definition microfmt.hpp:985
Definition net.hpp:33