[libcxx-commits] [libcxx] [libc++] Avoid heap allocation for default-precision double formatting (PR #212502)
via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Jul 28 07:11:15 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: Adib Pathan (adxb-pxthxn)
<details>
<summary>Changes</summary>
Fixes #<!-- -->211909.
## Summary
When formatting floating-point values with unspecified precision (`{}`), libc++ initializes `__float_buffer` precision to `_Traits::__max_fractional`. For `double`, that inflates the computed buffer size beyond the stack buffer threshold and causes an unnecessary heap allocation on the default path.
This patch uses the Standard's default precision (`6`) when no precision is specified, so the common `double` formatting path stays within the stack buffer.
Discussion on #<!-- -->211909 noted that simply increasing `__stack_buffer_size` is not ideal. @<!-- -->philnik777 suggested keeping the common case stack-backed rather than pessimistically reserving worst-case space (format into the stack buffer first, and only allocate if needed). This change follows that direction for the default-precision case by avoiding worst-case precision sizing up front.
## Test plan
- [x] Added regression in `libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.floating_point.pass.cpp`
- [x] Test verifies `std::format("{}", 1.23)` does not allocate (via `count_new.h`)
- [x] `ninja -C build runtimes-test-depends`
- [x] `build/bin/llvm-lit -sv build/runtimes/runtimes-bins/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.floating_point.pass.cpp`
---
Full diff: https://github.com/llvm/llvm-project/pull/212502.diff
2 Files Affected:
- (modified) libcxx/include/__format/formatter_floating_point.h (+1-1)
- (modified) libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.floating_point.pass.cpp (+10)
``````````diff
diff --git a/libcxx/include/__format/formatter_floating_point.h b/libcxx/include/__format/formatter_floating_point.h
index f4de8b927651a..8728f996e78f9 100644
--- a/libcxx/include/__format/formatter_floating_point.h
+++ b/libcxx/include/__format/formatter_floating_point.h
@@ -154,7 +154,7 @@ class __float_buffer {
// may be too much for some platforms. For these cases a better estimate is
// required.
explicit _LIBCPP_HIDE_FROM_ABI __float_buffer(int __precision)
- : __precision_(__precision != -1 ? __precision : _Traits::__max_fractional) {
+ : __precision_(__precision != -1 ? __precision : 6) {
// When the precision is larger than _Traits::__max_fractional the digits in
// the range (_Traits::__max_fractional, precision] will contain the value
// zero. There's no need to request to_chars to write these zeros:
diff --git a/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.floating_point.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.floating_point.pass.cpp
index 3ad84577b90d2..fb410591ab7c5 100644
--- a/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.floating_point.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.floating_point.pass.cpp
@@ -42,6 +42,7 @@
#include "test_format_context.h"
#include "test_macros.h"
#include "make_string.h"
+#include "count_new.h"
#define STR(S) MAKE_STRING(CharT, S)
@@ -562,11 +563,20 @@ void test_all_float_types() {
test_float_type<long double, CharT>();
}
+void test_default_precision_double_does_not_allocate() {
+ globalMemCounter.reset();
+ DisableAllocationGuard g;
+ std::string result = std::format("{}", 1.23);
+ g.release();
+ assert(result == "1.23");
+}
+
int main(int, char**) {
test_all_float_types<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test_all_float_types<wchar_t>();
#endif
+ test_default_precision_double_does_not_allocate();
return 0;
}
``````````
</details>
https://github.com/llvm/llvm-project/pull/212502
More information about the libcxx-commits
mailing list