microfmt
Zero-allocation C++ formatting for constrained environments
Loading...
Searching...
No Matches
format_helpers.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
8#include "../microfmt.hpp"
9
10namespace microfmt {
11
12// ============================================================================
13// Hex/Binary Explicit Wrapper
14// ============================================================================
15
21template <typename T> struct hex_view {
22 T value{};
23 int width{0};
24 bool prefix{false};
25 bool uppercase{false};
26};
27
28template <typename T>
29[[nodiscard]] constexpr hex_view<T> hex(T val, int width = 0, bool prefix = false, bool uppercase = false) noexcept {
30 return hex_view<T>{val, width, prefix, uppercase};
31}
32
33template <typename T> struct formatter<hex_view<T>> {
34 constexpr void parse(format_parse_context &) noexcept {}
35
36 void format(const hex_view<T> &h, const sink &out) const noexcept {
37 if (h.prefix) {
38 out.write(h.uppercase ? "0X" : "0x");
39 }
40 detail::format_unsigned<detail::radix::hex>(out, static_cast<uint64_t>(h.value), h.uppercase, h.width);
41 }
42};
43
48template <typename T> struct bin_view {
49 T value{};
50 int width{sizeof(T) * 8};
51 bool prefix{false};
52};
53
54template <typename T>
55[[nodiscard]] constexpr bin_view<T> bin(T val, int width = sizeof(T) * 8, bool prefix = false) noexcept {
56 return bin_view<T>{val, width, prefix};
57}
58
59template <typename T> struct formatter<bin_view<T>> {
60 constexpr void parse(format_parse_context &) noexcept {}
61
62 void format(const bin_view<T> &b, const sink &out) const noexcept {
63 if (b.prefix) {
64 out.write("0b");
65 }
66 detail::format_binary(out, static_cast<uint64_t>(b.value), b.width);
67 }
68};
69
70// ============================================================================
71// Human-Readable Byte / Size Formatter
72// ============================================================================
73
79 uint64_t bytes{0};
80};
81
82[[nodiscard]] constexpr bytes_view bytes(uint64_t count) noexcept { return bytes_view{count}; }
83
84template <> struct formatter<bytes_view> {
85 constexpr void parse(format_parse_context &) noexcept {}
86
87 void format(const bytes_view &b, const sink &out) const noexcept {
88 static constexpr reloco::array<string_view, 6> units = {"B", "KiB", "MiB", "GiB", "TiB", "PiB"};
89 uint64_t val = b.bytes;
90 size_t unit_idx = 0;
91 uint64_t rem = 0;
92
93 while (val >= 1024 && unit_idx < 5) {
94 rem = (val % 1024) * 10 / 1024; // 1 decimal place remainder
95 val /= 1024;
96 unit_idx++;
97 }
98
99 detail::format_unsigned<detail::radix::decimal>(out, val, false, 0);
100 if (unit_idx > 0 && rem > 0) {
101 out.put('.');
102 detail::format_unsigned<detail::radix::decimal>(out, rem, false, 0);
103 }
104 out.put(' ');
105 out.write(units[unit_idx]);
106 }
107};
108
109// ============================================================================
110// Pointer Offset / Range Formatter
111// ============================================================================
112
117 uintptr_t addr{0};
118 uintptr_t base{0};
119};
120
121[[nodiscard]] constexpr addr_offset_view addr_offset(uintptr_t addr, uintptr_t base) noexcept {
122 return addr_offset_view{addr, base};
123}
124
125template <> struct formatter<addr_offset_view> {
126 constexpr void parse(format_parse_context &) noexcept {}
127
128 void format(const addr_offset_view &v, const sink &out) const noexcept {
129 out.write("0x");
130 detail::format_unsigned<detail::radix::hex>(out, static_cast<uint64_t>(v.base), false);
131 if (v.addr >= v.base) {
132 out.write("+0x");
133 detail::format_unsigned<detail::radix::hex>(out, static_cast<uint64_t>(v.addr - v.base), false);
134 } else {
135 out.write("-0x");
136 detail::format_unsigned<detail::radix::hex>(out, static_cast<uint64_t>(v.base - v.addr), false);
137 }
138 }
139};
140
145 uintptr_t start{0};
146 uintptr_t end{0};
147};
148
149[[nodiscard]] constexpr memory_range_view mem_range(uintptr_t start, uintptr_t end) noexcept {
150 return memory_range_view{start, end};
151}
152
153template <> struct formatter<memory_range_view> {
154 constexpr void parse(format_parse_context &) noexcept {}
155
156 void format(const memory_range_view &r, const sink &out) const noexcept {
157 out.write("[0x");
158 detail::format_unsigned<detail::radix::hex>(out, static_cast<uint64_t>(r.start), false);
159 out.write("..0x");
160 detail::format_unsigned<detail::radix::hex>(out, static_cast<uint64_t>(r.end), false);
161 out.write("] (");
162 if (r.end >= r.start) {
163 formatter<bytes_view>{}.format(bytes(r.end - r.start), out);
164 } else {
165 out.write("invalid");
166 }
167 out.put(')');
168 }
169};
170
171// ============================================================================
172// Padded / Aligned Text Field
173// ============================================================================
174
175enum class align_mode : uint8_t { left, right, center };
176
178 microfmt::string_view text{};
179 size_t width{0};
180 align_mode mode{align_mode::left};
181 char pad_char{' '};
182};
183
184[[nodiscard]] constexpr aligned_text_view align(microfmt::string_view text, size_t width,
185 align_mode mode = align_mode::left, char pad_char = ' ') noexcept {
186 return aligned_text_view{text, width, mode, pad_char};
187}
188
189template <> struct formatter<aligned_text_view> {
190 constexpr void parse(format_parse_context &) noexcept {}
191
192 void format(const aligned_text_view &v, const sink &out) const noexcept {
193 if (v.text.size() >= v.width) {
194 out.write(v.text);
195 return;
196 }
197
198 const size_t pad_total = v.width - v.text.size();
199 switch (v.mode) {
201 for (size_t i = 0; i < pad_total; ++i)
202 out.put(v.pad_char);
203 out.write(v.text);
204 break;
205 case align_mode::center: {
206 const size_t left = pad_total / 2;
207 const size_t right = pad_total - left;
208 for (size_t i = 0; i < left; ++i)
209 out.put(v.pad_char);
210 out.write(v.text);
211 for (size_t i = 0; i < right; ++i)
212 out.put(v.pad_char);
213 break;
214 }
215 case align_mode::left:
216 default:
217 out.write(v.text);
218 for (size_t i = 0; i < pad_total; ++i)
219 out.put(v.pad_char);
220 break;
221 }
222 }
223};
224
225// ============================================================================
226// Delimited Span / Array Formatter (Zero-Allocation Container Join)
227// ============================================================================
228
233template <typename T> struct RELOCO_POINTER joined_span_view {
234 span<const T> items{};
235 microfmt::string_view delimiter{", "};
236};
237
238template <typename T>
239[[nodiscard]] constexpr joined_span_view<T> join(span<const T> items, microfmt::string_view delim = ", ") noexcept {
240 return joined_span_view<T>{items, delim};
241}
242
243template <typename T> struct formatter<joined_span_view<T>> {
244 constexpr void parse(format_parse_context &) noexcept {}
245
246 void format(const joined_span_view<T> &j, const sink &out) const noexcept {
247 bool first = true;
249 format_parse_context dummy_ctx("");
250 elem_fmt.parse(dummy_ctx);
251
252 for (const auto &item : j.items) {
253 if (!first) {
254 out.write(j.delimiter);
255 }
256 first = false;
257 elem_fmt.format(item, out);
258 }
259 }
260};
261
262} // namespace microfmt
Definition microfmt.hpp:881
#define MICROFMT_API_CLASS
Definition compat.hpp:181
Definition assert.hpp:19
constexpr hex_view< T > hex(T val, int width=0, bool prefix=false, bool uppercase=false) noexcept
Definition format_helpers.hpp:29
reloco::sink sink
Type-erased, zero-allocation output sink.
Definition microfmt.hpp:46
constexpr aligned_text_view align(microfmt::string_view text, size_t width, align_mode mode=align_mode::left, char pad_char=' ') noexcept
Definition format_helpers.hpp:184
constexpr joined_span_view< T > join(span< const T > items, microfmt::string_view delim=", ") noexcept
Definition format_helpers.hpp:239
constexpr addr_offset_view addr_offset(uintptr_t addr, uintptr_t base) noexcept
Definition format_helpers.hpp:121
align_mode
Definition format_helpers.hpp:175
constexpr bytes_view bytes(uint64_t count) noexcept
Definition format_helpers.hpp:82
constexpr auto bin(T val) noexcept
Definition binary.hpp:34
constexpr memory_range_view mem_range(uintptr_t start, uintptr_t end) noexcept
Definition format_helpers.hpp:149
Formats an address with a base + offset view: 0x7fff0000+0x140
Definition format_helpers.hpp:116
Definition format_helpers.hpp:177
Explicit binary integer formatter (e.g. for bitfield and control register flags).
Definition format_helpers.hpp:48
T value
Definition format_helpers.hpp:49
int width
Definition format_helpers.hpp:50
bool prefix
Definition format_helpers.hpp:51
Automatically formats byte counts into human-readable units (B, KiB, MiB, GiB, TiB).
Definition format_helpers.hpp:78
Drop-in replacement for a formatter<T> underlying_formatter; member used by container/wrapper formatt...
Definition microfmt.hpp:1433
constexpr void parse(format_parse_context &ctx) noexcept
Definition microfmt.hpp:1445
void format(const T &value, const sink &out) const noexcept
Definition microfmt.hpp:1447
void format(const addr_offset_view &v, const sink &out) const noexcept
Definition format_helpers.hpp:128
constexpr void parse(format_parse_context &) noexcept
Definition format_helpers.hpp:126
void format(const aligned_text_view &v, const sink &out) const noexcept
Definition format_helpers.hpp:192
constexpr void parse(format_parse_context &) noexcept
Definition format_helpers.hpp:190
constexpr void parse(format_parse_context &) noexcept
Definition format_helpers.hpp:60
void format(const bin_view< T > &b, const sink &out) const noexcept
Definition format_helpers.hpp:62
constexpr void parse(format_parse_context &) noexcept
Definition format_helpers.hpp:85
void format(const bytes_view &b, const sink &out) const noexcept
Definition format_helpers.hpp:87
constexpr void parse(format_parse_context &) noexcept
Definition format_helpers.hpp:34
void format(const hex_view< T > &h, const sink &out) const noexcept
Definition format_helpers.hpp:36
void format(const joined_span_view< T > &j, const sink &out) const noexcept
Definition format_helpers.hpp:246
constexpr void parse(format_parse_context &) noexcept
Definition format_helpers.hpp:244
void format(const memory_range_view &r, const sink &out) const noexcept
Definition format_helpers.hpp:156
constexpr void parse(format_parse_context &) noexcept
Definition format_helpers.hpp:154
Definition microfmt.hpp:985
Explicitly formats an integer in hexadecimal or binary with customizable prefix, padding width,...
Definition format_helpers.hpp:21
int width
Definition format_helpers.hpp:23
bool prefix
Definition format_helpers.hpp:24
bool uppercase
Definition format_helpers.hpp:25
T value
Definition format_helpers.hpp:22
Formats a contiguous array/span of values separated by a custom delimiter. Example: join(span,...
Definition format_helpers.hpp:233
Formats an address range: [0x10000000..0x10004000] (16 KiB)
Definition format_helpers.hpp:144