diff options
Diffstat (limited to 'libstdc++-v3/include/bits/fstream.tcc')
-rw-r--r-- | libstdc++-v3/include/bits/fstream.tcc | 179 |
1 files changed, 147 insertions, 32 deletions
diff --git a/libstdc++-v3/include/bits/fstream.tcc b/libstdc++-v3/include/bits/fstream.tcc index c25d50142f4..31175559bb9 100644 --- a/libstdc++-v3/include/bits/fstream.tcc +++ b/libstdc++-v3/include/bits/fstream.tcc @@ -64,6 +64,11 @@ namespace std this->_M_buf = NULL; _M_buf_allocated = false; } + delete [] _M_ext_buf; + _M_ext_buf = NULL; + _M_ext_buf_size = 0; + _M_ext_next = NULL; + _M_ext_end = NULL; } template<typename _CharT, typename _Traits> @@ -73,7 +78,8 @@ namespace std _M_state_beg(__state_type()), _M_buf(NULL), _M_buf_size(BUFSIZ), _M_buf_allocated(false), _M_reading(false), _M_writing(false), _M_last_overflowed(false), _M_pback_cur_save(0), _M_pback_end_save(0), - _M_pback_init(false), _M_codecvt(0) + _M_pback_init(false), _M_codecvt(0), _M_ext_buf(0), _M_ext_buf_size(0), + _M_ext_next(0), _M_ext_end(0) { if (has_facet<__codecvt_type>(this->_M_buf_locale)) _M_codecvt = &use_facet<__codecvt_type>(this->_M_buf_locale); @@ -199,44 +205,92 @@ namespace std // Get and convert input sequence. const size_t __buflen = this->_M_buf_size > 1 ? this->_M_buf_size - 1 : 1; - streamsize __elen = 0; + + // Will be set to true if ::read() returns 0 indicating EOF. + bool __got_eof = false; + // Number of internal characters produced. streamsize __ilen = 0; if (__check_facet(_M_codecvt).always_noconv()) { - __elen = _M_file.xsgetn(reinterpret_cast<char*>(this->eback()), + __ilen = _M_file.xsgetn(reinterpret_cast<char*>(this->eback()), __buflen); - __ilen = __elen; + if (__ilen == 0) + __got_eof = true; } else { - // Worst-case number of external bytes. - // XXX Not done encoding() == -1. - const int __enc = _M_codecvt->encoding(); - const streamsize __blen = __enc > 0 ? __buflen * __enc : __buflen; - char* __buf = static_cast<char*>(__builtin_alloca(__blen)); - __elen = _M_file.xsgetn(__buf, __blen); - - const char* __eend; - char_type* __iend; - codecvt_base::result __r; - __r = _M_codecvt->in(_M_state_cur, __buf, __buf + __elen, - __eend, this->eback(), - this->eback() + __buflen, __iend); - if (__r == codecvt_base::ok || __r == codecvt_base::partial) - __ilen = __iend - this->eback(); - else if (__r == codecvt_base::noconv) + // Worst-case number of external bytes. + // XXX Not done encoding() == -1. + const int __enc = _M_codecvt->encoding(); + streamsize __blen; // Minimum buffer size. + streamsize __rlen; // Number of chars to read. + if (__enc > 0) + __blen = __rlen = __buflen * __enc; + else + { + __blen = __buflen + _M_codecvt->max_length() - 1; + __rlen = __buflen; + } + const streamsize __remainder = _M_ext_end - _M_ext_next; + __rlen = __rlen > __remainder ? __rlen - __remainder : 0; + + // Allocate buffer if necessary and move unconverted + // bytes to front. + if (_M_ext_buf_size < __blen) { - traits_type::copy(this->eback(), - reinterpret_cast<char_type*>(__buf), - __elen); - __ilen = __elen; + char* __buf = new char[__blen]; + if (__remainder > 0) + std::memcpy(__buf, _M_ext_next, __remainder); + + delete [] _M_ext_buf; + _M_ext_buf = __buf; + _M_ext_buf_size = __blen; } - else + else if (__remainder > 0) + std::memmove(_M_ext_buf, _M_ext_next, __remainder); + + _M_ext_next = _M_ext_buf; + _M_ext_end = _M_ext_buf + __remainder; + + do { - // Unwind. - __ilen = 0; - _M_file.seekoff(-__elen, ios_base::cur, ios_base::in); + if (__rlen > 0) + { + // Sanity check! + // This may fail if the return value of + // codecvt::max_length() is bogus. + if (_M_ext_end - _M_ext_buf + __rlen > _M_ext_buf_size) + std::abort(); + streamsize __elen = _M_file.xsgetn(_M_ext_end, __rlen); + if (__elen == 0) + __got_eof = true; + _M_ext_end += __elen; + } + + char_type* __iend; + codecvt_base::result __r; + __r = _M_codecvt->in(_M_state_cur, _M_ext_next, + _M_ext_end, _M_ext_next, this->eback(), + this->eback() + __buflen, __iend); + if (__r == codecvt_base::ok || __r == codecvt_base::partial) + __ilen = __iend - this->eback(); + else if (__r == codecvt_base::noconv) + { + size_t __avail = _M_ext_end - _M_ext_buf; + __ilen = std::min(__avail, __buflen); + traits_type::copy(this->eback(), + reinterpret_cast<char_type*>(_M_ext_buf), + __ilen); + _M_ext_next = _M_ext_buf + __ilen; + } + else + { + __ilen = 0; + break; + } + __rlen = 1; } + while (!__got_eof && __ilen == 0); } if (__ilen > 0) @@ -245,7 +299,7 @@ namespace std _M_reading = true; __ret = traits_type::to_int_type(*this->gptr()); } - else if (__elen == 0) + else if (__got_eof) { // If the actual end of file is reached, set 'uncommitted' // mode, thus allowing an immediate write without an @@ -438,6 +492,54 @@ namespace std return __elen && __elen == __plen; } + template<typename _CharT, typename _Traits> + streamsize + basic_filebuf<_CharT, _Traits>:: + xsputn(const _CharT* __s, streamsize __n) + { + streamsize __ret = 0; + + // Optimization in the always_noconv() case, to be generalized in the + // future: when __n is sufficiently large we write directly instead of + // using the buffer. + const bool __testout = this->_M_mode & ios_base::out; + if (__testout && !_M_reading + && __check_facet(_M_codecvt).always_noconv()) + { + // Measurement would reveal the best choice. + const streamsize __chunk = 1ul << 10; + streamsize __bufavail = this->epptr() - this->pptr(); + + // Don't mistake 'uncommitted' mode buffered with unbuffered. + if (!_M_writing && this->_M_buf_size > 1) + __bufavail = this->_M_buf_size - 1; + + const streamsize __limit = std::min(__chunk, __bufavail); + if (__n >= __limit) + { + const streamsize __buffill = this->pptr() - this->pbase(); + const char* __buf = reinterpret_cast<const char*>(this->pbase()); + __ret = _M_file.xsputn_2(__buf, __buffill, + reinterpret_cast<const char*>(__s), __n); + if (__ret == __buffill + __n) + { + _M_set_buffer(0); + _M_writing = true; + } + if (__ret > __buffill) + __ret -= __buffill; + else + __ret = 0; + } + else + __ret = __streambuf_type::xsputn(__s, __n); + } + else + __ret = __streambuf_type::xsputn(__s, __n); + + return __ret; + } + template<typename _CharT, typename _Traits> typename basic_filebuf<_CharT, _Traits>::__streambuf_type* basic_filebuf<_CharT, _Traits>:: @@ -491,7 +593,7 @@ namespace std // Ditch any pback buffers to avoid confusion. _M_destroy_pback(); - off_type __computed_off = __off; + off_type __computed_off = __off * __width; if (this->pbase() < this->pptr()) { // Part one: update the output sequence. @@ -501,13 +603,26 @@ namespace std _M_output_unshift(); } else if (_M_reading && __way == ios_base::cur) - __computed_off += this->gptr() - this->egptr(); + { + if (_M_codecvt->always_noconv()) + __computed_off += this->gptr() - this->egptr(); + else + { + // Calculate offset from _M_ext_buf that corresponds + // to gptr(). + const int __gptr_off = + _M_codecvt->length(_M_state_cur, _M_ext_buf, _M_ext_next, + this->gptr() - this->eback()); + __computed_off += _M_ext_buf + __gptr_off - _M_ext_end; + } + } // Returns pos_type(off_type(-1)) in case of failure. - __ret = _M_file.seekoff(__computed_off * __width, __way, __mode); + __ret = _M_file.seekoff(__computed_off, __way, __mode); _M_reading = false; _M_writing = false; + _M_ext_next = _M_ext_end = _M_ext_buf; _M_set_buffer(-1); } _M_last_overflowed = false; |