microfmt
Zero-allocation C++ formatting for constrained environments
Loading...
Searching...
No Matches
stdio.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 <cstdio>
11#include <string_view>
12
13#if MICROFMT_HAS_POSIX_FD
14#include <unistd.h>
15#endif
16
17namespace microfmt {
18
19// ============================================================================
20// FILE* Sink Adapter
21// ============================================================================
22
23// bridges to a C/platform API (FILE*, syslog, android log, raw chunk storage) that takes raw pointers.
24RELOCO_BEGIN_UNSAFE_CODE
25[[nodiscard]] inline sink file_sink(std::FILE *file) noexcept {
26 return sink{file, [](void *ctx, microfmt::string_view sv) noexcept {
27 if (ctx != nullptr && !sv.empty()) {
28 RELOCO_BEGIN_UNSAFE_BUFFER_USAGE;
29 std::fwrite(sv.data(), 1, sv.size(), static_cast<std::FILE *>(ctx));
30 RELOCO_END_UNSAFE_BUFFER_USAGE;
31 }
32 }};
33}
35
36[[nodiscard]] inline sink stdout_sink() noexcept { return file_sink(stdout); }
37
38[[nodiscard]] inline sink stderr_sink() noexcept { return file_sink(stderr); }
39
40// ============================================================================
41// POSIX File Descriptor Sink Adapter (write(2))
42// ============================================================================
43
44#if MICROFMT_HAS_POSIX_FD
45// bridges to a C/platform API (FILE*, syslog, android log, raw chunk storage) that takes raw pointers.
46RELOCO_BEGIN_UNSAFE_CODE
47[[nodiscard]] inline sink fd_sink(int fd) noexcept {
48 // Store fd inside the pointer context value without allocation
49 return sink{reinterpret_cast<void *>(static_cast<intptr_t>(fd)), [](void *ctx, microfmt::string_view sv) noexcept {
50 RELOCO_BEGIN_UNSAFE_BUFFER_USAGE;
51
52 const int target_fd = static_cast<int>(reinterpret_cast<intptr_t>(ctx));
53 if (target_fd >= 0 && !sv.empty()) {
54 const char *ptr = sv.data();
55 size_t remaining = sv.size();
56 while (remaining > 0) {
57 const ssize_t written = ::write(target_fd, ptr, remaining);
58 if (written <= 0) {
59 break; // Non-blocking full / broken pipe
60 }
61 ptr += written;
62 remaining -= static_cast<size_t>(written);
63 }
64 }
65
66 RELOCO_END_UNSAFE_BUFFER_USAGE;
67 }};
68}
70#endif
71
72// =============================================================================
73// Direct stdout printing
74// =============================================================================
75
76// Compile-time stdout overloads
77template <typename StrProvider, typename... Args>
78inline void print(compile_string_holder<StrProvider> fmt, const Args &...args) noexcept {
79 auto s = stdout_sink();
80 format_to(s, fmt, args...);
81}
82
83template <typename StrProvider, typename... Args>
84inline void println(compile_string_holder<StrProvider> fmt, const Args &...args) noexcept {
85 auto s = stdout_sink();
86 format_to(s, fmt, args...);
87 s.put('\n');
88}
89
90// Runtime stdout overloads
91template <typename... Args> inline void print(microfmt::string_view fmt_str, const Args &...args) noexcept {
92 auto s = stdout_sink();
93 format_to(s, fmt_str, args...);
94}
95
96template <typename... Args> inline void println(microfmt::string_view fmt_str, const Args &...args) noexcept {
97 auto s = stdout_sink();
98 format_to(s, fmt_str, args...);
99 s.put('\n');
100}
101
102// =============================================================================
103// Target std::FILE* stream printing
104// =============================================================================
105
106// Compile-time FILE* overloads
107// bridges to a C/platform API (FILE*, syslog, android log, raw chunk storage) that takes raw pointers.
108RELOCO_BEGIN_UNSAFE_CODE
109template <typename StrProvider, typename... Args>
110inline void print(std::FILE *file, compile_string_holder<StrProvider> fmt, const Args &...args) noexcept {
111 auto s = file_sink(file);
112 format_to(s, fmt, args...);
113}
115
116// bridges to a C/platform API (FILE*, syslog, android log, raw chunk storage) that takes raw pointers.
117RELOCO_BEGIN_UNSAFE_CODE
118template <typename StrProvider, typename... Args>
119inline void println(std::FILE *file, compile_string_holder<StrProvider> fmt, const Args &...args) noexcept {
120 auto s = file_sink(file);
121 format_to(s, fmt, args...);
122 s.put('\n');
123}
125
126// Runtime FILE* overloads
127// bridges to a C/platform API (FILE*, syslog, android log, raw chunk storage) that takes raw pointers.
128RELOCO_BEGIN_UNSAFE_CODE
129template <typename... Args>
130inline void print(std::FILE *file, microfmt::string_view fmt_str, const Args &...args) noexcept {
131 auto s = file_sink(file);
132 format_to(s, fmt_str, args...);
133}
135
136// bridges to a C/platform API (FILE*, syslog, android log, raw chunk storage) that takes raw pointers.
137RELOCO_BEGIN_UNSAFE_CODE
138template <typename... Args>
139inline void println(std::FILE *file, microfmt::string_view fmt_str, const Args &...args) noexcept {
140 auto s = file_sink(file);
141 format_to(s, fmt_str, args...);
142 s.put('\n');
143}
145
146// =============================================================================
147// Target POSIX FD printing
148// =============================================================================
149
150#if MICROFMT_HAS_POSIX_FD
151// Compile-time FD overloads
152template <typename StrProvider, typename... Args>
153inline void print(int fd, compile_string_holder<StrProvider> fmt, const Args &...args) noexcept {
154 auto s = fd_sink(fd);
155 format_to(s, fmt, args...);
156}
157
158template <typename StrProvider, typename... Args>
159inline void println(int fd, compile_string_holder<StrProvider> fmt, const Args &...args) noexcept {
160 auto s = fd_sink(fd);
161 format_to(s, fmt, args...);
162 s.put('\n');
163}
164
165// Runtime FD overloads
166template <typename... Args> inline void print(int fd, microfmt::string_view fmt_str, const Args &...args) noexcept {
167 auto s = fd_sink(fd);
168 format_to(s, fmt_str, args...);
169}
170
171template <typename... Args> inline void println(int fd, microfmt::string_view fmt_str, const Args &...args) noexcept {
172 auto s = fd_sink(fd);
173 format_to(s, fmt_str, args...);
174 s.put('\n');
175}
176#endif
177
178// =============================================================================
179// Target Sink printing
180// =============================================================================
181
182// Compile-time Sink overloads
183template <typename StrProvider, typename... Args>
184inline void print(sink s, compile_string_holder<StrProvider> fmt, const Args &...args) noexcept {
185 format_to(s, fmt, args...);
186}
187
188template <typename StrProvider, typename... Args>
189inline void println(sink s, compile_string_holder<StrProvider> fmt, const Args &...args) noexcept {
190 format_to(s, fmt, args...);
191 s.put('\n');
192}
193
194// Runtime Sink overloads
195template <typename... Args> inline void print(sink s, microfmt::string_view fmt_str, const Args &...args) noexcept {
196 format_to(s, fmt_str, args...);
197}
198
199template <typename... Args> inline void println(sink s, microfmt::string_view fmt_str, const Args &...args) noexcept {
200 format_to(s, fmt_str, args...);
201 s.put('\n');
202}
203
204// =============================================================================
205// Bare newline helpers
206// =============================================================================
207
208inline void println(sink s) noexcept { s.put('\n'); }
209
210inline void println() noexcept { stdout_sink().put('\n'); }
211
212// bridges to a C/platform API (FILE*, syslog, android log, raw chunk storage) that takes raw pointers.
213RELOCO_BEGIN_UNSAFE_CODE
214inline void println(std::FILE *file) noexcept { file_sink(file).put('\n'); }
216
217#if MICROFMT_HAS_POSIX_FD
218inline void println(int fd) noexcept { fd_sink(fd).put('\n'); }
219#endif
220
221} // namespace microfmt
Definition fmt.hpp:17
Definition assert.hpp:19
void println() noexcept
Definition stdio.hpp:210
RELOCO_END_UNSAFE_CODE sink stdout_sink() noexcept
Definition stdio.hpp:36
sink stderr_sink() noexcept
Definition stdio.hpp:38
reloco::sink sink
Type-erased, zero-allocation output sink.
Definition microfmt.hpp:46
RELOCO_CONSTEXPR20 void format_to(const sink &out, microfmt::string_view fmt, const Args &...args) noexcept
Definition microfmt.hpp:1766
void print(compile_string_holder< StrProvider > fmt, const Args &...args) noexcept
Definition stdio.hpp:78
RELOCO_BEGIN_UNSAFE_CODE sink file_sink(std::FILE *file) noexcept
Definition stdio.hpp:25
RELOCO_END_UNSAFE_CODE
Definition remote_object.hpp:132
Definition microfmt.hpp:1792