[libcxx-commits] [libcxx] [libc++] Optimize std::getline (PR #121346)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Wed Jan 29 08:07:05 PST 2025


================
@@ -1265,41 +1265,49 @@ _LIBCPP_HIDE_FROM_ABI basic_istream<_CharT, _Traits>&
 getline(basic_istream<_CharT, _Traits>& __is, basic_string<_CharT, _Traits, _Allocator>& __str, _CharT __dlm) {
   ios_base::iostate __state = ios_base::goodbit;
   typename basic_istream<_CharT, _Traits>::sentry __sen(__is, true);
-  if (__sen) {
+  if (!__sen)
+    return __is;
 #    if _LIBCPP_HAS_EXCEPTIONS
-    try {
+  try {
 #    endif
-      __str.clear();
-      streamsize __extr = 0;
-      while (true) {
-        typename _Traits::int_type __i = __is.rdbuf()->sbumpc();
-        if (_Traits::eq_int_type(__i, _Traits::eof())) {
-          __state |= ios_base::eofbit;
-          break;
-        }
-        ++__extr;
-        _CharT __ch = _Traits::to_char_type(__i);
-        if (_Traits::eq(__ch, __dlm))
-          break;
-        __str.push_back(__ch);
-        if (__str.size() == __str.max_size()) {
+    __str.clear();
+
+    auto& __buffer = *__is.rdbuf();
+
+    auto __next = __buffer.sgetc();
+    for (; !_Traits::eq_int_type(__next, _Traits::eof()); __next = __buffer.sgetc()) {
+      const auto* __first = __buffer.gptr();
+      const auto* __last  = __buffer.egptr();
+      const auto* __match = _Traits::find(__first, __last - __first, __dlm);
+      if (__match) {
+        if (auto __cap = __str.max_size() - __str.size(); __cap <= static_cast<size_t>(__match - __first)) {
+          __str.append(__first, __cap);
+          __buffer.__gbump_ptrdiff(__cap);
           __state |= ios_base::failbit;
           break;
         }
+        __str.append(__first, __match);
+        __buffer.__gbump_ptrdiff(__match - __first + 1);
+        break;
----------------
ldionne wrote:

```suggestion
        if (auto __cap = __str.max_size() - __str.size(); __cap <= static_cast<size_t>(__match - __first)) {
          __str.append(__first, __cap);
          __buffer.__gbump_ptrdiff(__cap);
          __state |= ios_base::failbit;
        } else {
          __str.append(__first, __match);
          __buffer.__gbump_ptrdiff(__match - __first + 1); // drop the delimiter from the stream even if we don't read it into the string
        }
        break;
```

And in fact you could also invert the `if` logic to handle the happy case first, IMO that reads more naturally.

https://github.com/llvm/llvm-project/pull/121346


More information about the libcxx-commits mailing list