Skip to content

Speed up iterator_buffer#4679

Merged
vitaut merged 1 commit into
fmtlib:masterfrom
user202729:speed-up-iterator-buffer
Mar 25, 2026
Merged

Speed up iterator_buffer#4679
vitaut merged 1 commit into
fmtlib:masterfrom
user202729:speed-up-iterator-buffer

Conversation

@user202729

@user202729 user202729 commented Feb 23, 2026

Copy link
Copy Markdown
Contributor

Just a 1-line change to reuse the fmt::detail::copy() method instead of manually loop over each character. For that, some methods need to be moved around.

Demonstration of the speedup in fmtlib/format-benchmark#35 . Arguably vector<char> is a rare type, but it might be useful for other things (custom string types...?)

To make tests pass, I need to check whether the iterator type is move-assignable (throwing_iterator is not assignable), although I'd argue that in practice iterators ought to be move-assignable and that test is actually invalid.

@user202729 user202729 force-pushed the speed-up-iterator-buffer branch 2 times, most recently from 9778e35 to 73b240b Compare February 23, 2026 07:12
@user202729 user202729 force-pushed the speed-up-iterator-buffer branch from 73b240b to 1a282f8 Compare February 23, 2026 07:14

@vitaut vitaut left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR.

Comment thread include/fmt/base.h
Comment on lines 1930 to 1941
void flush() {
auto size = this->size();
this->clear();
const T* begin = data_;
const T* end = begin + this->limit(size);
while (begin != end) *out_++ = *begin++;
#if defined(__cpp_if_constexpr)
if constexpr (std::is_move_assignable<OutputIt>::value)
out_ = copy<T>(begin, end, out_);
else
#endif
while (begin != end) *out_++ = *begin++;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move the definition to fmt/format.h instead of bringing all the copy machinery here.

@vitaut

vitaut commented Mar 14, 2026

Copy link
Copy Markdown
Contributor

@user202729 do you still plan to update this PR?

@user202729 user202729 force-pushed the speed-up-iterator-buffer branch from 1a282f8 to 15252c8 Compare March 15, 2026 02:41
@user202729

user202729 commented Mar 15, 2026

Copy link
Copy Markdown
Contributor Author

Updated.

That said, it leads to a bunch of other things such as format_to being moved to format.h, which is technically a breaking change since, for example, previously a program that only use base.h would be able to use iterator_buffer, now they can't. (See the failing tests changed in the latest commit. In particular, deleting the error base-test includes format.h is extraordinarily wrong. One option is to move them to format-test.cc.)

I can think of a few possibilities such as providing a faster overload in format.h, but that would probably be a ODR violation.

What do you think?

Side note, if it makes you feel better, you could just close the PR and comment like "if you want to work on this later you can reopen it", or make a [stale] label and set your pull requests page to by default filter them out. I appreciate that you are very active and keep the number of pending issues and pull requests extraordinarily low.

Comment thread include/fmt/base.h
@user202729 user202729 force-pushed the speed-up-iterator-buffer branch from 03ed496 to 2e1c57c Compare March 23, 2026 05:13
@user202729

user202729 commented Mar 23, 2026

Copy link
Copy Markdown
Contributor Author

I followed the suggestion, and sure enough, base-test can't link.

What then? Move the tests in base-test.cc that requires this method to format-test?

@vitaut

vitaut commented Mar 24, 2026

Copy link
Copy Markdown
Contributor

I see, the problems is that the definition of flush won't get instantiated with the output iterator type. I guess moving copy to base.h is indeed the simplest option, sorry for going back and forth on it.

@user202729 user202729 force-pushed the speed-up-iterator-buffer branch from 2e1c57c to 1a282f8 Compare March 24, 2026 03:50
@user202729

Copy link
Copy Markdown
Contributor Author

in retrospect, with #4716 , this wouldn't be too useful. (maybe std::deque, but for that one the append method is named append_range.) but anyway...?

@vitaut vitaut merged commit 7b2c4d0 into fmtlib:master Mar 25, 2026
83 checks passed
@vitaut

vitaut commented Mar 25, 2026

Copy link
Copy Markdown
Contributor

Merged, thanks!

netbsd-srcmastr pushed a commit to NetBSD/pkgsrc that referenced this pull request Jun 22, 2026
# 12.2.0 - 2026-06-16

- Added a C11 API that brings fast, type-safe formatting to C. The new
  `fmt-c` library and `fmt/fmt-c.h` header use `_Generic` to dispatch on
  argument types and outperform `printf`/`sprintf`. For example:

  ```c++
  #include <fmt/fmt-c.h>

  fmt_print(stdout, "The answer is {}.\n", 42);
  ```

  (fmtlib/fmt#4663,
  fmtlib/fmt#4671,
  fmtlib/fmt#4696,
  fmtlib/fmt#4693,
  fmtlib/fmt#4694,
  fmtlib/fmt#4712,
  fmtlib/fmt#4789).
  Thanks @soumik15630m, @Ferdi265 and @localspook.

- Added a separate `fmt::fmt-module` CMake target for C++20 modules and a
  CI workflow that exercises module-based builds
  (fmtlib/fmt#4684,
  fmtlib/fmt#4685,
  fmtlib/fmt#4707,
  fmtlib/fmt#4708,
  fmtlib/fmt#4702,
  fmtlib/fmt#4709).
  Thanks @MathewBensonCode.

- Enabled the full Dragonbox lookup cache by default for floating-point
  formatting unless optimizing for binary size (`__OPTIMIZE_SIZE__`),
  giving a ~10–25% speedup. Thanks Matthias Kretz for the suggestion.
  Average time per `double` on Apple M1 Pro (clang 17, random digits,
  smaller is better) measured with
  [dtoa-benchmark](https://github.com/fmtlib/dtoa-benchmark):

  | Method                  | Time (ns) |
  | ----------------------- | --------: |
  | fmt (full)              |     22.07 |
  | fmt (compact)           |     29.55 |
  | ryu                     |     35.21 |
  | double-conversion       |     81.81 |
  | `sprintf`               |    726.27 |
  | `ostringstream`         |    864.34 |

- Improved integer formatting performance by ~3%
  (fmtlib/fmt#4630). Thanks @user202729.

- Optimized formatting into back-insert iterators by using bulk container
  append/insert methods (e.g. on `std::vector<char>` and custom string
  types) (fmtlib/fmt#4679). Thanks @user202729.

- Reduced binary size of debug builds (~200k to ~85k in the bloat test) and
  improved compile speed when `consteval` is unavailable.

- Made path formatting lossless, preserving ill-formed UTF-16
  sequences when converting `std::filesystem::path` to a narrow string.

- Added support for formatting `std::unexpected`
  (fmtlib/fmt#4675). Thanks @17steen.

- Added overloads of `fmt::println` that take a `fmt::text_style`
  (fmtlib/fmt#4782). Thanks @ahoarau.

- Added support for positional arguments as width and precision specifiers
  in `fmt::printf` (fmtlib/fmt#4643).
  Thanks @KareemOtoum.

- Made `FMT_STRING` a no-op when `FMT_USE_CONSTEVAL` is enabled, since the
  consteval format-string constructor already provides compile-time
  validation
  (fmtlib/fmt#4611,
  fmtlib/fmt#4612). Thanks @friedkeenan.

- Promoted `fmt::detail::named_arg` to the public API as `fmt::named_arg` and
  deprecated the detail alias
  (fmtlib/fmt#4683,
  fmtlib/fmt#4687). Thanks @TPPPP72.

- Moved the `std::byte` formatter from `fmt/format.h` to `fmt/std.h`.

- Provided a default definition for `fmt::is_contiguous`
  (fmtlib/fmt#4731,
  fmtlib/fmt#4770). Thanks @user202729 and @phprus.

- Added the `FMT_USE_FLOCKFILE` macro to disable the use of `flockfile`
  (fmtlib/fmt#4646,
  fmtlib/fmt#4666). Thanks @mvastola.

- Added `include_guard(GLOBAL)` so that {fmt} can be used in multiple
  submodules of the same project
  (fmtlib/fmt#4672). Thanks @torsten48.

- Improved `constexpr` support
  (fmtlib/fmt#4659,
  fmtlib/fmt#4591).
  Thanks @elbeno and @17steen.

- Deprecated the implicit conversion from `fmt::format_string` and
  `fmt::basic_fstring` to `string_view` to align with `std::format_string`;
  use `format_string::get()` instead.

- Opted out `std::complex` from tuple formatting so that the dedicated
  `std::complex` formatter is always used.

- Removed the `fmt::say` function.

- Deprecated the `std::initializer_list` overload of `fmt::join` and the array
  overload of `fmt::vformat_to`.

- Made the `<fmt/core.h>` header equivalent to `<fmt/base.h>` by
  default. Code that relied on `<fmt/core.h>` pulling in `<fmt/format.h>`
  must now either include `<fmt/format.h>` directly or define
  `FMT_DEPRECATED_HEAVY_CORE` to opt back in.

- Improved `wchar_t` support: `fmt::join` now accepts `wchar_t` and other
  non-`char` separators, and `fmt::format_to_n` now works with `fmt::runtime`
  on `wchar_t`
  (fmtlib/fmt#4686,
  fmtlib/fmt#4714,
  fmtlib/fmt#4715).
  Thanks @Yancey2023 and @sunmy2019.

- Fixed formatting of `std::tm` with a null `tm_zone`
  (fmtlib/fmt#4790). Thanks @Carmel0.

- Fixed compile-time formatting in `fmt/ranges.h`, `fmt/style.h` and
  `fmt/std.h` (fmtlib/fmt#4759). Thanks @j4niwzis.

- Fixed an ambiguity between `formatter<std::optional<T>>` in `fmt/std.h`
  and `fmt/ranges.h` on C++26 (P3168R2)
  (fmtlib/fmt#4761). Thanks @phprus.

- Fixed a GCC PCH breakage triggered by a scoped `#pragma GCC optimize`.

- Fixed a TSAN false positive in the locale handling code
  (fmtlib/fmt#4755).

- Fixed compile-time format string checks truncating string literals at
  an embedded null byte
  (fmtlib/fmt#4732). Thanks @user202729.

- Fixed out-of-bounds reads in `printf` formatting
  (fmtlib/fmt#4741,
  fmtlib/fmt#4742,
  fmtlib/fmt#4800).
  Thanks @Algunenano and @aizu-m.

- Fixed the return type of the `f(un)lockfile`   wrappers on Windows
  (fmtlib/fmt#4739). Thanks @mvastola.

- Worked around a CUDA issue when handling UTF-32 literals
  (fmtlib/fmt#4719). Thanks @Cazadorro.

- Fixed missing named-argument validation for compiled format strings
  (fmtlib/fmt#4638). Thanks @jaeheonshim.

- Fixed `fmt::format_to_n` in `<fmt/compile.h>` failing to compile when
  `<iterator>` is not transitively included
  (fmtlib/fmt#4615).

- Fixed handling of pointers in format string compilation with
  `FMT_BUILTIN_TYPES=0`.

- Stopped assuming nul termination of the format string in `fmt::printf`.
  Thanks @ZUENS2020 for reporting.

- Fixed a build error when locale support is disabled
  (fmtlib/fmt#4627). Thanks @marcel-behlau-elfin.

- Fixed a fallback range formatter for types with a `container_type` member
  (fmtlib/fmt#4123,
  fmtlib/fmt#4660). Thanks @soumik15630m.

- Fixed C++20 concept detection
  (fmtlib/fmt#4653). Thanks @tearfur.

- Fixed a clang compilation failure
  (fmtlib/fmt#4718). Thanks @mccakit.

- Fixed various MSVC warnings, including C4305 and conversion warnings on
  x86 (fmtlib/fmt#4668,
  fmtlib/fmt#4594).
  Thanks @kanren3 and @blizzard4591.

- Updated the Android Gradle Plugin to 9.x
  (fmtlib/fmt#4651,
  fmtlib/fmt#4658). Thanks @soumik15630m.

- Made various code, build and test improvements
  (fmtlib/fmt#4625,
  fmtlib/fmt#4639,
  fmtlib/fmt#4644,
  fmtlib/fmt#4656,
  fmtlib/fmt#4680,
  fmtlib/fmt#4681,
  fmtlib/fmt#4704,
  fmtlib/fmt#4710,
  fmtlib/fmt#4713,
  fmtlib/fmt#4729,
  fmtlib/fmt#4751,
  fmtlib/fmt#4758,
  fmtlib/fmt#4799).
  Thanks @ZephyrLykos, @togunchan, @KaganCanSit, @berndpetrovitsch,
  @Skylion007, @st0rmbtw, @localspook and @EXtremeExploit.

- Improved documentation, including a rewrite of the format string syntax,
  better handling of doxygen tags, documenting `output_file`, fixing CSS so
  that whitespace is displayed properly, and various smaller fixes
  (fmtlib/fmt#4622,
  fmtlib/fmt#4626,
  fmtlib/fmt#4631,
  fmtlib/fmt#4667,
  fmtlib/fmt#4616,
  fmtlib/fmt#4748).
  Thanks @heavywatal, @ZephyrLykos, @user202729, @ssszcmawo, @bigmoonbit
  and @Powerbyte7.

- Added building of release artifacts and SLSA provenance in CI, added a
  CodeQL workflow, and added the security policy in `.github/SECURITY.md`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants