Skip to content

Commit 022468b

Browse files
committed
[libc++] Optimize string to integer functions
1 parent 138e0ff commit 022468b

File tree

2 files changed

+133
-50
lines changed

2 files changed

+133
-50
lines changed

libcxx/src/string.cpp

Lines changed: 39 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ template string operator+ <char, char_traits<char>, allocator<char>>(char const*
8181

8282
namespace {
8383

84-
inline void throw_from_string_out_of_range(const string& func) {
85-
std::__throw_out_of_range((func + ": out of range").c_str());
84+
inline void throw_from_string_out_of_range(const char* func) {
85+
std::__throw_out_of_range((std::string(func) + ": out of range").c_str());
8686
}
8787

8888
inline void throw_from_string_invalid_arg(const string& func) {
@@ -92,7 +92,7 @@ inline void throw_from_string_invalid_arg(const string& func) {
9292
// as_integer
9393

9494
template <typename V, typename S, typename F>
95-
inline V as_integer_helper(const string& func, const S& str, size_t* idx, int base, F f) {
95+
inline V as_integer_helper(const char* func, const S& str, size_t* idx, int base, F f) {
9696
typename S::value_type* ptr = nullptr;
9797
const typename S::value_type* const p = str.c_str();
9898
__libcpp_remove_reference_t<decltype(errno)> errno_save = errno;
@@ -109,42 +109,14 @@ inline V as_integer_helper(const string& func, const S& str, size_t* idx, int ba
109109
}
110110

111111
template <typename V, typename S>
112-
inline V as_integer(const string& func, const S& s, size_t* idx, int base);
112+
inline V as_integer(const char* func, const S& s, size_t* idx, int base);
113113

114114
// string
115-
template <>
116-
inline int as_integer(const string& func, const string& s, size_t* idx, int base) {
117-
// Use long as no Standard string to integer exists.
118-
long r = as_integer_helper<long>(func, s, idx, base, strtol);
119-
if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)
120-
throw_from_string_out_of_range(func);
121-
return static_cast<int>(r);
122-
}
123-
124-
template <>
125-
inline long as_integer(const string& func, const string& s, size_t* idx, int base) {
126-
return as_integer_helper<long>(func, s, idx, base, strtol);
127-
}
128-
129-
template <>
130-
inline unsigned long as_integer(const string& func, const string& s, size_t* idx, int base) {
131-
return as_integer_helper<unsigned long>(func, s, idx, base, strtoul);
132-
}
133-
134-
template <>
135-
inline long long as_integer(const string& func, const string& s, size_t* idx, int base) {
136-
return as_integer_helper<long long>(func, s, idx, base, strtoll);
137-
}
138-
139-
template <>
140-
inline unsigned long long as_integer(const string& func, const string& s, size_t* idx, int base) {
141-
return as_integer_helper<unsigned long long>(func, s, idx, base, strtoull);
142-
}
143115

144116
#if _LIBCPP_HAS_WIDE_CHARACTERS
145117
// wstring
146118
template <>
147-
inline int as_integer(const string& func, const wstring& s, size_t* idx, int base) {
119+
inline int as_integer(const char* func, const wstring& s, size_t* idx, int base) {
148120
// Use long as no Stantard string to integer exists.
149121
long r = as_integer_helper<long>(func, s, idx, base, wcstol);
150122
if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)
@@ -153,30 +125,30 @@ inline int as_integer(const string& func, const wstring& s, size_t* idx, int bas
153125
}
154126

155127
template <>
156-
inline long as_integer(const string& func, const wstring& s, size_t* idx, int base) {
128+
inline long as_integer(const char* func, const wstring& s, size_t* idx, int base) {
157129
return as_integer_helper<long>(func, s, idx, base, wcstol);
158130
}
159131

160132
template <>
161-
inline unsigned long as_integer(const string& func, const wstring& s, size_t* idx, int base) {
133+
inline unsigned long as_integer(const char* func, const wstring& s, size_t* idx, int base) {
162134
return as_integer_helper<unsigned long>(func, s, idx, base, wcstoul);
163135
}
164136

165137
template <>
166-
inline long long as_integer(const string& func, const wstring& s, size_t* idx, int base) {
138+
inline long long as_integer(const char* func, const wstring& s, size_t* idx, int base) {
167139
return as_integer_helper<long long>(func, s, idx, base, wcstoll);
168140
}
169141

170142
template <>
171-
inline unsigned long long as_integer(const string& func, const wstring& s, size_t* idx, int base) {
143+
inline unsigned long long as_integer(const char* func, const wstring& s, size_t* idx, int base) {
172144
return as_integer_helper<unsigned long long>(func, s, idx, base, wcstoull);
173145
}
174146
#endif // _LIBCPP_HAS_WIDE_CHARACTERS
175147

176148
// as_float
177149

178150
template <typename V, typename S, typename F>
179-
inline V as_float_helper(const string& func, const S& str, size_t* idx, F f) {
151+
inline V as_float_helper(const char* func, const S& str, size_t* idx, F f) {
180152
typename S::value_type* ptr = nullptr;
181153
const typename S::value_type* const p = str.c_str();
182154
__libcpp_remove_reference_t<decltype(errno)> errno_save = errno;
@@ -193,54 +165,71 @@ inline V as_float_helper(const string& func, const S& str, size_t* idx, F f) {
193165
}
194166

195167
template <typename V, typename S>
196-
inline V as_float(const string& func, const S& s, size_t* idx = nullptr);
168+
inline V as_float(const char* func, const S& s, size_t* idx = nullptr);
197169

198170
template <>
199-
inline float as_float(const string& func, const string& s, size_t* idx) {
171+
inline float as_float(const char* func, const string& s, size_t* idx) {
200172
return as_float_helper<float>(func, s, idx, strtof);
201173
}
202174

203175
template <>
204-
inline double as_float(const string& func, const string& s, size_t* idx) {
176+
inline double as_float(const char* func, const string& s, size_t* idx) {
205177
return as_float_helper<double>(func, s, idx, strtod);
206178
}
207179

208180
template <>
209-
inline long double as_float(const string& func, const string& s, size_t* idx) {
181+
inline long double as_float(const char* func, const string& s, size_t* idx) {
210182
return as_float_helper<long double>(func, s, idx, strtold);
211183
}
212184

213185
#if _LIBCPP_HAS_WIDE_CHARACTERS
214186
template <>
215-
inline float as_float(const string& func, const wstring& s, size_t* idx) {
187+
inline float as_float(const char* func, const wstring& s, size_t* idx) {
216188
return as_float_helper<float>(func, s, idx, wcstof);
217189
}
218190

219191
template <>
220-
inline double as_float(const string& func, const wstring& s, size_t* idx) {
192+
inline double as_float(const char* func, const wstring& s, size_t* idx) {
221193
return as_float_helper<double>(func, s, idx, wcstod);
222194
}
223195

224196
template <>
225-
inline long double as_float(const string& func, const wstring& s, size_t* idx) {
197+
inline long double as_float(const char* func, const wstring& s, size_t* idx) {
226198
return as_float_helper<long double>(func, s, idx, wcstold);
227199
}
228200
#endif // _LIBCPP_HAS_WIDE_CHARACTERS
229201

202+
template <class Integer>
203+
Integer string_to_integer_impl(const char* func_name, const string& str, size_t* index, int base) {
204+
Integer result;
205+
from_chars_result status = std::from_chars(str.data(), str.data() + str.size(), result, base);
206+
if (status.ec != std::errc()) {
207+
if (status.ec == std::errc::result_out_of_range)
208+
throw_from_string_out_of_range(func_name);
209+
throw_from_string_invalid_arg(func_name);
210+
}
211+
if (index)
212+
*index = status.ptr - str.data();
213+
214+
return result;
215+
}
216+
230217
} // unnamed namespace
231218

232-
int stoi(const string& str, size_t* idx, int base) { return as_integer<int>("stoi", str, idx, base); }
219+
int stoi(const string& str, size_t* idx, int base) { return string_to_integer_impl<int>("stoi", str, idx, base); }
233220

234-
long stol(const string& str, size_t* idx, int base) { return as_integer<long>("stol", str, idx, base); }
221+
long stol(const string& str, size_t* idx, int base) { return string_to_integer_impl<long>("stol", str, idx, base); }
235222

236223
unsigned long stoul(const string& str, size_t* idx, int base) {
237-
return as_integer<unsigned long>("stoul", str, idx, base);
224+
return string_to_integer_impl<unsigned long>("stoul", str, idx, base);
238225
}
239226

240-
long long stoll(const string& str, size_t* idx, int base) { return as_integer<long long>("stoll", str, idx, base); }
227+
long long stoll(const string& str, size_t* idx, int base) {
228+
return string_to_integer_impl<long long>("stoll", str, idx, base);
229+
}
241230

242231
unsigned long long stoull(const string& str, size_t* idx, int base) {
243-
return as_integer<unsigned long long>("stoull", str, idx, base);
232+
return string_to_integer_impl<unsigned long long>("stoull", str, idx, base);
244233
}
245234

246235
float stof(const string& str, size_t* idx) { return as_float<float>("stof", str, idx); }
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: c++03
10+
11+
#include <limits>
12+
#include <string>
13+
14+
#include <benchmark/benchmark.h>
15+
16+
template <class CharT>
17+
void string_to_arithmetic_impl(int& out, const std::basic_string<CharT>& str) {
18+
out = std::stoi(str);
19+
}
20+
21+
template <class CharT>
22+
void string_to_arithmetic_impl(long& out, const std::basic_string<CharT>& str) {
23+
out = std::stol(str);
24+
}
25+
26+
template <class CharT>
27+
void string_to_arithmetic_impl(long long& out, const std::basic_string<CharT>& str) {
28+
out = std::stoll(str);
29+
}
30+
31+
template <class CharT>
32+
void string_to_arithmetic_impl(unsigned long& out, const std::basic_string<CharT>& str) {
33+
out = std::stoul(str);
34+
}
35+
36+
template <class CharT>
37+
void string_to_arithmetic_impl(unsigned long long& out, const std::basic_string<CharT>& str) {
38+
out = std::stoull(str);
39+
}
40+
41+
template <class CharT>
42+
void string_to_arithmetic_impl(float& out, const std::basic_string<CharT>& str) {
43+
out = std::stof(str);
44+
}
45+
46+
template <class CharT>
47+
void string_to_arithmetic_impl(double& out, const std::basic_string<CharT>& str) {
48+
out = std::stod(str);
49+
}
50+
51+
template <class CharT>
52+
void string_to_arithmetic_impl(long double& out, const std::basic_string<CharT>& str) {
53+
out = std::stold(str);
54+
}
55+
56+
template <class Integer>
57+
std::string to_string_dispatch(char, Integer i) {
58+
return std::to_string(i);
59+
}
60+
61+
template <class Integer>
62+
std::wstring to_string_dispatch(wchar_t, Integer i) {
63+
return std::to_wstring(i);
64+
}
65+
66+
template <class CharT, class Integer>
67+
void BM_string_to_arithmetic(benchmark::State& state) {
68+
std::basic_string<CharT> num = to_string_dispatch(CharT(), std::numeric_limits<Integer>::max());
69+
70+
for (auto _ : state) {
71+
benchmark::DoNotOptimize(num);
72+
Integer val;
73+
string_to_arithmetic_impl(val, num);
74+
}
75+
}
76+
77+
BENCHMARK(BM_string_to_arithmetic<char, int>);
78+
BENCHMARK(BM_string_to_arithmetic<char, long>);
79+
BENCHMARK(BM_string_to_arithmetic<char, long long>);
80+
BENCHMARK(BM_string_to_arithmetic<char, unsigned long>);
81+
BENCHMARK(BM_string_to_arithmetic<char, unsigned long long>);
82+
BENCHMARK(BM_string_to_arithmetic<char, float>);
83+
BENCHMARK(BM_string_to_arithmetic<char, double>);
84+
BENCHMARK(BM_string_to_arithmetic<char, long double>);
85+
BENCHMARK(BM_string_to_arithmetic<wchar_t, int>);
86+
BENCHMARK(BM_string_to_arithmetic<wchar_t, long>);
87+
BENCHMARK(BM_string_to_arithmetic<wchar_t, long long>);
88+
BENCHMARK(BM_string_to_arithmetic<wchar_t, unsigned long>);
89+
BENCHMARK(BM_string_to_arithmetic<wchar_t, unsigned long long>);
90+
BENCHMARK(BM_string_to_arithmetic<char, float>);
91+
BENCHMARK(BM_string_to_arithmetic<char, double>);
92+
BENCHMARK(BM_string_to_arithmetic<char, long double>);
93+
94+
BENCHMARK_MAIN();

0 commit comments

Comments
 (0)