From 404b491880abe5fe313f9fdac2b1b8adec20e85f Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Thu, 28 Aug 2025 14:05:45 -0400 Subject: [PATCH] Add documentation --- src/format.hpp | 159 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 154 insertions(+), 5 deletions(-) diff --git a/src/format.hpp b/src/format.hpp index fd28ce0..8d454d3 100644 --- a/src/format.hpp +++ b/src/format.hpp @@ -9,6 +9,90 @@ #include "arena_allocator.hpp" +/** + * @brief Runtime printf-style formatting with arena allocation optimization. + * + * This function provides familiar printf-style formatting with intelligent + * optimization for arena allocation. It attempts single-pass formatting by + * speculatively using available arena space, falling back to two-pass + * formatting only when necessary. + * + * The function uses an optimized allocation strategy: + * 1. **Single-pass attempt**: Try to format directly into available arena space + * 2. **Fallback to two-pass**: If formatting doesn't fit, measure required size + * and allocate exactly what's needed + * + * ## Supported Format Specifiers: + * All standard printf format specifiers are supported: + * - **Integers**: %d, %i, %u, %x, %X, %o, %ld, %lld, etc. + * - **Floating point**: %f, %e, %E, %g, %G, %.2f, etc. + * - **Strings**: %s, %.*s, etc. + * - **Characters**: %c + * - **Pointers**: %p + * - **Width/precision**: %10d, %-10s, %.2f, %*.*s, etc. + * + * ## Performance Characteristics: + * - **Optimistic single-pass**: Often avoids the cost of measuring format size + * - **Arena allocation**: Uses fast arena allocation (~1ns vs ~20-270ns for + * malloc) + * - **Memory efficient**: Returns unused space to arena via realloc() + * - **Fallback safety**: Two-pass approach handles any format that doesn't fit + * + * @param arena Arena allocator for memory management + * @param fmt Printf-style format string + * @param ... Variable arguments matching format specifiers + * @return std::string_view pointing to arena-allocated formatted string + * @note Returns empty string_view on formatting errors + * @note GCC format attribute enables compile-time format string validation + * + * ## Usage Examples: + * ```cpp + * ArenaAllocator arena(1024); + * + * // Basic formatting + * auto msg = format(arena, "Hello %s!", "World"); + * // msg == "Hello World!" + * + * // Numeric formatting with precision + * auto value = format(arena, "Pi: %.3f", 3.14159); + * // value == "Pi: 3.142" + * + * // Mixed types with width/alignment + * auto table = format(arena, "%-10s %5d %8.2f", "Item", 42, 99.95); + * // table == "Item 42 99.95" + * + * // Error messages + * auto error = format(arena, "Error %d: %s (line %d)", 404, "Not found", 123); + * // error == "Error 404: Not found (line 123)" + * ``` + * + * ## When to Use: + * - **Printf familiarity**: When you prefer printf-style format strings + * - **Runtime flexibility**: Format strings from variables, config, or user + * input + * - **Complex formatting**: Precision, width, alignment, padding + * - **Debugging**: Quick formatted output for logging/debugging + * - **Mixed precision**: Different numeric precision requirements + * + * ## When to Use static_format() Instead: + * - **Hot paths**: Performance-critical code where every nanosecond counts + * - **Simple concatenation**: Basic string + number + string combinations + * - **Compile-time optimization**: When all types/values known at compile time + * - **Template contexts**: Where compile-time buffer sizing is beneficial + * + * ## Optimization Details: + * The function uses `ArenaAllocator::allocate_remaining_space()` to claim all + * available arena space and attempt formatting. If successful, it shrinks the + * allocation to the actual size used. If formatting fails (doesn't fit), it + * falls back to the traditional two-pass approach: measure size, allocate + * exactly, then format. + * + * This strategy optimizes for the common case where available arena space is + * sufficient, while maintaining correctness for all cases. + */ +std::string_view format(ArenaAllocator &arena, const char *fmt, ...) + __attribute__((format(printf, 2, 3))); + namespace detail { template struct StringTerm { @@ -172,6 +256,76 @@ inline constexpr DoubleTerm term(double s) { return DoubleTerm(s); } } // namespace detail +/** + * @brief Compile-time optimized formatting for high-performance code paths. + * + * This function provides ultra-fast string formatting by calculating buffer + * sizes at compile time and using specialized term handlers for each type. + * It's designed for performance-critical code where formatting overhead + * matters. + * + * Unlike the runtime `format()` function, `static_format()` processes all + * arguments at compile time to determine exact memory requirements and uses + * optimized term writers for maximum speed. + * + * ## Supported Types: + * - **String literals**: C-style string literals and arrays + * - **Integers**: All integral types (int, int64_t, uint32_t, etc.) + * - **Floating point**: double (uses high-precision Grisu2 algorithm) + * - **Custom types**: Via specialization of `detail::term()` + * + * ## Performance Characteristics: + * - **Compile-time buffer sizing**: Buffer size calculated at compile time (no + * runtime measurement) + * - **Optimized arena allocation**: Uses pre-calculated exact buffer sizes with + * arena allocator + * - **Specialized type handling**: Fast paths for common types via template + * specialization + * - **Memory efficient**: Uses arena.realloc() to return unused space to the + * arena + * + * @tparam Ts Types of the arguments to format (auto-deduced) + * @param arena Arena allocator for memory management + * @param ts Arguments to format - can be string literals, integers, doubles + * @return std::string_view pointing to arena-allocated formatted string + * + * ## Usage Examples: + * ```cpp + * ArenaAllocator arena(1024); + * + * // String concatenation + * auto result1 = static_format(arena, "Hello ", "World", "!"); + * // result1 == "Hello World!" + * + * // Mixed types + * auto result2 = static_format(arena, "Count: ", 42, ", Rate: ", 3.14); + * // result2 == "Count: 42, Rate: 3.14" + * + * // Error messages + * auto error = static_format(arena, "Error ", 404, ": ", "Not found"); + * // error == "Error 404: Not found" + * ``` + * + * ## When to Use: + * - **Hot paths**: Performance-critical code where formatting speed matters + * - **Known types**: When argument types are known at compile time + * - **Simple formatting**: Concatenation and basic type conversion + * - **Template code**: Where compile-time optimization is beneficial + * + * ## When to Use format() Instead: + * - **Printf-style formatting**: When you need format specifiers like "%d", + * "%.2f" + * - **Runtime flexibility**: When format strings come from variables/config + * - **Complex formatting**: When you need padding, precision, etc. + * - **Convenience**: For quick debugging or non-critical paths + * + * @note All arguments are passed by forwarding reference for optimal + * performance + * @note Memory is arena-allocated and automatically sized to exact requirements + * @note Compile-time errors occur if unsupported types are used + * @note This function is constexpr-friendly and optimizes well in release + * builds + */ template std::string_view static_format(ArenaAllocator &arena, Ts &&...ts) { constexpr int upper_bound = @@ -184,8 +338,3 @@ std::string_view static_format(ArenaAllocator &arena, Ts &&...ts) { arena.realloc(result, upper_bound, upper_bound - size), static_cast(size)); } - -// Runtime formatting function using C-style varargs -// For convenience in non-performance-critical code paths -std::string_view format(ArenaAllocator &arena, const char *fmt, ...) - __attribute__((format(printf, 2, 3)));