зеркало из https://github.com/microsoft/STL.git
420 строки
15 KiB
C++
420 строки
15 KiB
C++
// streambuf standard header
|
|
|
|
// Copyright (c) Microsoft Corporation.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
#ifndef _STREAMBUF_
|
|
#define _STREAMBUF_
|
|
#include <yvals_core.h>
|
|
#if _STL_COMPILER_PREPROCESSOR
|
|
#include <xiosbase>
|
|
|
|
#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
|
|
_EXPORT_STD extern "C++" template <class _Elem, class _Traits>
|
|
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) noexcept {}
|
|
|
|
__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) noexcept /* strengthened */ {
|
|
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<ios_base::seekdir>(_Way), static_cast<ios_base::openmode>(_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<ios_base::openmode>(_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 noexcept /* strengthened */ { // 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 noexcept /* strengthened */ {
|
|
return *_IGfirst;
|
|
}
|
|
|
|
_Elem* __CLR_OR_THIS_CALL gptr() const noexcept /* strengthened */ {
|
|
return *_IGnext;
|
|
}
|
|
|
|
_Elem* __CLR_OR_THIS_CALL pbase() const noexcept /* strengthened */ {
|
|
return *_IPfirst;
|
|
}
|
|
|
|
_Elem* __CLR_OR_THIS_CALL pptr() const noexcept /* strengthened */ {
|
|
return *_IPnext;
|
|
}
|
|
|
|
_Elem* __CLR_OR_THIS_CALL egptr() const noexcept /* strengthened */ {
|
|
return *_IGnext + *_IGcount;
|
|
}
|
|
|
|
void __CLR_OR_THIS_CALL gbump(int _Off) noexcept /* strengthened */ {
|
|
// alter current position in read buffer by _Off
|
|
*_IGcount -= _Off;
|
|
*_IGnext += _Off;
|
|
}
|
|
|
|
void __CLR_OR_THIS_CALL setg(_Elem* _First, _Elem* _Next, _Elem* _Last) noexcept /* strengthened */ {
|
|
// set pointers for read buffer
|
|
*_IGfirst = _First;
|
|
*_IGnext = _Next;
|
|
*_IGcount = static_cast<int>(_Last - _Next);
|
|
}
|
|
|
|
_Elem* __CLR_OR_THIS_CALL epptr() const noexcept /* strengthened */ {
|
|
return *_IPnext + *_IPcount;
|
|
}
|
|
|
|
_Elem* __CLR_OR_THIS_CALL _Gndec() noexcept { // decrement current position in read buffer
|
|
++*_IGcount;
|
|
return --*_IGnext;
|
|
}
|
|
|
|
_Elem* __CLR_OR_THIS_CALL _Gninc() noexcept { // increment current position in read buffer
|
|
--*_IGcount;
|
|
return (*_IGnext)++;
|
|
}
|
|
|
|
_Elem* __CLR_OR_THIS_CALL _Gnpreinc() noexcept { // preincrement current position in read buffer
|
|
--*_IGcount;
|
|
return ++(*_IGnext);
|
|
}
|
|
|
|
streamsize __CLR_OR_THIS_CALL _Gnavail() const noexcept { // count number of available elements in read buffer
|
|
return *_IGnext ? *_IGcount : 0;
|
|
}
|
|
|
|
void __CLR_OR_THIS_CALL pbump(int _Off) noexcept /* strengthened */ {
|
|
// alter current position in write buffer by _Off
|
|
*_IPcount -= _Off;
|
|
*_IPnext += _Off;
|
|
}
|
|
|
|
void __CLR_OR_THIS_CALL setp(_Elem* _First, _Elem* _Last) noexcept /* strengthened */ {
|
|
// set pointers for write buffer
|
|
*_IPfirst = _First;
|
|
*_IPnext = _First;
|
|
*_IPcount = static_cast<int>(_Last - _First);
|
|
}
|
|
|
|
void __CLR_OR_THIS_CALL setp(_Elem* _First, _Elem* _Next, _Elem* _Last) noexcept /* strengthened */ {
|
|
// set pointers for write buffer, extended version
|
|
*_IPfirst = _First;
|
|
*_IPnext = _Next;
|
|
*_IPcount = static_cast<int>(_Last - _Next);
|
|
}
|
|
|
|
_Elem* __CLR_OR_THIS_CALL _Pninc() noexcept { // increment current position in write buffer
|
|
--*_IPcount;
|
|
return (*_IPnext)++;
|
|
}
|
|
|
|
streamsize __CLR_OR_THIS_CALL _Pnavail() const noexcept { // count number of available positions in write buffer
|
|
return *_IPnext ? *_IPcount : 0;
|
|
}
|
|
|
|
void __CLR_OR_THIS_CALL _Init() noexcept { // 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) noexcept {
|
|
// 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_t>(_Size));
|
|
_Ptr += _Size;
|
|
_Count -= _Size;
|
|
gbump(static_cast<int>(_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_t>(_Size));
|
|
_Ptr += _Size;
|
|
_Count -= _Size;
|
|
pbump(static_cast<int>(_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 pos_type{off_type{-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 pos_type{off_type{-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<char, char_traits<char>>;
|
|
template class _CRTIMP2_PURE_IMPORT basic_streambuf<wchar_t, char_traits<wchar_t>>;
|
|
#endif // !defined(_CRTBLD) || defined(__FORCE_INSTANCE)
|
|
|
|
#ifdef __FORCE_INSTANCE
|
|
template class _CRTIMP2_PURE_IMPORT basic_streambuf<unsigned short, char_traits<unsigned short>>;
|
|
#endif // defined(__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_
|