Commit 65d7b6d4 by Abseil Team Committed by Copybara-Service

StrCat: do not use intermediate buffer when result fits in SSO.

PiperOrigin-RevId: 557811632
Change-Id: I370fa17d2fb82a1f1ca86f84529bae31b34b18e4
parent 9377c75b
......@@ -89,8 +89,11 @@
#include <algorithm>
#include <array>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <limits>
#include <string>
#include <type_traits>
#include <utility>
......@@ -98,7 +101,9 @@
#include "absl/base/attributes.h"
#include "absl/base/port.h"
#include "absl/meta/type_traits.h"
#include "absl/strings/internal/has_absl_stringify.h"
#include "absl/strings/internal/resize_uninitialized.h"
#include "absl/strings/internal/stringify_sink.h"
#include "absl/strings/numbers.h"
#include "absl/strings/string_view.h"
......@@ -444,10 +449,69 @@ std::string CatPieces(std::initializer_list<absl::string_view> pieces);
void AppendPieces(std::string* dest,
std::initializer_list<absl::string_view> pieces);
template <typename Integer>
std::string IntegerToString(Integer i) {
// Any integer (signed/unsigned) up to 64 bits can be formatted into a buffer
// with 22 bytes (including NULL at the end).
constexpr size_t kMaxDigits10 = 22;
std::string result;
strings_internal::STLStringResizeUninitialized(&result, kMaxDigits10);
char* start = &result[0];
// note: this can be optimized to not write last zero.
char* end = numbers_internal::FastIntToBuffer(i, start);
auto size = static_cast<size_t>(end - start);
assert((size < result.size()) &&
"StrCat(Integer) does not fit into kMaxDigits10");
result.erase(size);
return result;
}
template <typename Float>
std::string FloatToString(Float f) {
std::string result;
strings_internal::STLStringResizeUninitialized(
&result, numbers_internal::kSixDigitsToBufferSize);
char* start = &result[0];
result.erase(numbers_internal::SixDigitsToBuffer(f, start));
return result;
}
// `SingleArgStrCat` overloads take built-in `int`, `long` and `long long` types
// (signed / unsigned) to avoid ambiguity on the call side. If we used int32_t
// and int64_t, then at least one of the three (`int` / `long` / `long long`)
// would have been ambiguous when passed to `SingleArgStrCat`.
inline std::string SingleArgStrCat(int x) { return IntegerToString(x); }
inline std::string SingleArgStrCat(unsigned int x) {
return IntegerToString(x);
}
// NOLINTNEXTLINE
inline std::string SingleArgStrCat(long x) { return IntegerToString(x); }
// NOLINTNEXTLINE
inline std::string SingleArgStrCat(unsigned long x) {
return IntegerToString(x);
}
// NOLINTNEXTLINE
inline std::string SingleArgStrCat(long long x) { return IntegerToString(x); }
// NOLINTNEXTLINE
inline std::string SingleArgStrCat(unsigned long long x) {
return IntegerToString(x);
}
inline std::string SingleArgStrCat(float x) { return FloatToString(x); }
inline std::string SingleArgStrCat(double x) { return FloatToString(x); }
template <typename T, typename = std::enable_if_t<std::is_arithmetic<T>{} &&
!std::is_same<T, char>{}>>
using EnableIfFastCase = T;
} // namespace strings_internal
ABSL_MUST_USE_RESULT inline std::string StrCat() { return std::string(); }
template <typename T>
ABSL_MUST_USE_RESULT inline std::string StrCat(
strings_internal::EnableIfFastCase<T> a) {
return strings_internal::SingleArgStrCat(a);
}
ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a) {
return std::string(a.data(), a.size());
}
......
......@@ -188,4 +188,15 @@ void StrAppendConfig(B* benchmark) {
BENCHMARK(BM_StrAppend)->Apply(StrAppendConfig);
void BM_StrCat_int(benchmark::State& state) {
int i = 0;
for (auto s : state) {
std::string result = absl::StrCat(i);
benchmark::DoNotOptimize(result);
i = IncrementAlternatingSign(i);
}
}
BENCHMARK(BM_StrCat_int);
} // namespace
......@@ -665,4 +665,20 @@ TEST(StrCat, AbslStringifyWithEnum) {
EXPECT_EQ(absl::StrCat(e), "Choices");
}
template <typename Integer>
void CheckSingleArgumentIntegerLimits() {
Integer max = std::numeric_limits<Integer>::max();
Integer min = std::numeric_limits<Integer>::min();
EXPECT_EQ(absl::StrCat(max), std::to_string(max));
EXPECT_EQ(absl::StrCat(min), std::to_string(min));
}
TEST(StrCat, SingleArgumentLimits) {
CheckSingleArgumentIntegerLimits<int32_t>();
CheckSingleArgumentIntegerLimits<uint32_t>();
CheckSingleArgumentIntegerLimits<int64_t>();
CheckSingleArgumentIntegerLimits<uint64_t>();
}
} // namespace
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment