[libc++] Optimize string operator[] for known large inputs (#69500)

If we know that index is larger than SSO size, we know that we can't be
in SSO case, and should access the pointer. This removes extra check
from operator[] for inputs known at compile time to be larger than SSO.
This commit is contained in:
Ilya Tocar 2023-10-26 13:09:20 -04:00 committed by GitHub
parent 3e79f4d2c2
commit 178a1fea57
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 27 additions and 0 deletions

View File

@ -1198,11 +1198,17 @@ public:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference operator[](size_type __pos) const _NOEXCEPT {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__pos <= size(), "string index out of bounds");
if (__builtin_constant_p(__pos) && !__fits_in_sso(__pos)) {
return *(__get_long_pointer() + __pos);
}
return *(data() + __pos);
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference operator[](size_type __pos) _NOEXCEPT {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__pos <= size(), "string index out of bounds");
if (__builtin_constant_p(__pos) && !__fits_in_sso(__pos)) {
return *(__get_long_pointer() + __pos);
}
return *(__get_pointer() + __pos);
}

View File

@ -34,10 +34,31 @@ TEST_CONSTEXPR_CXX20 void test_string() {
assert(s2[0] == '\0');
}
// Same, but for the string that doesn't fit into SSO.
template <class S>
TEST_CONSTEXPR_CXX20 void test_string_long() {
S s("0123456789012345678901234567890123456789");
const S& cs = s;
ASSERT_SAME_TYPE(decltype(s[0]), typename S::reference);
ASSERT_SAME_TYPE(decltype(cs[0]), typename S::const_reference);
LIBCPP_ASSERT_NOEXCEPT(s[0]);
LIBCPP_ASSERT_NOEXCEPT(cs[0]);
for (typename S::size_type i = 0; i < cs.size(); ++i) {
assert(s[i] == static_cast<char>('0' + (i % 10)));
assert(cs[i] == s[i]);
}
assert(s[33] == static_cast<char>('0' + (33 % 10)));
assert(cs[34] == s[34]);
assert(cs[cs.size()] == '\0');
const S s2 = S();
assert(s2[0] == '\0');
}
TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
test_string_long<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
#endif
return true;