Skip to content

Commit 73a7634

Browse files
committed
[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.
1 parent 86d1d6b commit 73a7634

File tree

1 file changed

+36
-21
lines changed

1 file changed

+36
-21
lines changed

libcxx/include/fstream

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -835,35 +835,50 @@ typename basic_filebuf<_CharT, _Traits>::int_type basic_filebuf<_CharT, _Traits>
835835
}
836836
if (this->pptr() != this->pbase()) {
837837
if (__always_noconv_) {
838-
size_t __nmemb = static_cast<size_t>(this->pptr() - this->pbase());
839-
if (std::fwrite(this->pbase(), sizeof(char_type), __nmemb, __file_) != __nmemb)
838+
size_t __n = static_cast<size_t>(this->pptr() - this->pbase());
839+
if (std::fwrite(this->pbase(), sizeof(char_type), __n, __file_) != __n)
840840
return traits_type::eof();
841841
} else {
842-
char* __extbe = __extbuf_;
843-
codecvt_base::result __r;
842+
if (!__cv_)
843+
std::__throw_bad_cast();
844+
845+
// See [filebuf.virtuals]
846+
char_type* __b = this->pbase();
847+
char_type* __p = this->pptr();
848+
const char_type* __end;
849+
char* __extbuf_end = __extbuf_;
844850
do {
845-
if (!__cv_)
846-
std::__throw_bad_cast();
847-
848-
const char_type* __e;
849-
__r = __cv_->out(__st_, this->pbase(), this->pptr(), __e, __extbuf_, __extbuf_ + __ebs_, __extbe);
850-
if (__e == this->pbase())
851+
codecvt_base::result __r = __cv_->out(__st_, __b, __p, __end, __extbuf_, __extbuf_ + __ebs_, __extbuf_end);
852+
if (__end == __b)
851853
return traits_type::eof();
854+
855+
// No conversion needed: output characters directly to the file, done.
852856
if (__r == codecvt_base::noconv) {
853-
size_t __nmemb = static_cast<size_t>(this->pptr() - this->pbase());
854-
if (std::fwrite(this->pbase(), 1, __nmemb, __file_) != __nmemb)
857+
size_t __n = static_cast<size_t>(__p - __b);
858+
if (std::fwrite(__b, 1, __n, __file_) != __n)
855859
return traits_type::eof();
856-
} else if (__r == codecvt_base::ok || __r == codecvt_base::partial) {
857-
size_t __nmemb = static_cast<size_t>(__extbe - __extbuf_);
858-
if (std::fwrite(__extbuf_, 1, __nmemb, __file_) != __nmemb)
860+
break;
861+
862+
// Conversion successful: output the converted characters to the file, done.
863+
} else if (__r == codecvt_base::ok) {
864+
size_t __n = static_cast<size_t>(__extbuf_end - __extbuf_);
865+
if (std::fwrite(__extbuf_, 1, __n, __file_) != __n)
866+
return traits_type::eof();
867+
break;
868+
869+
// Conversion partially successful: output converted characters to the file and repeat with the
870+
// remaining characters.
871+
} else if (__r == codecvt_base::partial) {
872+
size_t __n = static_cast<size_t>(__extbuf_end - __extbuf_);
873+
if (std::fwrite(__extbuf_, 1, __n, __file_) != __n)
859874
return traits_type::eof();
860-
if (__r == codecvt_base::partial) {
861-
this->setp(const_cast<char_type*>(__e), this->pptr());
862-
this->__pbump(this->epptr() - this->pbase());
863-
}
864-
} else
875+
__b = const_cast<char_type*>(__end);
876+
continue;
877+
878+
} else {
865879
return traits_type::eof();
866-
} while (__r == codecvt_base::partial);
880+
}
881+
} while (true);
867882
}
868883
this->setp(__pb_save, __epb_save);
869884
}

0 commit comments

Comments
 (0)