📄 fstream.tcc
字号:
streamsize __plen; if (__check_facet(_M_codecvt).always_noconv()) { __elen = _M_file.xsputn(reinterpret_cast<char*>(__ibuf), __ilen); __plen = __ilen; } else { // Worst-case number of external bytes needed. // XXX Not done encoding() == -1. streamsize __blen = __ilen * _M_codecvt->max_length(); char* __buf = static_cast<char*>(__builtin_alloca(__blen)); char* __bend; const char_type* __iend; codecvt_base::result __r; __r = _M_codecvt->out(_M_state_cur, __ibuf, __ibuf + __ilen, __iend, __buf, __buf + __blen, __bend); if (__r == codecvt_base::ok || __r == codecvt_base::partial) __blen = __bend - __buf; else if (__r == codecvt_base::noconv) { // Same as the always_noconv case above. __buf = reinterpret_cast<char*>(__ibuf); __blen = __ilen; } else __throw_ios_failure(__N("basic_filebuf::_M_convert_to_external " "conversion error")); __elen = _M_file.xsputn(__buf, __blen); __plen = __blen; // Try once more for partial conversions. if (__r == codecvt_base::partial && __elen == __plen) { const char_type* __iresume = __iend; streamsize __rlen = this->pptr() - __iend; __r = _M_codecvt->out(_M_state_cur, __iresume, __iresume + __rlen, __iend, __buf, __buf + __blen, __bend); if (__r != codecvt_base::error) { __rlen = __bend - __buf; __elen = _M_file.xsputn(__buf, __rlen); __plen = __rlen; } else __throw_ios_failure(__N("basic_filebuf::_M_convert_to_external " "conversion error")); } } return __elen == __plen; } template<typename _CharT, typename _Traits> streamsize basic_filebuf<_CharT, _Traits>:: xsgetn(_CharT* __s, streamsize __n) { // Clear out pback buffer before going on to the real deal... streamsize __ret = 0; if (this->_M_pback_init) { if (__n > 0 && this->gptr() == this->eback()) { *__s++ = *this->gptr(); this->gbump(1); __ret = 1; --__n; } _M_destroy_pback(); } // Optimization in the always_noconv() case, to be generalized in the // future: when __n > __buflen we read directly instead of using the // buffer repeatedly. const bool __testin = this->_M_mode & ios_base::in; const streamsize __buflen = this->_M_buf_size > 1 ? this->_M_buf_size - 1 : 1; if (__n > __buflen && __check_facet(_M_codecvt).always_noconv() && __testin && !_M_writing) { // First, copy the chars already present in the buffer. const streamsize __avail = this->egptr() - this->gptr(); if (__avail != 0) { if (__avail == 1) *__s = *this->gptr(); else traits_type::copy(__s, this->gptr(), __avail); __s += __avail; this->gbump(__avail); __ret += __avail; __n -= __avail; } const streamsize __len = _M_file.xsgetn(reinterpret_cast<char*>(__s), __n); if (__len == -1) __throw_ios_failure(__N("basic_filebuf::xsgetn " "error reading the file")); __ret += __len; if (__len == __n) { _M_set_buffer(0); _M_reading = true; } else if (__len == 0) { // If end of file is reached, set 'uncommitted' // mode, thus allowing an immediate write without // an intervening seek. _M_set_buffer(-1); _M_reading = false; } } else __ret += __streambuf_type::xsgetn(__s, __n); return __ret; } template<typename _CharT, typename _Traits> streamsize basic_filebuf<_CharT, _Traits>:: xsputn(const _CharT* __s, streamsize __n) { // 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. streamsize __ret = 0; const bool __testout = this->_M_mode & ios_base::out; if (__check_facet(_M_codecvt).always_noconv() && __testout && !_M_reading) { // 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>:: setbuf(char_type* __s, streamsize __n) { if (!this->is_open()) if (__s == 0 && __n == 0) this->_M_buf_size = 1; else if (__s && __n > 0) { // This is implementation-defined behavior, and assumes that // an external char_type array of length __n exists and has // been pre-allocated. If this is not the case, things will // quickly blow up. When __n > 1, __n - 1 positions will be // used for the get area, __n - 1 for the put area and 1 // position to host the overflow char of a full put area. // When __n == 1, 1 position will be used for the get area // and 0 for the put area, as in the unbuffered case above. this->_M_buf = __s; this->_M_buf_size = __n; } return this; } // According to 27.8.1.4 p11 - 13, seekoff should ignore the last // argument (of type openmode). template<typename _CharT, typename _Traits> typename basic_filebuf<_CharT, _Traits>::pos_type basic_filebuf<_CharT, _Traits>:: seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode) { int __width = 0; if (_M_codecvt) __width = _M_codecvt->encoding(); if (__width < 0) __width = 0; pos_type __ret = pos_type(off_type(-1)); const bool __testfail = __off != 0 && __width <= 0; if (this->is_open() && !__testfail) { // Ditch any pback buffers to avoid confusion. _M_destroy_pback(); // Correct state at destination. Note that this is the correct // state for the current position during output, because // codecvt::unshift() returns the state to the initial state. // This is also the correct state at the end of the file because // an unshift sequence should have been written at the end. __state_type __state = _M_state_beg; off_type __computed_off = __off * __width; if (_M_reading && __way == ios_base::cur) { if (_M_codecvt->always_noconv()) __computed_off += this->gptr() - this->egptr(); else { // Calculate offset from _M_ext_buf that corresponds // to gptr(). Note: uses _M_state_last, which // corresponds to eback(). const int __gptr_off = _M_codecvt->length(_M_state_last, _M_ext_buf, _M_ext_next, this->gptr() - this->eback()); __computed_off += _M_ext_buf + __gptr_off - _M_ext_end; // _M_state_last is modified by codecvt::length() so // it now corresponds to gptr(). __state = _M_state_last; } } __ret = _M_seek(__computed_off, __way, __state); } return __ret; } // _GLIBCXX_RESOLVE_LIB_DEFECTS // 171. Strange seekpos() semantics due to joint position // According to the resolution of DR 171, seekpos should ignore the last // argument (of type openmode). template<typename _CharT, typename _Traits> typename basic_filebuf<_CharT, _Traits>::pos_type basic_filebuf<_CharT, _Traits>:: seekpos(pos_type __pos, ios_base::openmode) { pos_type __ret = pos_type(off_type(-1)); if (this->is_open()) { // Ditch any pback buffers to avoid confusion. _M_destroy_pback(); __ret = _M_seek(off_type(__pos), ios_base::beg, __pos.state()); } return __ret; } template<typename _CharT, typename _Traits> typename basic_filebuf<_CharT, _Traits>::pos_type basic_filebuf<_CharT, _Traits>:: _M_seek(off_type __off, ios_base::seekdir __way, __state_type __state) { pos_type __ret = pos_type(off_type(-1)); if (_M_terminate_output()) { // Returns pos_type(off_type(-1)) in case of failure. __ret = pos_type(_M_file.seekoff(__off, __way)); _M_reading = false; _M_writing = false; _M_ext_next = _M_ext_end = _M_ext_buf; _M_set_buffer(-1); _M_state_cur = __state; __ret.state(_M_state_cur); } return __ret; } template<typename _CharT, typename _Traits> bool basic_filebuf<_CharT, _Traits>:: _M_terminate_output() { // Part one: update the output sequence. bool __testvalid = true; if (this->pbase() < this->pptr()) { const int_type __tmp = this->overflow(); if (traits_type::eq_int_type(__tmp, traits_type::eof())) __testvalid = false; } // Part two: output unshift sequence. if (_M_writing && !__check_facet(_M_codecvt).always_noconv() && __testvalid) { // Note: this value is arbitrary, since there is no way to // get the length of the unshift sequence from codecvt, // without calling unshift. const size_t __blen = 128; char __buf[__blen]; codecvt_base::result __r; streamsize __ilen = 0; do { char* __next; __r = _M_codecvt->unshift(_M_state_cur, __buf, __buf + __blen, __next); if (__r == codecvt_base::error) __testvalid = false; else if (__r == codecvt_base::ok || __r == codecvt_base::partial) { __ilen = __next - __buf; if (__ilen > 0) { const streamsize __elen = _M_file.xsputn(__buf, __ilen); if (__elen != __ilen) __testvalid = false; } } } while (__r == codecvt_base::partial && __ilen > 0 && __testvalid); if (__testvalid) { // This second call to overflow() is required by the standard, // but it's not clear why it's needed, since the output buffer // should be empty by this point (it should have been emptied // in the first call to overflow()). const int_type __tmp = this->overflow(); if (traits_type::eq_int_type(__tmp, traits_type::eof())) __testvalid = false; } } return __testvalid; } template<typename _CharT, typename _Traits> int basic_filebuf<_CharT, _Traits>:: sync() { // Make sure that the internal buffer resyncs its idea of // the file position with the external file. int __ret = 0; if (this->pbase() < this->pptr()) { const int_type __tmp = this->overflow(); if (traits_type::eq_int_type(__tmp, traits_type::eof())) __ret = -1; } return __ret; } template<typename _CharT, typename _Traits> void basic_filebuf<_CharT, _Traits>:: imbue(const locale& __loc) { bool __testvalid = true; const __codecvt_type* _M_codecvt_tmp = 0; if (__builtin_expect(has_facet<__codecvt_type>(__loc), true)) _M_codecvt_tmp = &use_facet<__codecvt_type>(__loc); if (this->is_open()) { // encoding() == -1 is ok only at the beginning. if ((_M_reading || _M_writing) && __check_facet(_M_codecvt).encoding() == -1) __testvalid = false; else { if (_M_reading) { if (__check_facet(_M_codecvt).always_noconv()) { if (_M_codecvt_tmp && !__check_facet(_M_codecvt_tmp).always_noconv()) __testvalid = this->seekoff(0, ios_base::cur, this->_M_mode) != pos_type(off_type(-1)); } else { // External position corresponding to gptr(). _M_ext_next = _M_ext_buf + _M_codecvt->length(_M_state_last, _M_ext_buf, _M_ext_next, this->gptr() - this->eback()); const streamsize __remainder = _M_ext_end - _M_ext_next; if (__remainder) std::memmove(_M_ext_buf, _M_ext_next, __remainder); _M_ext_next = _M_ext_buf; _M_ext_end = _M_ext_buf + __remainder; _M_set_buffer(-1); _M_state_last = _M_state_cur = _M_state_beg; } } else if (_M_writing && (__testvalid = _M_terminate_output())) _M_set_buffer(-1); } } if (__testvalid) _M_codecvt = _M_codecvt_tmp; else _M_codecvt = 0; } // Inhibit implicit instantiations for required instantiations, // which are defined via explicit instantiations elsewhere. // NB: This syntax is a GNU extension.#if _GLIBCXX_EXTERN_TEMPLATE extern template class basic_filebuf<char>; extern template class basic_ifstream<char>; extern template class basic_ofstream<char>; extern template class basic_fstream<char>;#ifdef _GLIBCXX_USE_WCHAR_T extern template class basic_filebuf<wchar_t>; extern template class basic_ifstream<wchar_t>; extern template class basic_ofstream<wchar_t>; extern template class basic_fstream<wchar_t>;#endif#endif} // namespace std#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -