Optimize `numberToString()`

This function is slower than it needs to be due to the expensive inserts at
the front of the string. The new version is 38 times faster for a 9-digit
number using GCC 13.2 with full optimizations according to Quick Bench.
This commit is contained in:
Martchus 2024-02-21 21:10:17 +01:00
parent a337452179
commit d8e144d312
1 changed files with 18 additions and 17 deletions

View File

@ -421,13 +421,15 @@ template <typename IntegralType, class StringType = std::string, typename BaseTy
CppUtilities::Traits::EnableIf<std::is_integral<IntegralType>, std::is_unsigned<IntegralType>> * = nullptr> CppUtilities::Traits::EnableIf<std::is_integral<IntegralType>, std::is_unsigned<IntegralType>> * = nullptr>
StringType numberToString(IntegralType number, BaseType base = 10) StringType numberToString(IntegralType number, BaseType base = 10)
{ {
std::size_t resSize = 0; auto resSize = std::size_t();
for (auto n = number; n; n /= static_cast<IntegralType>(base), ++resSize) auto n = number;
;
StringType res;
res.reserve(resSize);
do { do {
res.insert(res.begin(), digitToChar<typename StringType::value_type>(static_cast<typename StringType::value_type>(number % base))); n /= static_cast<IntegralType>(base), ++resSize;
} while (n);
auto res = StringType(resSize, typename StringType::value_type());
auto resIter = res.end();
do {
*(--resIter) = digitToChar<typename StringType::value_type>(static_cast<typename StringType::value_type>(number % static_cast<IntegralType>(base)));
number /= static_cast<IntegralType>(base); number /= static_cast<IntegralType>(base);
} while (number); } while (number);
return res; return res;
@ -443,24 +445,23 @@ template <typename IntegralType, class StringType = std::string, typename BaseTy
Traits::EnableIf<std::is_integral<IntegralType>, std::is_signed<IntegralType>> * = nullptr> Traits::EnableIf<std::is_integral<IntegralType>, std::is_signed<IntegralType>> * = nullptr>
StringType numberToString(IntegralType number, BaseType base = 10) StringType numberToString(IntegralType number, BaseType base = 10)
{ {
const bool negative = number < 0; const auto negative = number < 0;
std::size_t resSize; auto resSize = std::size_t();
if (negative) { if (negative) {
number = -number, resSize = 1; number = -number, resSize = 1;
} else {
resSize = 0;
} }
for (auto n = number; n; n /= static_cast<IntegralType>(base), ++resSize) auto n = number;
;
StringType res;
res.reserve(resSize);
do { do {
res.insert(res.begin(), n /= static_cast<IntegralType>(base), ++resSize;
digitToChar<typename StringType::value_type>(static_cast<typename StringType::value_type>(number % static_cast<IntegralType>(base)))); } while (n);
auto res = StringType(resSize, typename StringType::value_type());
auto resIter = res.end();
do {
*(--resIter) = digitToChar<typename StringType::value_type>(static_cast<typename StringType::value_type>(number % static_cast<IntegralType>(base)));
number /= static_cast<IntegralType>(base); number /= static_cast<IntegralType>(base);
} while (number); } while (number);
if (negative) { if (negative) {
res.insert(res.begin(), '-'); *(--resIter) = '-';
} }
return res; return res;
} }