diff --git a/libcxx/src/string.cpp b/libcxx/src/string.cpp index 5028fc88fe46d..287a99db39be6 100644 --- a/libcxx/src/string.cpp +++ b/libcxx/src/string.cpp @@ -81,8 +81,8 @@ template string operator+ , allocator>(char const* namespace { -inline void throw_from_string_out_of_range(const string& func) { - std::__throw_out_of_range((func + ": out of range").c_str()); +inline void throw_from_string_out_of_range(const char* func) { + std::__throw_out_of_range((std::string(func) + ": out of range").c_str()); } inline void throw_from_string_invalid_arg(const string& func) { @@ -92,7 +92,7 @@ inline void throw_from_string_invalid_arg(const string& func) { // as_integer template -inline V as_integer_helper(const string& func, const S& str, size_t* idx, int base, F f) { +inline V as_integer_helper(const char* func, const S& str, size_t* idx, int base, F f) { typename S::value_type* ptr = nullptr; const typename S::value_type* const p = str.c_str(); __libcpp_remove_reference_t errno_save = errno; @@ -109,42 +109,14 @@ inline V as_integer_helper(const string& func, const S& str, size_t* idx, int ba } template -inline V as_integer(const string& func, const S& s, size_t* idx, int base); +inline V as_integer(const char* func, const S& s, size_t* idx, int base); // string -template <> -inline int as_integer(const string& func, const string& s, size_t* idx, int base) { - // Use long as no Standard string to integer exists. - long r = as_integer_helper(func, s, idx, base, strtol); - if (r < numeric_limits::min() || numeric_limits::max() < r) - throw_from_string_out_of_range(func); - return static_cast(r); -} - -template <> -inline long as_integer(const string& func, const string& s, size_t* idx, int base) { - return as_integer_helper(func, s, idx, base, strtol); -} - -template <> -inline unsigned long as_integer(const string& func, const string& s, size_t* idx, int base) { - return as_integer_helper(func, s, idx, base, strtoul); -} - -template <> -inline long long as_integer(const string& func, const string& s, size_t* idx, int base) { - return as_integer_helper(func, s, idx, base, strtoll); -} - -template <> -inline unsigned long long as_integer(const string& func, const string& s, size_t* idx, int base) { - return as_integer_helper(func, s, idx, base, strtoull); -} #if _LIBCPP_HAS_WIDE_CHARACTERS // wstring template <> -inline int as_integer(const string& func, const wstring& s, size_t* idx, int base) { +inline int as_integer(const char* func, const wstring& s, size_t* idx, int base) { // Use long as no Stantard string to integer exists. long r = as_integer_helper(func, s, idx, base, wcstol); if (r < numeric_limits::min() || numeric_limits::max() < r) @@ -153,22 +125,22 @@ inline int as_integer(const string& func, const wstring& s, size_t* idx, int bas } template <> -inline long as_integer(const string& func, const wstring& s, size_t* idx, int base) { +inline long as_integer(const char* func, const wstring& s, size_t* idx, int base) { return as_integer_helper(func, s, idx, base, wcstol); } template <> -inline unsigned long as_integer(const string& func, const wstring& s, size_t* idx, int base) { +inline unsigned long as_integer(const char* func, const wstring& s, size_t* idx, int base) { return as_integer_helper(func, s, idx, base, wcstoul); } template <> -inline long long as_integer(const string& func, const wstring& s, size_t* idx, int base) { +inline long long as_integer(const char* func, const wstring& s, size_t* idx, int base) { return as_integer_helper(func, s, idx, base, wcstoll); } template <> -inline unsigned long long as_integer(const string& func, const wstring& s, size_t* idx, int base) { +inline unsigned long long as_integer(const char* func, const wstring& s, size_t* idx, int base) { return as_integer_helper(func, s, idx, base, wcstoull); } #endif // _LIBCPP_HAS_WIDE_CHARACTERS @@ -176,7 +148,7 @@ inline unsigned long long as_integer(const string& func, const wstring& s, size_ // as_float template -inline V as_float_helper(const string& func, const S& str, size_t* idx, F f) { +inline V as_float_helper(const char* func, const S& str, size_t* idx, F f) { typename S::value_type* ptr = nullptr; const typename S::value_type* const p = str.c_str(); __libcpp_remove_reference_t errno_save = errno; @@ -193,54 +165,71 @@ inline V as_float_helper(const string& func, const S& str, size_t* idx, F f) { } template -inline V as_float(const string& func, const S& s, size_t* idx = nullptr); +inline V as_float(const char* func, const S& s, size_t* idx = nullptr); template <> -inline float as_float(const string& func, const string& s, size_t* idx) { +inline float as_float(const char* func, const string& s, size_t* idx) { return as_float_helper(func, s, idx, strtof); } template <> -inline double as_float(const string& func, const string& s, size_t* idx) { +inline double as_float(const char* func, const string& s, size_t* idx) { return as_float_helper(func, s, idx, strtod); } template <> -inline long double as_float(const string& func, const string& s, size_t* idx) { +inline long double as_float(const char* func, const string& s, size_t* idx) { return as_float_helper(func, s, idx, strtold); } #if _LIBCPP_HAS_WIDE_CHARACTERS template <> -inline float as_float(const string& func, const wstring& s, size_t* idx) { +inline float as_float(const char* func, const wstring& s, size_t* idx) { return as_float_helper(func, s, idx, wcstof); } template <> -inline double as_float(const string& func, const wstring& s, size_t* idx) { +inline double as_float(const char* func, const wstring& s, size_t* idx) { return as_float_helper(func, s, idx, wcstod); } template <> -inline long double as_float(const string& func, const wstring& s, size_t* idx) { +inline long double as_float(const char* func, const wstring& s, size_t* idx) { return as_float_helper(func, s, idx, wcstold); } #endif // _LIBCPP_HAS_WIDE_CHARACTERS +template +Integer string_to_integer_impl(const char* func_name, const string& str, size_t* index, int base) { + Integer result; + from_chars_result status = std::from_chars(str.data(), str.data() + str.size(), result, base); + if (status.ec != std::errc()) { + if (status.ec == std::errc::result_out_of_range) + throw_from_string_out_of_range(func_name); + throw_from_string_invalid_arg(func_name); + } + if (index) + *index = status.ptr - str.data(); + + return result; +} + } // unnamed namespace -int stoi(const string& str, size_t* idx, int base) { return as_integer("stoi", str, idx, base); } +int stoi(const string& str, size_t* idx, int base) { return string_to_integer_impl("stoi", str, idx, base); } -long stol(const string& str, size_t* idx, int base) { return as_integer("stol", str, idx, base); } +long stol(const string& str, size_t* idx, int base) { return string_to_integer_impl("stol", str, idx, base); } unsigned long stoul(const string& str, size_t* idx, int base) { - return as_integer("stoul", str, idx, base); + return string_to_integer_impl("stoul", str, idx, base); } -long long stoll(const string& str, size_t* idx, int base) { return as_integer("stoll", str, idx, base); } +long long stoll(const string& str, size_t* idx, int base) { + return string_to_integer_impl("stoll", str, idx, base); +} unsigned long long stoull(const string& str, size_t* idx, int base) { - return as_integer("stoull", str, idx, base); + return string_to_integer_impl("stoull", str, idx, base); } float stof(const string& str, size_t* idx) { return as_float("stof", str, idx); } diff --git a/libcxx/test/benchmarks/containers/string_conversion.bench.cpp b/libcxx/test/benchmarks/containers/string_conversion.bench.cpp new file mode 100644 index 0000000000000..ee3a38ecdef40 --- /dev/null +++ b/libcxx/test/benchmarks/containers/string_conversion.bench.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03 + +#include +#include + +#include + +template +void string_to_arithmetic_impl(int& out, const std::basic_string& str) { + out = std::stoi(str); +} + +template +void string_to_arithmetic_impl(long& out, const std::basic_string& str) { + out = std::stol(str); +} + +template +void string_to_arithmetic_impl(long long& out, const std::basic_string& str) { + out = std::stoll(str); +} + +template +void string_to_arithmetic_impl(unsigned long& out, const std::basic_string& str) { + out = std::stoul(str); +} + +template +void string_to_arithmetic_impl(unsigned long long& out, const std::basic_string& str) { + out = std::stoull(str); +} + +template +void string_to_arithmetic_impl(float& out, const std::basic_string& str) { + out = std::stof(str); +} + +template +void string_to_arithmetic_impl(double& out, const std::basic_string& str) { + out = std::stod(str); +} + +template +void string_to_arithmetic_impl(long double& out, const std::basic_string& str) { + out = std::stold(str); +} + +template +std::string to_string_dispatch(char, Integer i) { + return std::to_string(i); +} + +template +std::wstring to_string_dispatch(wchar_t, Integer i) { + return std::to_wstring(i); +} + +template +void BM_string_to_arithmetic(benchmark::State& state) { + std::basic_string num = to_string_dispatch(CharT(), std::numeric_limits::max()); + + for (auto _ : state) { + benchmark::DoNotOptimize(num); + Integer val; + string_to_arithmetic_impl(val, num); + } +} + +BENCHMARK(BM_string_to_arithmetic); +BENCHMARK(BM_string_to_arithmetic); +BENCHMARK(BM_string_to_arithmetic); +BENCHMARK(BM_string_to_arithmetic); +BENCHMARK(BM_string_to_arithmetic); +BENCHMARK(BM_string_to_arithmetic); +BENCHMARK(BM_string_to_arithmetic); +BENCHMARK(BM_string_to_arithmetic); +BENCHMARK(BM_string_to_arithmetic); +BENCHMARK(BM_string_to_arithmetic); +BENCHMARK(BM_string_to_arithmetic); +BENCHMARK(BM_string_to_arithmetic); +BENCHMARK(BM_string_to_arithmetic); +BENCHMARK(BM_string_to_arithmetic); +BENCHMARK(BM_string_to_arithmetic); +BENCHMARK(BM_string_to_arithmetic); + +BENCHMARK_MAIN();