Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 39 additions & 50 deletions libcxx/src/string.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ template string operator+ <char, char_traits<char>, allocator<char>>(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) {
Expand All @@ -92,7 +92,7 @@ inline void throw_from_string_invalid_arg(const string& func) {
// as_integer

template <typename V, typename S, typename F>
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<decltype(errno)> errno_save = errno;
Expand All @@ -109,42 +109,14 @@ inline V as_integer_helper(const string& func, const S& str, size_t* idx, int ba
}

template <typename V, typename S>
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<long>(func, s, idx, base, strtol);
if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)
throw_from_string_out_of_range(func);
return static_cast<int>(r);
}

template <>
inline long as_integer(const string& func, const string& s, size_t* idx, int base) {
return as_integer_helper<long>(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<unsigned long>(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<long long>(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<unsigned long long>(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<long>(func, s, idx, base, wcstol);
if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)
Expand All @@ -153,30 +125,30 @@ 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<long>(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<unsigned long>(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<long long>(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<unsigned long long>(func, s, idx, base, wcstoull);
}
#endif // _LIBCPP_HAS_WIDE_CHARACTERS

// as_float

template <typename V, typename S, typename F>
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<decltype(errno)> errno_save = errno;
Expand All @@ -193,54 +165,71 @@ inline V as_float_helper(const string& func, const S& str, size_t* idx, F f) {
}

template <typename V, typename S>
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<float>(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<double>(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<long double>(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<float>(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<double>(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<long double>(func, s, idx, wcstold);
}
#endif // _LIBCPP_HAS_WIDE_CHARACTERS

template <class Integer>
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<int>("stoi", str, idx, base); }
int stoi(const string& str, size_t* idx, int base) { return string_to_integer_impl<int>("stoi", str, idx, base); }

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

unsigned long stoul(const string& str, size_t* idx, int base) {
return as_integer<unsigned long>("stoul", str, idx, base);
return string_to_integer_impl<unsigned long>("stoul", str, idx, base);
}

long long stoll(const string& str, size_t* idx, int base) { return as_integer<long long>("stoll", str, idx, base); }
long long stoll(const string& str, size_t* idx, int base) {
return string_to_integer_impl<long long>("stoll", str, idx, base);
}

unsigned long long stoull(const string& str, size_t* idx, int base) {
return as_integer<unsigned long long>("stoull", str, idx, base);
return string_to_integer_impl<unsigned long long>("stoull", str, idx, base);
}

float stof(const string& str, size_t* idx) { return as_float<float>("stof", str, idx); }
Expand Down
94 changes: 94 additions & 0 deletions libcxx/test/benchmarks/containers/string_conversion.bench.cpp
Original file line number Diff line number Diff line change
@@ -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 <limits>
#include <string>

#include <benchmark/benchmark.h>

template <class CharT>
void string_to_arithmetic_impl(int& out, const std::basic_string<CharT>& str) {
out = std::stoi(str);
}

template <class CharT>
void string_to_arithmetic_impl(long& out, const std::basic_string<CharT>& str) {
out = std::stol(str);
}

template <class CharT>
void string_to_arithmetic_impl(long long& out, const std::basic_string<CharT>& str) {
out = std::stoll(str);
}

template <class CharT>
void string_to_arithmetic_impl(unsigned long& out, const std::basic_string<CharT>& str) {
out = std::stoul(str);
}

template <class CharT>
void string_to_arithmetic_impl(unsigned long long& out, const std::basic_string<CharT>& str) {
out = std::stoull(str);
}

template <class CharT>
void string_to_arithmetic_impl(float& out, const std::basic_string<CharT>& str) {
out = std::stof(str);
}

template <class CharT>
void string_to_arithmetic_impl(double& out, const std::basic_string<CharT>& str) {
out = std::stod(str);
}

template <class CharT>
void string_to_arithmetic_impl(long double& out, const std::basic_string<CharT>& str) {
out = std::stold(str);
}

template <class Integer>
std::string to_string_dispatch(char, Integer i) {
return std::to_string(i);
}

template <class Integer>
std::wstring to_string_dispatch(wchar_t, Integer i) {
return std::to_wstring(i);
}

template <class CharT, class Integer>
void BM_string_to_arithmetic(benchmark::State& state) {
std::basic_string<CharT> num = to_string_dispatch(CharT(), std::numeric_limits<Integer>::max());

for (auto _ : state) {
benchmark::DoNotOptimize(num);
Integer val;
string_to_arithmetic_impl(val, num);
}
}

BENCHMARK(BM_string_to_arithmetic<char, int>);
BENCHMARK(BM_string_to_arithmetic<char, long>);
BENCHMARK(BM_string_to_arithmetic<char, long long>);
BENCHMARK(BM_string_to_arithmetic<char, unsigned long>);
BENCHMARK(BM_string_to_arithmetic<char, unsigned long long>);
BENCHMARK(BM_string_to_arithmetic<char, float>);
BENCHMARK(BM_string_to_arithmetic<char, double>);
BENCHMARK(BM_string_to_arithmetic<char, long double>);
BENCHMARK(BM_string_to_arithmetic<wchar_t, int>);
BENCHMARK(BM_string_to_arithmetic<wchar_t, long>);
BENCHMARK(BM_string_to_arithmetic<wchar_t, long long>);
BENCHMARK(BM_string_to_arithmetic<wchar_t, unsigned long>);
BENCHMARK(BM_string_to_arithmetic<wchar_t, unsigned long long>);
BENCHMARK(BM_string_to_arithmetic<char, float>);
BENCHMARK(BM_string_to_arithmetic<char, double>);
BENCHMARK(BM_string_to_arithmetic<char, long double>);

BENCHMARK_MAIN();
Loading