Skip to content

Commit 12ed602

Browse files
ldionnegithub-actions[bot]
authored andcommitted
Automerge: [libc++] Refactor basic_filebuf::overflow() (#144793)
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.
2 parents 53a260a + 52b27c2 commit 12ed602

File tree

1 file changed

+48
-29
lines changed

1 file changed

+48
-29
lines changed

libcxx/include/fstream

Lines changed: 48 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -834,40 +834,59 @@ typename basic_filebuf<_CharT, _Traits>::int_type basic_filebuf<_CharT, _Traits>
834834
*this->pptr() = traits_type::to_char_type(__c);
835835
this->pbump(1);
836836
}
837-
if (this->pptr() != this->pbase()) {
838-
if (__always_noconv_) {
839-
size_t __nmemb = static_cast<size_t>(this->pptr() - this->pbase());
840-
if (std::fwrite(this->pbase(), sizeof(char_type), __nmemb, __file_) != __nmemb)
837+
838+
// There is nothing to write, early return
839+
if (this->pptr() == this->pbase()) {
840+
return traits_type::not_eof(__c);
841+
}
842+
843+
if (__always_noconv_) {
844+
size_t __n = static_cast<size_t>(this->pptr() - this->pbase());
845+
if (std::fwrite(this->pbase(), sizeof(char_type), __n, __file_) != __n)
846+
return traits_type::eof();
847+
} else {
848+
if (!__cv_)
849+
std::__throw_bad_cast();
850+
851+
// See [filebuf.virtuals]
852+
char_type* __b = this->pbase();
853+
char_type* __p = this->pptr();
854+
const char_type* __end;
855+
char* __extbuf_end = __extbuf_;
856+
do {
857+
codecvt_base::result __r = __cv_->out(__st_, __b, __p, __end, __extbuf_, __extbuf_ + __ebs_, __extbuf_end);
858+
if (__end == __b)
841859
return traits_type::eof();
842-
} else {
843-
char* __extbe = __extbuf_;
844-
codecvt_base::result __r;
845-
do {
846-
if (!__cv_)
847-
std::__throw_bad_cast();
848860

849-
const char_type* __e;
850-
__r = __cv_->out(__st_, this->pbase(), this->pptr(), __e, __extbuf_, __extbuf_ + __ebs_, __extbe);
851-
if (__e == this->pbase())
861+
// No conversion needed: output characters directly to the file, done.
862+
if (__r == codecvt_base::noconv) {
863+
size_t __n = static_cast<size_t>(__p - __b);
864+
if (std::fwrite(__b, 1, __n, __file_) != __n)
852865
return traits_type::eof();
853-
if (__r == codecvt_base::noconv) {
854-
size_t __nmemb = static_cast<size_t>(this->pptr() - this->pbase());
855-
if (std::fwrite(this->pbase(), 1, __nmemb, __file_) != __nmemb)
856-
return traits_type::eof();
857-
} else if (__r == codecvt_base::ok || __r == codecvt_base::partial) {
858-
size_t __nmemb = static_cast<size_t>(__extbe - __extbuf_);
859-
if (std::fwrite(__extbuf_, 1, __nmemb, __file_) != __nmemb)
860-
return traits_type::eof();
861-
if (__r == codecvt_base::partial) {
862-
this->setp(const_cast<char_type*>(__e), this->pptr());
863-
this->__pbump(this->epptr() - this->pbase());
864-
}
865-
} else
866+
break;
867+
868+
// Conversion successful: output the converted characters to the file, done.
869+
} else if (__r == codecvt_base::ok) {
870+
size_t __n = static_cast<size_t>(__extbuf_end - __extbuf_);
871+
if (std::fwrite(__extbuf_, 1, __n, __file_) != __n)
866872
return traits_type::eof();
867-
} while (__r == codecvt_base::partial);
868-
}
869-
this->setp(__pb_save, __epb_save);
873+
break;
874+
875+
// Conversion partially successful: output converted characters to the file and repeat with the
876+
// remaining characters.
877+
} else if (__r == codecvt_base::partial) {
878+
size_t __n = static_cast<size_t>(__extbuf_end - __extbuf_);
879+
if (std::fwrite(__extbuf_, 1, __n, __file_) != __n)
880+
return traits_type::eof();
881+
__b = const_cast<char_type*>(__end);
882+
continue;
883+
884+
} else {
885+
return traits_type::eof();
886+
}
887+
} while (true);
870888
}
889+
this->setp(__pb_save, __epb_save);
871890
return traits_type::not_eof(__c);
872891
}
873892

0 commit comments

Comments
 (0)