[libcxx-commits] [libcxx] [libc++] Refactor basic_filebuf::overflow() (PR #144793)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Fri Jun 20 09:02:55 PDT 2025


https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/144793

>From 73a7634f261d63e018ae338f53d7a308c2bc7006 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Tue, 17 Jun 2025 12:23:18 -0400
Subject: [PATCH 1/2] [libc++] Refactor basic_filebuf::overflow()

Refactor the function to streamline the logic so it matches the specification
in [filebuf.virtuals] more closely. In particular, avoid modifying the put
area pointers when we loop around after a partial codecvt conversion.

Note that we're technically not up-to-spec in this implementation, since
the Standard says that we shouldn't try more than once after a partial
codecvt conversion. However, this refactoring attempts not to change any
functionality.
---
 libcxx/include/fstream | 57 ++++++++++++++++++++++++++----------------
 1 file changed, 36 insertions(+), 21 deletions(-)

diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index 00aa00ff7e9cd..f9cbac2ab0578 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -835,35 +835,50 @@ typename basic_filebuf<_CharT, _Traits>::int_type basic_filebuf<_CharT, _Traits>
   }
   if (this->pptr() != this->pbase()) {
     if (__always_noconv_) {
-      size_t __nmemb = static_cast<size_t>(this->pptr() - this->pbase());
-      if (std::fwrite(this->pbase(), sizeof(char_type), __nmemb, __file_) != __nmemb)
+      size_t __n = static_cast<size_t>(this->pptr() - this->pbase());
+      if (std::fwrite(this->pbase(), sizeof(char_type), __n, __file_) != __n)
         return traits_type::eof();
     } else {
-      char* __extbe = __extbuf_;
-      codecvt_base::result __r;
+      if (!__cv_)
+        std::__throw_bad_cast();
+
+      // See [filebuf.virtuals]
+      char_type* __b = this->pbase();
+      char_type* __p = this->pptr();
+      const char_type* __end;
+      char* __extbuf_end = __extbuf_;
       do {
-        if (!__cv_)
-          std::__throw_bad_cast();
-
-        const char_type* __e;
-        __r = __cv_->out(__st_, this->pbase(), this->pptr(), __e, __extbuf_, __extbuf_ + __ebs_, __extbe);
-        if (__e == this->pbase())
+        codecvt_base::result __r = __cv_->out(__st_, __b, __p, __end, __extbuf_, __extbuf_ + __ebs_, __extbuf_end);
+        if (__end == __b)
           return traits_type::eof();
+
+        // No conversion needed: output characters directly to the file, done.
         if (__r == codecvt_base::noconv) {
-          size_t __nmemb = static_cast<size_t>(this->pptr() - this->pbase());
-          if (std::fwrite(this->pbase(), 1, __nmemb, __file_) != __nmemb)
+          size_t __n = static_cast<size_t>(__p - __b);
+          if (std::fwrite(__b, 1, __n, __file_) != __n)
             return traits_type::eof();
-        } else if (__r == codecvt_base::ok || __r == codecvt_base::partial) {
-          size_t __nmemb = static_cast<size_t>(__extbe - __extbuf_);
-          if (std::fwrite(__extbuf_, 1, __nmemb, __file_) != __nmemb)
+          break;
+
+          // Conversion successful: output the converted characters to the file, done.
+        } else if (__r == codecvt_base::ok) {
+          size_t __n = static_cast<size_t>(__extbuf_end - __extbuf_);
+          if (std::fwrite(__extbuf_, 1, __n, __file_) != __n)
+            return traits_type::eof();
+          break;
+
+          // Conversion partially successful: output converted characters to the file and repeat with the
+          // remaining characters.
+        } else if (__r == codecvt_base::partial) {
+          size_t __n = static_cast<size_t>(__extbuf_end - __extbuf_);
+          if (std::fwrite(__extbuf_, 1, __n, __file_) != __n)
             return traits_type::eof();
-          if (__r == codecvt_base::partial) {
-            this->setp(const_cast<char_type*>(__e), this->pptr());
-            this->__pbump(this->epptr() - this->pbase());
-          }
-        } else
+          __b = const_cast<char_type*>(__end);
+          continue;
+
+        } else {
           return traits_type::eof();
-      } while (__r == codecvt_base::partial);
+        }
+      } while (true);
     }
     this->setp(__pb_save, __epb_save);
   }

>From 98f6169a69fe647baf2aea537932724271841c46 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Fri, 20 Jun 2025 12:01:05 -0400
Subject: [PATCH 2/2] Use early return

---
 libcxx/include/fstream | 92 ++++++++++++++++++++++--------------------
 1 file changed, 48 insertions(+), 44 deletions(-)

diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index f9cbac2ab0578..c86f709bedb80 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -833,55 +833,59 @@ typename basic_filebuf<_CharT, _Traits>::int_type basic_filebuf<_CharT, _Traits>
     *this->pptr() = traits_type::to_char_type(__c);
     this->pbump(1);
   }
-  if (this->pptr() != this->pbase()) {
-    if (__always_noconv_) {
-      size_t __n = static_cast<size_t>(this->pptr() - this->pbase());
-      if (std::fwrite(this->pbase(), sizeof(char_type), __n, __file_) != __n)
+
+  // There is nothing to write, early return
+  if (this->pptr() == this->pbase()) {
+    return traits_type::not_eof(__c);
+  }
+
+  if (__always_noconv_) {
+    size_t __n = static_cast<size_t>(this->pptr() - this->pbase());
+    if (std::fwrite(this->pbase(), sizeof(char_type), __n, __file_) != __n)
+      return traits_type::eof();
+  } else {
+    if (!__cv_)
+      std::__throw_bad_cast();
+
+    // See [filebuf.virtuals]
+    char_type* __b = this->pbase();
+    char_type* __p = this->pptr();
+    const char_type* __end;
+    char* __extbuf_end = __extbuf_;
+    do {
+      codecvt_base::result __r = __cv_->out(__st_, __b, __p, __end, __extbuf_, __extbuf_ + __ebs_, __extbuf_end);
+      if (__end == __b)
         return traits_type::eof();
-    } else {
-      if (!__cv_)
-        std::__throw_bad_cast();
-
-      // See [filebuf.virtuals]
-      char_type* __b = this->pbase();
-      char_type* __p = this->pptr();
-      const char_type* __end;
-      char* __extbuf_end = __extbuf_;
-      do {
-        codecvt_base::result __r = __cv_->out(__st_, __b, __p, __end, __extbuf_, __extbuf_ + __ebs_, __extbuf_end);
-        if (__end == __b)
+
+      // No conversion needed: output characters directly to the file, done.
+      if (__r == codecvt_base::noconv) {
+        size_t __n = static_cast<size_t>(__p - __b);
+        if (std::fwrite(__b, 1, __n, __file_) != __n)
           return traits_type::eof();
+        break;
 
-        // No conversion needed: output characters directly to the file, done.
-        if (__r == codecvt_base::noconv) {
-          size_t __n = static_cast<size_t>(__p - __b);
-          if (std::fwrite(__b, 1, __n, __file_) != __n)
-            return traits_type::eof();
-          break;
-
-          // Conversion successful: output the converted characters to the file, done.
-        } else if (__r == codecvt_base::ok) {
-          size_t __n = static_cast<size_t>(__extbuf_end - __extbuf_);
-          if (std::fwrite(__extbuf_, 1, __n, __file_) != __n)
-            return traits_type::eof();
-          break;
-
-          // Conversion partially successful: output converted characters to the file and repeat with the
-          // remaining characters.
-        } else if (__r == codecvt_base::partial) {
-          size_t __n = static_cast<size_t>(__extbuf_end - __extbuf_);
-          if (std::fwrite(__extbuf_, 1, __n, __file_) != __n)
-            return traits_type::eof();
-          __b = const_cast<char_type*>(__end);
-          continue;
-
-        } else {
+        // Conversion successful: output the converted characters to the file, done.
+      } else if (__r == codecvt_base::ok) {
+        size_t __n = static_cast<size_t>(__extbuf_end - __extbuf_);
+        if (std::fwrite(__extbuf_, 1, __n, __file_) != __n)
           return traits_type::eof();
-        }
-      } while (true);
-    }
-    this->setp(__pb_save, __epb_save);
+        break;
+
+        // Conversion partially successful: output converted characters to the file and repeat with the
+        // remaining characters.
+      } else if (__r == codecvt_base::partial) {
+        size_t __n = static_cast<size_t>(__extbuf_end - __extbuf_);
+        if (std::fwrite(__extbuf_, 1, __n, __file_) != __n)
+          return traits_type::eof();
+        __b = const_cast<char_type*>(__end);
+        continue;
+
+      } else {
+        return traits_type::eof();
+      }
+    } while (true);
   }
+  this->setp(__pb_save, __epb_save);
   return traits_type::not_eof(__c);
 }
 



More information about the libcxx-commits mailing list