Skip to content

Commit 178a1fe

Browse files
authored
[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.
1 parent 3e79f4d commit 178a1fe

File tree

2 files changed

+27
-0
lines changed

2 files changed

+27
-0
lines changed

libcxx/include/string

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1198,11 +1198,17 @@ public:
11981198

11991199
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference operator[](size_type __pos) const _NOEXCEPT {
12001200
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__pos <= size(), "string index out of bounds");
1201+
if (__builtin_constant_p(__pos) && !__fits_in_sso(__pos)) {
1202+
return *(__get_long_pointer() + __pos);
1203+
}
12011204
return *(data() + __pos);
12021205
}
12031206

12041207
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference operator[](size_type __pos) _NOEXCEPT {
12051208
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__pos <= size(), "string index out of bounds");
1209+
if (__builtin_constant_p(__pos) && !__fits_in_sso(__pos)) {
1210+
return *(__get_long_pointer() + __pos);
1211+
}
12061212
return *(__get_pointer() + __pos);
12071213
}
12081214

libcxx/test/std/strings/basic.string/string.access/index.pass.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,31 @@ TEST_CONSTEXPR_CXX20 void test_string() {
3434
assert(s2[0] == '\0');
3535
}
3636

37+
// Same, but for the string that doesn't fit into SSO.
38+
template <class S>
39+
TEST_CONSTEXPR_CXX20 void test_string_long() {
40+
S s("0123456789012345678901234567890123456789");
41+
const S& cs = s;
42+
ASSERT_SAME_TYPE(decltype(s[0]), typename S::reference);
43+
ASSERT_SAME_TYPE(decltype(cs[0]), typename S::const_reference);
44+
LIBCPP_ASSERT_NOEXCEPT(s[0]);
45+
LIBCPP_ASSERT_NOEXCEPT(cs[0]);
46+
for (typename S::size_type i = 0; i < cs.size(); ++i) {
47+
assert(s[i] == static_cast<char>('0' + (i % 10)));
48+
assert(cs[i] == s[i]);
49+
}
50+
assert(s[33] == static_cast<char>('0' + (33 % 10)));
51+
assert(cs[34] == s[34]);
52+
assert(cs[cs.size()] == '\0');
53+
const S s2 = S();
54+
assert(s2[0] == '\0');
55+
}
56+
3757
TEST_CONSTEXPR_CXX20 bool test() {
3858
test_string<std::string>();
3959
#if TEST_STD_VER >= 11
4060
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
61+
test_string_long<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
4162
#endif
4263

4364
return true;

0 commit comments

Comments
 (0)