How fmt::basic_appender<T> Works with fmt::format_to for Efficient Output

The fmt::basic_appender<T> iterator enables zero-copy formatting by providing a minimal output iterator interface that writes characters directly into a detail::buffer<T>, eliminating the overhead of standard library abstractions and temporary allocations.

In the fmtlib/fmt repository, the format_to API achieves its high-throughput performance through a specialized output iterator that bypasses traditional C++ iterator machinery. This lightweight bridge, known as basic_appender<T>, allows the formatting engine to emit characters straight into user-supplied buffers without creating intermediate string objects or dragging in heavy standard library headers.

Minimal Iterator Interface in base.h

The basic_appender<T> template is defined in include/fmt/base.h at lines 42-60 as a thin wrapper around a detail::buffer<T> pointer. Unlike std::back_insert_iterator, it implements only the essential output iterator operations required by the C++ standard:

  • operator= – forwards the character to container->push_back(c)
  • operator* – returns the iterator itself (no-op dereference)
  • operator++ – increments the internal pointer tracking position

This minimal interface avoids the complex iterator category machinery found in the standard library, resulting in smaller binary sizes and faster compilation times.

Zero Dependency on

A critical optimization in the fmt library's design is the deliberate avoidance of the <iterator> header. By not inheriting from std::back_insert_iterator or including standard iterator adaptors, basic_appender<T> keeps compilation units lean. The implementation in include/fmt/base.h relies solely on the buffer's push_back method, ensuring that every character write is an O(1) operation directly into contiguous memory.

Specialized Iterator Traits

To ensure the formatting machinery treats basic_appender<T> as a proper output iterator without including <iterator>, the library provides an explicit std::iterator_traits specialization. Located in include/fmt/format.h at lines 152-158, this specialization declares the iterator_category as std::output_iterator_tag and defines the appropriate value and pointer types, allowing generic_context and other internal templates to recognize and optimize for this iterator type.

Memory Pre-allocation with reserve and to_pointer

Efficient output requires avoiding repeated heap allocations during formatting. The basic_appender<T> interface includes reserve and to_pointer helper methods defined in include/fmt/format.h (lines 482-508). These methods allow the formatting engine to:

  • Pre-allocate capacity – reserve(n) ensures the underlying buffer can accommodate n additional characters
  • Direct pointer access – to_pointer() returns a raw pointer for bulk operations, enabling the formatter to write multiple characters through std::memcpy when possible

This approach prevents incremental reallocations during large formatting operations, maintaining linear time complexity regardless of output size.

Integration with format_to

The format_to function constructs a basic_appender<T> from the target buffer and passes it to a generic_context instance. In include/fmt/format.h at lines 2221-2230, the implementation:

  1. Constructs basic_appender<char> out(buffer)
  2. Instantiates generic_context<basic_appender<char>, char> with the iterator
  3. Drives the formatting loop, calling *it = c for each character

Because the iterator writes directly into the buffer's internal array via push_back, format_to achieves zero-copy output—no temporary std::string objects are created, and no additional memory copies occur between the formatting engine and the destination buffer.

Practical Usage Example

The following example demonstrates direct buffer formatting using basic_appender through the format_to API:

#include <fmt/core.h>
#include <fmt/format.h>

int main() {
    // Create a reusable buffer that avoids repeated allocations
    fmt::memory_buffer buf;

    // Write formatted output directly into the buffer
    fmt::format_to(buf, "The answer is {}.\n", 42);

    // View the result without copying data
    std::string_view sv(buf.data(), buf.size());
    fmt::print("{}", sv);

    // Continue appending using the returned iterator
    auto it = fmt::format_to(buf, "Another {} line.\n", "formatted");
    // 'it' points just past the last written character
}

This pattern works for wide character variants (basic_appender<wchar_t>) and any custom buffer implementing the detail::buffer<T> interface.

Summary

  • basic_appender<T> provides a minimal output iterator interface in include/fmt/base.h that writes directly to detail::buffer<T> instances
  • Zero standard library overhead – the implementation avoids <iterator> dependencies, reducing compile times and symbol sizes
  • Direct integration – format_to constructs basic_appender instances and passes them to generic_context for immediate buffer writes
  • Pre-allocation support – reserve and to_pointer methods in include/fmt/format.h enable bulk memory operations and prevent reallocations
  • Universal applicability – the same efficient path supports char, wchar_t, and custom buffer types through template specialization

Frequently Asked Questions

What makes basic_appender more efficient than std::back_insert_iterator?

The basic_appender<T> avoids the heavy template machinery and header dependencies of std::back_insert_iterator by implementing only three required operations (operator=, operator*, operator++) and directly calling the buffer's push_back method. This eliminates virtual function indirection and unnecessary iterator category checks while preventing the inclusion of the <iterator> header, resulting in faster compile times and smaller binaries.

Can I use basic_appender with my own custom buffer types?

Yes, basic_appender<T> works with any type satisfying the detail::buffer<T> interface, which requires implementing push_back(T), grow(std::size_t), and providing access to the underlying storage through data() and size() methods. The iterator holds a raw pointer to the buffer container, enabling direct writes without virtual dispatch overhead.

Does format_to always construct a basic_appender internally?

When called with a detail::buffer<T> or memory_buffer, format_to automatically constructs a basic_appender<T> as the output iterator. However, format_to is a template function that accepts any output iterator meeting the C++ output iterator requirements. When passed standard iterators or pointers, it uses those directly rather than wrapping them in basic_appender.

How does basic_appender prevent memory reallocations during formatting?

The iterator exposes reserve(std::size_t) and to_pointer() methods that allow the formatting engine to pre-allocate sufficient capacity in the underlying buffer before writing. By calculating the required output size ahead of time and reserving space via include/fmt/format.h (lines 482-508), format_to avoids the repeated growth and copying that would occur with incremental appending, ensuring linear time complexity even for large format strings.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →