aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/include/std
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2019-06-12 15:52:02 +0100
committerJonathan Wakely <redi@gcc.gnu.org>2019-06-12 15:52:02 +0100
commitcd0b94e650a880b2ab04922e476aa28007277d5c (patch)
tree392d0abf2fbedc380e69b203ddb9b74c775d072d /libstdc++-v3/include/std
parentff7b3aa51f8edd24fdc599d9f95a5cbf61aeb76e (diff)
downloadgcc-cd0b94e650a880b2ab04922e476aa28007277d5c.zip
gcc-cd0b94e650a880b2ab04922e476aa28007277d5c.tar.gz
gcc-cd0b94e650a880b2ab04922e476aa28007277d5c.tar.bz2
Replace std::to_string for integers with optimized version
The std::to_chars functions from C++17 can be used to implement std::to_string with much better performance than calling snprintf. Only the __detail::__to_chars_len and __detail::__to_chars_10 functions are needed for to_string, because it always outputs base 10 representations. The return type of __detail::__to_chars_10 should not be declared before C++17, so the function body is extracted into a new function that can be reused by to_string and __detail::__to_chars_10. The existing tests for to_chars rely on to_string to check for correct answers. Now that they use the same code that doesn't actually ensure correctness, so add new tests for std::to_string that compare against printf output. * include/Makefile.am: Add new <bits/charconv.h> header. * include/Makefile.in: Regenerate. * include/bits/basic_string.h (to_string(int), to_string(unsigned)) (to_string(long), to_string(unsigned long), to_string(long long)) (to_string(unsigned long long)): Rewrite to use __to_chars_10_impl. * include/bits/charconv.h: New header. (__detail::__to_chars_len): Move here from <charconv>. (__detail::__to_chars_10_impl): New function extracted from __detail::__to_chars_10. * include/std/charconv (__cpp_lib_to_chars): Add, but comment out. (__to_chars_unsigned_type): New class template that reuses __make_unsigned_selector_base::__select to pick a type. (__unsigned_least_t): Redefine as __to_chars_unsigned_type<T>::type. (__detail::__to_chars_len): Move to new header. (__detail::__to_chars_10): Add inline specifier. Move code doing the output to __detail::__to_chars_10_impl and call that. * include/std/version (__cpp_lib_to_chars): Add, but comment out. * testsuite/21_strings/basic_string/numeric_conversions/char/ to_string.cc: Fix reference in comment. Remove unused variable. * testsuite/21_strings/basic_string/numeric_conversions/char/ to_string_int.cc: New test. From-SVN: r272186
Diffstat (limited to 'libstdc++-v3/include/std')
-rw-r--r--libstdc++-v3/include/std/charconv75
-rw-r--r--libstdc++-v3/include/std/version1
2 files changed, 23 insertions, 53 deletions
diff --git a/libstdc++-v3/include/std/charconv b/libstdc++-v3/include/std/charconv
index 9f01d4c..a777f60 100644
--- a/libstdc++-v3/include/std/charconv
+++ b/libstdc++-v3/include/std/charconv
@@ -36,8 +36,11 @@
#include <type_traits>
#include <limits>
#include <cctype>
+#include <bits/charconv.h> // for __to_chars_len, __to_chars_10_impl
#include <bits/error_constants.h> // for std::errc
+// Define when floating point is supported: #define __cpp_lib_to_chars 201611L
+
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
@@ -76,42 +79,30 @@ namespace __detail
using __integer_to_chars_result_type
= enable_if_t<__is_int_to_chars_type<_Tp>::value, to_chars_result>;
+ // Pick an unsigned type of suitable size. This is used to reduce the
+ // number of specializations of __to_chars_len, __to_chars etc. that
+ // get instantiated. For example, to_chars<char> and to_chars<short>
+ // and to_chars<unsigned> will all use the same code, and so will
+ // to_chars<long> when sizeof(int) == sizeof(long).
template<typename _Tp>
- using __unsigned_least_t
- = conditional_t<(sizeof(_Tp) <= sizeof(int)), unsigned int,
- conditional_t<(sizeof(_Tp) <= sizeof(long)), unsigned long,
- conditional_t<(sizeof(_Tp) <= sizeof(long long)), unsigned long long,
-#if _GLIBCXX_USE_INT128
- conditional_t<(sizeof(_Tp) <= sizeof(__int128)), unsigned __int128,
-#endif
- void
+ struct __to_chars_unsigned_type : __make_unsigned_selector_base
+ {
+ using _UInts = _List<unsigned int, unsigned long, unsigned long long
#if _GLIBCXX_USE_INT128
- >
+ , unsigned __int128
#endif
- >>>;
+ >;
+ using type = typename __select<sizeof(_Tp), _UInts>::__type;
+ };
+
+ template<typename _Tp>
+ using __unsigned_least_t = typename __to_chars_unsigned_type<_Tp>::type;
// Generic implementation for arbitrary bases.
+ // Defined in <bits/charconv.h>.
template<typename _Tp>
constexpr unsigned
- __to_chars_len(_Tp __value, int __base = 10) noexcept
- {
- static_assert(is_integral<_Tp>::value, "implementation bug");
- static_assert(is_unsigned<_Tp>::value, "implementation bug");
-
- unsigned __n = 1;
- const int __b2 = __base * __base;
- const int __b3 = __b2 * __base;
- const int __b4 = __b3 * __base;
- for (;;)
- {
- if (__value < __base) return __n;
- if (__value < __b2) return __n + 1;
- if (__value < __b3) return __n + 2;
- if (__value < __b4) return __n + 3;
- __value /= (unsigned)__b4;
- __n += 4;
- }
- }
+ __to_chars_len(_Tp __value, int __base /* = 10 */) noexcept;
template<typename _Tp>
constexpr unsigned
@@ -242,7 +233,7 @@ namespace __detail
}
template<typename _Tp>
- __integer_to_chars_result_type<_Tp>
+ inline __integer_to_chars_result_type<_Tp>
__to_chars_10(char* __first, char* __last, _Tp __val) noexcept
{
static_assert(is_integral<_Tp>::value, "implementation bug");
@@ -259,29 +250,7 @@ namespace __detail
return __res;
}
- static constexpr char __digits[201] =
- "0001020304050607080910111213141516171819"
- "2021222324252627282930313233343536373839"
- "4041424344454647484950515253545556575859"
- "6061626364656667686970717273747576777879"
- "8081828384858687888990919293949596979899";
- unsigned __pos = __len - 1;
- while (__val >= 100)
- {
- auto const __num = (__val % 100) * 2;
- __val /= 100;
- __first[__pos] = __digits[__num + 1];
- __first[__pos - 1] = __digits[__num];
- __pos -= 2;
- }
- if (__val >= 10)
- {
- auto const __num = __val * 2;
- __first[__pos] = __digits[__num + 1];
- __first[__pos - 1] = __digits[__num];
- }
- else
- __first[__pos] = '0' + __val;
+ __detail::__to_chars_10_impl(__first, __len, __val);
__res.ptr = __first + __len;
__res.ec = {};
return __res;
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index 9da3854..cef4f1f 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -139,6 +139,7 @@
#endif
#define __cpp_lib_shared_ptr_weak_type 201606
#define __cpp_lib_string_view 201603
+// #define __cpp_lib_to_chars 201611L
#define __cpp_lib_type_trait_variable_templates 201510L
#define __cpp_lib_uncaught_exceptions 201411L
#define __cpp_lib_unordered_map_insertion 201411