diff options
| author | Jonathan Wakely <jwakely@redhat.com> | 2019-06-12 15:52:02 +0100 |
|---|---|---|
| committer | Jonathan Wakely <redi@gcc.gnu.org> | 2019-06-12 15:52:02 +0100 |
| commit | cd0b94e650a880b2ab04922e476aa28007277d5c (patch) | |
| tree | 392d0abf2fbedc380e69b203ddb9b74c775d072d /libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions | |
| parent | ff7b3aa51f8edd24fdc599d9f95a5cbf61aeb76e (diff) | |
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/testsuite/21_strings/basic_string/numeric_conversions')
| -rw-r--r-- | libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string.cc | 4 | ||||
| -rw-r--r-- | libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string_int.cc | 164 |
2 files changed, 165 insertions, 3 deletions
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string.cc index 11cb7c8a451..a3dab3e54ac 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string.cc @@ -20,7 +20,7 @@ // with this library; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. -// 21.4 Numeric Conversions [string.conversions] +// C++11 21.5 Numeric Conversions [string.conversions] #include <string> #include <testsuite_hooks.h> @@ -28,7 +28,6 @@ void test01() { - bool test = true; using namespace std; long long ll1 = -2; @@ -59,5 +58,4 @@ test01() int main() { test01(); - return 0; } diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string_int.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string_int.cc new file mode 100644 index 00000000000..8eb2a48bd30 --- /dev/null +++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string_int.cc @@ -0,0 +1,164 @@ +// { dg-options "-DSIMULATOR_TEST" { target simulator } } +// { dg-do run { target c++11 } } + +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// C++11 21.5 Numeric Conversions [string.conversions] + +#include <string> +#include <limits> +#include <cstdint> +#include <cstdio> +#include <testsuite_hooks.h> + +namespace test +{ +static char buf[100]; + +// Canonical version of std::to_string(int) as specified in the standard. +static std::string to_string(int val) +{ + std::string str; + const int len = std::snprintf(buf, sizeof(buf), "%d", val); + VERIFY( len < (int)sizeof(buf) ); + return std::string(buf, len); +} + +static std::string to_string(unsigned int val) +{ + std::string str; + const int len = std::snprintf(buf, sizeof(buf), "%u", val); + VERIFY( len < (int)sizeof(buf) ); + return std::string(buf, len); +} + +static std::string to_string(long val) +{ + std::string str; + const int len = std::snprintf(buf, sizeof(buf), "%ld", val); + VERIFY( len < (int)sizeof(buf) ); + return std::string(buf, len); +} + +static std::string to_string(unsigned long val) +{ + std::string str; + const int len = std::snprintf(buf, sizeof(buf), "%lu", val); + VERIFY( len < (int)sizeof(buf) ); + return std::string(buf, len); +} + +static std::string to_string(long long val) +{ + std::string str; + const int len = std::snprintf(buf, sizeof(buf), "%lld", val); + VERIFY( len < (int)sizeof(buf) ); + return std::string(buf, len); +} + +static std::string to_string(unsigned long long val) +{ + std::string str; + const int len = std::snprintf(buf, sizeof(buf), "%llu", val); + VERIFY( len < (int)sizeof(buf) ); + return std::string(buf, len); +} + +} // namespace test + +const std::uint_least32_t values[] = { + 0x10, 0x30, 0x50, 0x80, 0xc0, + 0x100, 0x180, 0x1c0, 0x200, 0x400, 0x800, 0xc00, + 0x1000, 0x1800, 0x2000, 0x4000, 0x8000, 0xc000, + 0x10000, 0x10101, 0x80000, 0x80706, 0xc0000, 0xccccc, + 0x100000, 0x101010, 0x800000, 0x807060, 0xc0fefe, 0xc1d2e3f, + 0x1000000, 0x1001000, 0x1008000, 0x1010000, 0x1080000, 0x1100000, 0x1234567, + 0x10000000, 0x10101010, 0x12345678, 0x80000010, 0x87654321, 0xaaaaaaaa, + 0xf0000000, 0xf0101010, 0xf0f00000, 0xf0f0f0f0, 0xf0ff0ff0, 0xff0ff00f, + 0xffff0000, 0xffff00f0, 0xffff0ff0, 0xffffff00 +}; + +const std::size_t empty_string_capacity = std::string().capacity(); + +#include <set> + +template<typename T> + void check_value(T val) + { + const std::string s = std::to_string(val); + const std::string expected = test::to_string(val); + VERIFY( s == expected ); + VERIFY( s[s.size()] == '\0' ); // null-terminator not overwritten! + if (s.size() > empty_string_capacity) + VERIFY( s.capacity() == s.size() ); // GNU-specific guarantee + } + +#ifdef SIMULATOR_TEST +const int width = 3; +#else +const int width = 16; +#endif + +template<typename T> + void check_values() + { +#ifdef SIMULATOR_TEST + check_value((T)-1); + check_value((T)0); + check_value((T)+1); +#endif + + for (auto v : values) + { + for (int i = -width; i < +width; ++i) + { + const T val = (T)v + i; + check_value(val); + } + + if (std::numeric_limits<T>::digits > 32) + { + for (auto v2 : values) + { + for (int i = -width; i < +width; ++i) + { + typename std::make_unsigned<T>::type hi = v2; + hi += i; + hi <<= 32; + const T val = T(hi) | v; + check_value(val); + } + } + } + } + } + +void test02() +{ + check_values<int>(); + check_values<unsigned int>(); + check_values<long>(); + check_values<unsigned long>(); + check_values<long long>(); + check_values<unsigned long long>(); +} + +int main() +{ + test02(); +} |
