[libcxx-commits] [libcxx] 178a1fe - [libc++] Optimize string operator[] for known large inputs (#69500)

via libcxx-commits libcxx-commits at lists.llvm.org
Thu Oct 26 10:09:24 PDT 2023


Author: Ilya Tocar
Date: 2023-10-26T13:09:20-04:00
New Revision: 178a1fea57b542c39de79624662085f86f3e348f

URL: https://github.com/llvm/llvm-project/commit/178a1fea57b542c39de79624662085f86f3e348f
DIFF: https://github.com/llvm/llvm-project/commit/178a1fea57b542c39de79624662085f86f3e348f.diff

LOG: [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.

Added: 
    

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

Removed: 
    


################################################################################
diff  --git a/libcxx/include/string b/libcxx/include/string
index 91935162f02383a..cf9f0c847eb43af 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -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);
   }
 

diff  --git a/libcxx/test/std/strings/basic.string/string.access/index.pass.cpp b/libcxx/test/std/strings/basic.string/string.access/index.pass.cpp
index a270dd579667b1d..8ba8bf0c8b096bb 100644
--- a/libcxx/test/std/strings/basic.string/string.access/index.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.access/index.pass.cpp
@@ -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;


        


More information about the libcxx-commits mailing list