Skip to content

Commit 90bfa6e

Browse files
committed
[libc++] Optimize string operator[] for known large inputs
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 e8fe4de commit 90bfa6e

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)