mirror of
https://github.com/abseil/abseil-cpp.git
synced 2026-06-04 12:07:05 +08:00
Performance improvements for absl::AsciiStrToLower and absl::AsciiStrToUpper.
PiperOrigin-RevId: 575969640 Change-Id: If6ddc0a71debfe571c2739ec91fc99594bc36f88
This commit is contained in:
committed by
Copybara-Service
parent
a0b72adc35
commit
a6d9a9cdda
@@ -159,6 +159,20 @@ ABSL_DLL const char kToUpper[256] = {
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
// Returns whether `c` is in the a-z/A-Z range (w.r.t. `ToUpper`).
|
||||
// Implemented by:
|
||||
// 1. Pushing the a-z/A-Z range to [SCHAR_MIN, SCHAR_MIN + 26).
|
||||
// 2. Comparing to SCHAR_MIN + 26.
|
||||
template <bool ToUpper>
|
||||
constexpr bool AsciiInAZRange(unsigned char c) {
|
||||
constexpr unsigned char sub = (ToUpper ? 'a' : 'A') - SCHAR_MIN;
|
||||
constexpr signed char threshold = SCHAR_MIN + 26; // 26 = alphabet size.
|
||||
// Using unsigned arithmetic as overflows/underflows are well defined.
|
||||
unsigned char u = c - sub;
|
||||
// Using signed cmp, as SIMD unsigned cmp isn't available in many platforms.
|
||||
return static_cast<signed char>(u) < threshold;
|
||||
}
|
||||
|
||||
template <bool ToUpper>
|
||||
constexpr void AsciiStrCaseFold(char* p, char* end) {
|
||||
// The upper- and lowercase versions of ASCII characters differ by only 1 bit.
|
||||
@@ -168,15 +182,9 @@ constexpr void AsciiStrCaseFold(char* p, char* end) {
|
||||
// have the same single bit difference.
|
||||
constexpr unsigned char kAsciiCaseBitFlip = 'a' ^ 'A';
|
||||
|
||||
constexpr char ch_a = ToUpper ? 'a' : 'A';
|
||||
constexpr char ch_z = ToUpper ? 'z' : 'Z';
|
||||
for (; p < end; ++p) {
|
||||
unsigned char v = static_cast<unsigned char>(*p);
|
||||
// We use & instead of && to ensure this always stays branchless
|
||||
// We use static_cast<int> to suppress -Wbitwise-instead-of-logical
|
||||
bool is_in_range = static_cast<bool>(static_cast<int>(ch_a <= v) &
|
||||
static_cast<int>(v <= ch_z));
|
||||
v ^= is_in_range ? kAsciiCaseBitFlip : 0;
|
||||
v ^= AsciiInAZRange<ToUpper>(v) ? kAsciiCaseBitFlip : 0;
|
||||
*p = static_cast<char>(v);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,18 +105,28 @@ static void BM_StrToLower(benchmark::State& state) {
|
||||
const int size = state.range(0);
|
||||
std::string s(size, 'X');
|
||||
for (auto _ : state) {
|
||||
benchmark::DoNotOptimize(absl::AsciiStrToLower(s));
|
||||
benchmark::DoNotOptimize(s);
|
||||
std::string res = absl::AsciiStrToLower(s);
|
||||
benchmark::DoNotOptimize(res);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_StrToLower)->Range(1, 1 << 20);
|
||||
BENCHMARK(BM_StrToLower)
|
||||
->DenseRange(0, 32)
|
||||
->RangeMultiplier(2)
|
||||
->Range(64, 1 << 20);
|
||||
|
||||
static void BM_StrToUpper(benchmark::State& state) {
|
||||
const int size = state.range(0);
|
||||
std::string s(size, 'x');
|
||||
for (auto _ : state) {
|
||||
benchmark::DoNotOptimize(absl::AsciiStrToUpper(s));
|
||||
benchmark::DoNotOptimize(s);
|
||||
std::string res = absl::AsciiStrToUpper(s);
|
||||
benchmark::DoNotOptimize(res);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_StrToUpper)->Range(1, 1 << 20);
|
||||
BENCHMARK(BM_StrToUpper)
|
||||
->DenseRange(0, 32)
|
||||
->RangeMultiplier(2)
|
||||
->Range(64, 1 << 20);
|
||||
|
||||
} // namespace
|
||||
|
||||
Reference in New Issue
Block a user