// streambuf standard header // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #pragma once #ifndef _STREAMBUF_ #define _STREAMBUF_ #include #if _STL_COMPILER_PREPROCESSOR #include #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) #pragma warning(disable : _STL_DISABLED_WARNINGS) _STL_DISABLE_CLANG_WARNINGS #pragma push_macro("new") #undef new _STD_BEGIN // CLASS TEMPLATE basic_streambuf template class basic_streambuf { // control read/write buffers protected: __CLR_OR_THIS_CALL basic_streambuf() : _Plocale(new locale) { _Init(); } __CLR_OR_THIS_CALL basic_streambuf(_Uninitialized) {} __CLR_OR_THIS_CALL basic_streambuf(const basic_streambuf& _Right) : _Plocale(new locale(_Right.getloc())) { _Init(); setp(_Right.pbase(), _Right.pptr(), _Right.epptr()); setg(_Right.eback(), _Right.gptr(), _Right.egptr()); } basic_streambuf& __CLR_OR_THIS_CALL operator=(const basic_streambuf& _Right) { if (this != _STD addressof(_Right)) { setp(_Right.pbase(), _Right.pptr(), _Right.epptr()); setg(_Right.eback(), _Right.gptr(), _Right.egptr()); pubimbue(_Right.getloc()); } return *this; } void __CLR_OR_THIS_CALL swap(basic_streambuf& _Right) { if (this != _STD addressof(_Right)) { _Elem* _Pfirst0 = pbase(); _Elem* _Pnext0 = pptr(); _Elem* _Pend = epptr(); _Elem* _Gfirst0 = eback(); _Elem* _Gnext0 = gptr(); _Elem* _Gend = egptr(); setp(_Right.pbase(), _Right.pptr(), _Right.epptr()); _Right.setp(_Pfirst0, _Pnext0, _Pend); setg(_Right.eback(), _Right.gptr(), _Right.egptr()); _Right.setg(_Gfirst0, _Gnext0, _Gend); _STD swap(_Plocale, _Right._Plocale); } } public: using char_type = _Elem; using traits_type = _Traits; virtual __CLR_OR_THIS_CALL ~basic_streambuf() noexcept { delete _Plocale; } using int_type = typename _Traits::int_type; using pos_type = typename _Traits::pos_type; using off_type = typename _Traits::off_type; pos_type __CLR_OR_THIS_CALL pubseekoff(off_type _Off, ios_base::seekdir _Way, ios_base::openmode _Mode = ios_base::in | ios_base::out) { // change position by _Off, according to _Way, _Mode return seekoff(_Off, _Way, _Mode); } #if _HAS_OLD_IOSTREAMS_MEMBERS pos_type __CLR_OR_THIS_CALL pubseekoff(off_type _Off, ios_base::seek_dir _Way, ios_base::open_mode _Mode) { // change position by _Off, according to _Way, _Mode (old style) return pubseekoff(_Off, static_cast(_Way), static_cast(_Mode)); } #endif // _HAS_OLD_IOSTREAMS_MEMBERS pos_type __CLR_OR_THIS_CALL pubseekpos(pos_type _Pos, ios_base::openmode _Mode = ios_base::in | ios_base::out) { // change position to _Pos, according to _Mode return seekpos(_Pos, _Mode); } #if _HAS_OLD_IOSTREAMS_MEMBERS pos_type __CLR_OR_THIS_CALL pubseekpos(pos_type _Pos, ios_base::open_mode _Mode) { // change position to _Pos, according to _Mode (old style) return seekpos(_Pos, static_cast(_Mode)); } #endif // _HAS_OLD_IOSTREAMS_MEMBERS basic_streambuf* __CLR_OR_THIS_CALL pubsetbuf(_Elem* _Buffer, streamsize _Count) { // offer _Buffer to external agent return setbuf(_Buffer, _Count); } locale __CLR_OR_THIS_CALL pubimbue(const locale& _Newlocale) { // set locale to argument locale _Oldlocale = *_Plocale; imbue(_Newlocale); *_Plocale = _Newlocale; return _Oldlocale; } locale __CLR_OR_THIS_CALL getloc() const { // get locale return *_Plocale; } streamsize __CLR_OR_THIS_CALL in_avail() { streamsize _Res = _Gnavail(); return 0 < _Res ? _Res : showmanyc(); } int __CLR_OR_THIS_CALL pubsync() { // synchronize with external agent return sync(); } int_type __CLR_OR_THIS_CALL sbumpc() { // get a character and point past it return 0 < _Gnavail() ? _Traits::to_int_type(*_Gninc()) : uflow(); } int_type __CLR_OR_THIS_CALL sgetc() { // get a character and don't point past it return 0 < _Gnavail() ? _Traits::to_int_type(*gptr()) : underflow(); } streamsize __CLR_OR_THIS_CALL sgetn(_Elem* _Ptr, streamsize _Count) { // get up to _Count characters into array beginning at _Ptr return xsgetn(_Ptr, _Count); } int_type __CLR_OR_THIS_CALL snextc() { // point to next character and return it return 1 < _Gnavail() ? _Traits::to_int_type(*_Gnpreinc()) : _Traits::eq_int_type(_Traits::eof(), sbumpc()) ? _Traits::eof() : sgetc(); } int_type __CLR_OR_THIS_CALL sputbackc(_Elem _Ch) { // put back _Ch if (gptr() && eback() < gptr() && _Traits::eq(_Ch, gptr()[-1])) { return _Traits::to_int_type(*_Gndec()); } return pbackfail(_Traits::to_int_type(_Ch)); } #if _HAS_OLD_IOSTREAMS_MEMBERS void __CLR_OR_THIS_CALL stossc() { // point past a character if (0 < _Gnavail()) { _Gninc(); } else { uflow(); } } #endif // _HAS_OLD_IOSTREAMS_MEMBERS int_type __CLR_OR_THIS_CALL sungetc() { // back up one position return gptr() && eback() < gptr() ? _Traits::to_int_type(*_Gndec()) : pbackfail(); } int_type __CLR_OR_THIS_CALL sputc(_Elem _Ch) { // put a character return 0 < _Pnavail() ? _Traits::to_int_type(*_Pninc() = _Ch) : overflow(_Traits::to_int_type(_Ch)); } streamsize __CLR_OR_THIS_CALL sputn(const _Elem* _Ptr, streamsize _Count) { // put _Count characters from array beginning at _Ptr return xsputn(_Ptr, _Count); } virtual void __CLR_OR_THIS_CALL _Lock() { // set the thread lock (overridden by basic_filebuf) } virtual void __CLR_OR_THIS_CALL _Unlock() { // clear the thread lock (overridden by basic_filebuf) } protected: _Elem* __CLR_OR_THIS_CALL eback() const { return *_IGfirst; } _Elem* __CLR_OR_THIS_CALL gptr() const { return *_IGnext; } _Elem* __CLR_OR_THIS_CALL pbase() const { return *_IPfirst; } _Elem* __CLR_OR_THIS_CALL pptr() const { return *_IPnext; } _Elem* __CLR_OR_THIS_CALL egptr() const { return *_IGnext + *_IGcount; } void __CLR_OR_THIS_CALL gbump(int _Off) { // alter current position in read buffer by _Off *_IGcount -= _Off; *_IGnext += _Off; } void __CLR_OR_THIS_CALL setg(_Elem* _First, _Elem* _Next, _Elem* _Last) { // set pointers for read buffer *_IGfirst = _First; *_IGnext = _Next; *_IGcount = static_cast(_Last - _Next); } _Elem* __CLR_OR_THIS_CALL epptr() const { return *_IPnext + *_IPcount; } _Elem* __CLR_OR_THIS_CALL _Gndec() { // decrement current position in read buffer ++*_IGcount; return --*_IGnext; } _Elem* __CLR_OR_THIS_CALL _Gninc() { // increment current position in read buffer --*_IGcount; return (*_IGnext)++; } _Elem* __CLR_OR_THIS_CALL _Gnpreinc() { // preincrement current position in read buffer --*_IGcount; return ++(*_IGnext); } streamsize __CLR_OR_THIS_CALL _Gnavail() const { // count number of available elements in read buffer return *_IGnext ? *_IGcount : 0; } void __CLR_OR_THIS_CALL pbump(int _Off) { // alter current position in write buffer by _Off *_IPcount -= _Off; *_IPnext += _Off; } void __CLR_OR_THIS_CALL setp(_Elem* _First, _Elem* _Last) { // set pointers for write buffer *_IPfirst = _First; *_IPnext = _First; *_IPcount = static_cast(_Last - _First); } void __CLR_OR_THIS_CALL setp( _Elem* _First, _Elem* _Next, _Elem* _Last) { // set pointers for write buffer, extended version *_IPfirst = _First; *_IPnext = _Next; *_IPcount = static_cast(_Last - _Next); } _Elem* __CLR_OR_THIS_CALL _Pninc() { // increment current position in write buffer --*_IPcount; return (*_IPnext)++; } streamsize __CLR_OR_THIS_CALL _Pnavail() const { // count number of available positions in write buffer return *_IPnext ? *_IPcount : 0; } void __CLR_OR_THIS_CALL _Init() { // initialize buffer parameters for no buffers _IGfirst = &_Gfirst; _IPfirst = &_Pfirst; _IGnext = &_Gnext; _IPnext = &_Pnext; _IGcount = &_Gcount; _IPcount = &_Pcount; setp(nullptr, nullptr); setg(nullptr, nullptr, nullptr); } void __CLR_OR_THIS_CALL _Init(_Elem** _Gf, _Elem** _Gn, int* _Gc, _Elem** _Pf, _Elem** _Pn, int* _Pc) { // initialize buffer parameters as specified _IGfirst = _Gf; _IPfirst = _Pf; _IGnext = _Gn; _IPnext = _Pn; _IGcount = _Gc; _IPcount = _Pc; } virtual int_type __CLR_OR_THIS_CALL overflow(int_type = _Traits::eof()) { // put a character to stream (always fail) return _Traits::eof(); } virtual int_type __CLR_OR_THIS_CALL pbackfail(int_type = _Traits::eof()) { // put a character back to stream (always fail) return _Traits::eof(); } virtual streamsize __CLR_OR_THIS_CALL showmanyc() { return 0; } virtual int_type __CLR_OR_THIS_CALL underflow() { // get a character from stream, but don't point past it return _Traits::eof(); } virtual int_type __CLR_OR_THIS_CALL uflow() { // get a character from stream, point past it return _Traits::eq_int_type(_Traits::eof(), underflow()) ? _Traits::eof() : _Traits::to_int_type(*_Gninc()); } virtual streamsize __CLR_OR_THIS_CALL xsgetn(_Elem* _Ptr, streamsize _Count) { // get _Count characters from stream const streamsize _Start_count = _Count; while (0 < _Count) { streamsize _Size = _Gnavail(); if (0 < _Size) { // copy from read buffer if (_Count < _Size) { _Size = _Count; } _Traits::copy(_Ptr, gptr(), static_cast(_Size)); _Ptr += _Size; _Count -= _Size; gbump(static_cast(_Size)); } else { const int_type _Meta = uflow(); if (_Traits::eq_int_type(_Traits::eof(), _Meta)) { break; // end of file, quit } // get a single character *_Ptr++ = _Traits::to_char_type(_Meta); --_Count; } } return _Start_count - _Count; } virtual streamsize __CLR_OR_THIS_CALL xsputn(const _Elem* _Ptr, streamsize _Count) { // put _Count characters to stream const streamsize _Start_count = _Count; while (0 < _Count) { streamsize _Size = _Pnavail(); if (0 < _Size) { // copy to write buffer if (_Count < _Size) { _Size = _Count; } _Traits::copy(pptr(), _Ptr, static_cast(_Size)); _Ptr += _Size; _Count -= _Size; pbump(static_cast(_Size)); } else if (_Traits::eq_int_type(_Traits::eof(), overflow(_Traits::to_int_type(*_Ptr)))) { break; // single character put failed, quit } else { // count character successfully put ++_Ptr; --_Count; } } return _Start_count - _Count; } virtual pos_type __CLR_OR_THIS_CALL seekoff( off_type, ios_base::seekdir, ios_base::openmode = ios_base::in | ios_base::out) { // change position by offset, according to way and mode return streampos(-1); } virtual pos_type __CLR_OR_THIS_CALL seekpos(pos_type, ios_base::openmode = ios_base::in | ios_base::out) { // change to specified position, according to mode return streampos(-1); } virtual basic_streambuf* __CLR_OR_THIS_CALL setbuf(_Elem*, streamsize) { // offer buffer to external agent (do nothing) return this; } virtual int __CLR_OR_THIS_CALL sync() { // synchronize with external agent (do nothing) return 0; } virtual void __CLR_OR_THIS_CALL imbue(const locale&) { // set locale to argument (do nothing) } private: _Elem* _Gfirst; // beginning of read buffer _Elem* _Pfirst; // beginning of write buffer _Elem** _IGfirst; // pointer to beginning of read buffer _Elem** _IPfirst; // pointer to beginning of write buffer _Elem* _Gnext; // current position in read buffer _Elem* _Pnext; // current position in write buffer _Elem** _IGnext; // pointer to current position in read buffer _Elem** _IPnext; // pointer to current position in write buffer int _Gcount; // length of read buffer int _Pcount; // length of write buffer int* _IGcount; // pointer to length of read buffer int* _IPcount; // pointer to length of write buffer protected: locale* _Plocale; // pointer to imbued locale object }; #if defined(_DLL_CPPLIB) #if !defined(_CRTBLD) || defined(__FORCE_INSTANCE) template class _CRTIMP2_PURE_IMPORT basic_streambuf>; template class _CRTIMP2_PURE_IMPORT basic_streambuf>; #endif // !defined(_CRTBLD) || defined(__FORCE_INSTANCE) #ifdef __FORCE_INSTANCE template class _CRTIMP2_PURE_IMPORT basic_streambuf>; #endif // __FORCE_INSTANCE #endif // defined(_DLL_CPPLIB) _STD_END #pragma pop_macro("new") _STL_RESTORE_CLANG_WARNINGS #pragma warning(pop) #pragma pack(pop) #endif // _STL_COMPILER_PREPROCESSOR #endif // _STREAMBUF_