[libcxx-commits] [libcxx] [libc++] Optimize num_put integral functions (PR #120859)
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Jan 15 06:39:32 PST 2025
================
@@ -1259,30 +1262,68 @@ num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob, char_ty
template <class _CharT, class _OutputIterator>
template <class _Integral>
_LIBCPP_HIDE_FROM_ABI inline _OutputIterator num_put<_CharT, _OutputIterator>::__do_put_integral(
- iter_type __s, ios_base& __iob, char_type __fl, _Integral __v, char const* __len) const {
+ iter_type __s, ios_base& __iob, char_type __fl, _Integral __v) const {
// Stage 1 - Get number in narrow char
- char __fmt[8] = {'%', 0};
- this->__format_int(__fmt + 1, __len, is_signed<_Integral>::value, __iob.flags());
+
// Worst case is octal, with showbase enabled. Note that octal is always
// printed as an unsigned value.
using _Unsigned = typename make_unsigned<_Integral>::type;
- _LIBCPP_CONSTEXPR const unsigned __nbuf =
+ _LIBCPP_CONSTEXPR const unsigned __buffer_size =
(numeric_limits<_Unsigned>::digits / 3) // 1 char per 3 bits
+ ((numeric_limits<_Unsigned>::digits % 3) != 0) // round up
+ 2; // base prefix + terminating null character
- char __nar[__nbuf];
- _LIBCPP_DIAGNOSTIC_PUSH
- _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wformat-nonliteral")
- _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wformat-nonliteral")
- int __nc = __locale::__snprintf(__nar, sizeof(__nar), _LIBCPP_GET_C_LOCALE, __fmt, __v);
- _LIBCPP_DIAGNOSTIC_POP
- char* __ne = __nar + __nc;
- char* __np = this->__identify_padding(__nar, __ne, __iob);
+
+ char __char_buffer[__buffer_size];
+ char* __buffer_ptr = __char_buffer;
+
+ auto __flags = __iob.flags();
+
+ auto __basefield = (__flags & ios_base::basefield);
+
+ // Extract base
+ int __base = 10;
+ if (__basefield == ios_base::oct)
+ __base = 8;
+ else if (__basefield == ios_base::hex)
+ __base = 16;
+
+ // Print '-' and make the argument unsigned
+ auto __uval = std::__to_unsigned_like(__v);
+ if (__basefield != ios_base::oct && __basefield != ios_base::hex && __v < 0) {
+ *__buffer_ptr++ = '-';
+ __uval = std::__complement(__uval);
+ }
+
+ // Maybe add '+' prefix
+ if (std::is_signed<_Integral>::value && (__flags & ios_base::showpos) && __basefield != ios_base::oct &&
+ __basefield != ios_base::hex && __v > 0)
+ *__buffer_ptr++ = '+';
+
+ // Add base prefix
+ if (__flags & ios_base::showbase) {
+ if (__basefield == ios_base::oct) {
+ *__buffer_ptr++ = '0';
+ } else if (__basefield == ios_base::hex) {
+ *__buffer_ptr++ = '0';
+ *__buffer_ptr++ = (__flags & ios_base::uppercase ? 'X' : 'x');
+ }
+ }
+
+ auto __res = std::__to_chars_integral(__buffer_ptr, __char_buffer + __buffer_size, __uval, __base);
+ _LIBCPP_ASSERT_INTERNAL(__res.__ec == std::errc(), "to_chars failed!");
----------------
ldionne wrote:
```suggestion
_LIBCPP_ASSERT_INTERNAL(__res.__ec == std::errc(), "to_chars: invalid maximum buffer size computed?");
```
https://github.com/llvm/llvm-project/pull/120859
More information about the libcxx-commits
mailing list