Avoid unnecessary copying when upper-casing or lower-casing ASCII string_view
PiperOrigin-RevId: 655151660
Change-Id: I1aeb8eaeb3892eebcd31f28c646677dc82a267af
diff --git a/absl/strings/ascii.cc b/absl/strings/ascii.cc
index 20a696a..2af13a6 100644
--- a/absl/strings/ascii.cc
+++ b/absl/strings/ascii.cc
@@ -180,7 +180,7 @@
// Force-inline so the compiler won't merge the short and long implementations.
template <bool ToUpper>
ABSL_ATTRIBUTE_ALWAYS_INLINE inline constexpr void AsciiStrCaseFoldImpl(
- absl::Nonnull<char*> p, size_t size) {
+ absl::Nonnull<char*> dst, absl::Nonnull<const char*> src, size_t size) {
// The upper- and lowercase versions of ASCII characters differ by only 1 bit.
// When we need to flip the case, we can xor with this bit to achieve the
// desired result. Note that the choice of 'a' and 'A' here is arbitrary. We
@@ -189,9 +189,9 @@
constexpr unsigned char kAsciiCaseBitFlip = 'a' ^ 'A';
for (size_t i = 0; i < size; ++i) {
- unsigned char v = static_cast<unsigned char>(p[i]);
+ unsigned char v = static_cast<unsigned char>(src[i]);
v ^= AsciiInAZRange<ToUpper>(v) ? kAsciiCaseBitFlip : 0;
- p[i] = static_cast<char>(v);
+ dst[i] = static_cast<char>(v);
}
}
@@ -201,17 +201,28 @@
// No-inline so the compiler won't merge the short and long implementations.
template <bool ToUpper>
ABSL_ATTRIBUTE_NOINLINE constexpr void AsciiStrCaseFoldLong(
- absl::Nonnull<char*> p, size_t size) {
+ absl::Nonnull<char*> dst, absl::Nonnull<const char*> src, size_t size) {
ABSL_ASSUME(size >= kCaseFoldThreshold);
- AsciiStrCaseFoldImpl<ToUpper>(p, size);
+ AsciiStrCaseFoldImpl<ToUpper>(dst, src, size);
}
// Splitting to short and long strings to allow vectorization decisions
// to be made separately in the long and short cases.
template <bool ToUpper>
-constexpr void AsciiStrCaseFold(absl::Nonnull<char*> p, size_t size) {
- size < kCaseFoldThreshold ? AsciiStrCaseFoldImpl<ToUpper>(p, size)
- : AsciiStrCaseFoldLong<ToUpper>(p, size);
+constexpr void AsciiStrCaseFold(absl::Nonnull<char*> dst,
+ absl::Nonnull<const char*> src, size_t size) {
+ size < kCaseFoldThreshold ? AsciiStrCaseFoldImpl<ToUpper>(dst, src, size)
+ : AsciiStrCaseFoldLong<ToUpper>(dst, src, size);
+}
+
+void AsciiStrToLower(absl::Nonnull<char*> dst, absl::Nonnull<const char*> src,
+ size_t n) {
+ return AsciiStrCaseFold<false>(dst, src, n);
+}
+
+void AsciiStrToUpper(absl::Nonnull<char*> dst, absl::Nonnull<const char*> src,
+ size_t n) {
+ return AsciiStrCaseFold<true>(dst, src, n);
}
static constexpr size_t ValidateAsciiCasefold() {
@@ -222,8 +233,8 @@
for (unsigned int i = 0; i < num_chars; ++i) {
uppered[i] = lowered[i] = static_cast<char>(i);
}
- AsciiStrCaseFold<false>(&lowered[0], num_chars);
- AsciiStrCaseFold<true>(&uppered[0], num_chars);
+ AsciiStrCaseFold<false>(&lowered[0], &lowered[0], num_chars);
+ AsciiStrCaseFold<true>(&uppered[0], &uppered[0], num_chars);
for (size_t i = 0; i < num_chars; ++i) {
const char ch = static_cast<char>(i),
ch_upper = ('a' <= ch && ch <= 'z' ? 'A' + (ch - 'a') : ch),
@@ -241,11 +252,13 @@
} // namespace ascii_internal
void AsciiStrToLower(absl::Nonnull<std::string*> s) {
- return ascii_internal::AsciiStrCaseFold<false>(&(*s)[0], s->size());
+ char* p = &(*s)[0];
+ return ascii_internal::AsciiStrCaseFold<false>(p, p, s->size());
}
void AsciiStrToUpper(absl::Nonnull<std::string*> s) {
- return ascii_internal::AsciiStrCaseFold<true>(&(*s)[0], s->size());
+ char* p = &(*s)[0];
+ return ascii_internal::AsciiStrCaseFold<true>(p, p, s->size());
}
void RemoveExtraAsciiWhitespace(absl::Nonnull<std::string*> str) {
diff --git a/absl/strings/ascii.h b/absl/strings/ascii.h
index c238f4d..591c451 100644
--- a/absl/strings/ascii.h
+++ b/absl/strings/ascii.h
@@ -59,6 +59,7 @@
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/nullability.h"
+#include "absl/strings/internal/resize_uninitialized.h"
#include "absl/strings/string_view.h"
namespace absl {
@@ -74,6 +75,12 @@
// Declaration for the array of characters to lower-case characters.
ABSL_DLL extern const char kToLower[256];
+void AsciiStrToLower(absl::Nonnull<char*> dst, absl::Nonnull<const char*> src,
+ size_t n);
+
+void AsciiStrToUpper(absl::Nonnull<char*> dst, absl::Nonnull<const char*> src,
+ size_t n);
+
} // namespace ascii_internal
// ascii_isalpha()
@@ -171,8 +178,9 @@
// Creates a lowercase string from a given absl::string_view.
ABSL_MUST_USE_RESULT inline std::string AsciiStrToLower(absl::string_view s) {
- std::string result(s);
- absl::AsciiStrToLower(&result);
+ std::string result;
+ strings_internal::STLStringResizeUninitialized(&result, s.size());
+ ascii_internal::AsciiStrToLower(&result[0], s.data(), s.size());
return result;
}
@@ -189,8 +197,9 @@
// Creates an uppercase string from a given absl::string_view.
ABSL_MUST_USE_RESULT inline std::string AsciiStrToUpper(absl::string_view s) {
- std::string result(s);
- absl::AsciiStrToUpper(&result);
+ std::string result;
+ strings_internal::STLStringResizeUninitialized(&result, s.size());
+ ascii_internal::AsciiStrToUpper(&result[0], s.data(), s.size());
return result;
}