Compile-Time Formatting
print.hpp provides a formatting and output layer in current mainline that is independent from STDIO, under:
namespace LibXR::Print
It is a shared compile-time formatting surface that can be reused by:
- I/O paths such as
STDIO::Printf RuntimeStringView::Reformat / Reprintf- higher-level modules such as
Logger
Current mainline supports two source-format frontends:
- brace style:
LibXR::Format<"..."> - printf style:
LibXR::Print::Printf::Build<"...">()
1. Output sink contract: OutputSink
LibXR::Print does not hardcode one target such as UART or terminal output. Instead, it writes to any object satisfying the OutputSink concept.
The current requirement is simple:
ErrorCode Write(std::string_view text);
So any object that provides Write(std::string_view) and returns something convertible to ErrorCode can be used as a print sink.
This is why current mainline can write formatted output both to real I/O and to test sinks, memory buffers, or retained string builders.
2. Brace-style frontend: LibXR::Format<Source>
constexpr LibXR::Format<"x={:+05d} {:#x} {}"> format{};
Format<Source> parses a brace-style literal at compile time and exposes several static interfaces used in current mainline:
ArgumentCount(): how many call-site arguments are actually referencedMatches<Args...>(): whether a given argument-type list is compatible with the formatCompiled<Args...>: the compiled result after binding concrete argument typesWriteTo(sink, args...): direct output into anOutputSink
Current mainline also supports explicit argument reordering, for example:
LibXR::Format<"{1} {0}">
but mixing automatic and manual indexing is a compile-time error.
3. printf-style frontend: Print::Printf
constexpr auto format = LibXR::Print::Printf::Build<"%+05d %#x %s">();
Printf::Build<Source>() parses a printf-style literal at compile time and returns a compiled-format object. Current mainline also provides:
Printf::Matches<Source, Args...>()Printf::Compiled<Source>
Its failures are also pushed to compile time whenever possible, including:
- invalid conversion specifiers
- unsupported length modifiers
- dynamic width / precision using
* - mixing positional and sequential arguments
The current implementation is a compile-time literal path, not a traditional runtime
printfparser for arbitrary format strings.
4. Public output APIs
4.1 Write into any sink
Current mainline exposes these convenience wrappers:
ErrorCode Write(sink, format, args...)ErrorCode FormatTo(sink, format, args...)ErrorCode FormatTo<"...">(sink, args...)ErrorCode PrintfTo<"...">(sink, args...)
These sink-writing paths return only sink-side ErrorCode, not a written-length value.
4.2 Write into a bounded char buffer
Current mainline also exposes bounded-buffer helpers:
int FormatIntoBuffer(buffer, capacity, format, args...)int FormatIntoBuffer<"...">(buffer, capacity, args...)int PrintfIntoBuffer<"...">(buffer, capacity, args...)int SNPrintf(buffer, capacity, format, args...)int SNPrintf<"...">(buffer, capacity, args...)
Their return contract matches the current implementation:
- success returns the full formatted length, excluding the trailing
\0 - even when truncation happens, the return value still reports the full untruncated length
- runtime error or length overflow beyond
intreturns-1 - when
capacity > 0, the destination buffer is always kept NUL-terminated
That is much closer to snprintf semantics than to “actual retained length”.
5. Examples
5.1 Brace-style output to a sink
struct Sink
{
ErrorCode Write(std::string_view text)
{
// write to UART, a string cache, or another target
return ErrorCode::OK;
}
};
Sink sink;
constexpr LibXR::Format<"x={:+05d} {:#x} {}"> format{};
LibXR::Print::FormatTo(sink, format, 7, 42U, "ok");
5.2 printf-style output to a sink
Sink sink;
LibXR::Print::PrintfTo<"%+05d %#x %s">(sink, 7, 42U, "ok");
5.3 Output to a bounded char buffer
char buffer[16] = {};
int written = LibXR::Print::PrintfIntoBuffer<"%d %s">(buffer, sizeof(buffer), 123, "xy");
If buffer is too small, written still reports the full text length, while buffer keeps only the first capacity - 1 visible characters and appends \0 automatically.
6. Relationship to STDIO::Printf
STDIO::Printf is one upper-layer entry point, but it is not the whole formatting system.
The current relationship is more accurately:
Printprovides compile-time format parsing and output contractsSTDIO::Printfreuses that layer and sends the result to the globalSTDIOwrite endpointRuntimeStringViewalso reuses it, but retains the result inside its own string storage
If you only want to emit debug text through the global output, STDIO::Printf from core-rw is the most direct choice. If you want to write formatted output into a custom sink or a bounded memory buffer, use the Print::* APIs on this page directly.