diff options
author | Abseil Team <absl-team@google.com> | 2023-08-17 07:04:14 -0700 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2023-08-17 07:05:33 -0700 |
commit | 65d7b6d421f780941dd585d7094f257a546e2510 (patch) | |
tree | 7751d97a393f4f6597b03d29957653b24244faed /absl/strings/str_cat.h | |
parent | 9377c75bf499af0018542c17abcedf659e094a1e (diff) |
StrCat: do not use intermediate buffer when result fits in SSO.
PiperOrigin-RevId: 557811632
Change-Id: I370fa17d2fb82a1f1ca86f84529bae31b34b18e4
Diffstat (limited to 'absl/strings/str_cat.h')
-rw-r--r-- | absl/strings/str_cat.h | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/absl/strings/str_cat.h b/absl/strings/str_cat.h index d5f71ff0..57a5823f 100644 --- a/absl/strings/str_cat.h +++ b/absl/strings/str_cat.h @@ -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()); } |