STL/stl/inc/strstream

631 строка
22 KiB
C++

// strstream standard header
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#pragma once
#ifndef _STRSTREAM_
#define _STRSTREAM_
#include <yvals_core.h>
#if _STL_COMPILER_PREPROCESSOR
#include <istream>
#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
_CXX17_DEPRECATE_STRSTREAM typedef int _Header_strstream;
using _Hdr_strstream = _Header_strstream;
// CLASS strstreambuf
class strstreambuf : public streambuf { // stream buffer associated with static or allocated character array
public:
using _Mysb = streambuf;
enum { // constants for bits in stream state
_Allocated = 1, // set if character array storage has been allocated
_Constant = 2, // set if character array immutable
_Dynamic = 4, // set if character array length grows on demand
_Frozen = 8
}; // set if character array ownership given away
using _Strstate = int;
__CLR_OR_THIS_CALL strstreambuf() { // construct with empty character array
_Init(0);
}
explicit __CLR_OR_THIS_CALL strstreambuf(streamsize _Count) { // construct with suggested initial size
_Init(_Count);
}
__CLR_OR_THIS_CALL strstreambuf(
void*(__CLRCALL_OR_CDECL* _Allocfunc)(size_t), void(__CLRCALL_OR_CDECL* _Freefunc)(void*)) {
// construct with empty character array, allocation functions
_Init();
_Palloc = _Allocfunc;
_Pfree = _Freefunc;
}
__CLR_OR_THIS_CALL strstreambuf(_In_opt_z_ char* _Getptr, streamsize _Count, _In_opt_z_ char* _Putptr = nullptr) {
// construct with [_Getptr, _Getptr + _Count), possibly mutable
_Init(_Count, _Getptr, _Putptr);
}
__CLR_OR_THIS_CALL strstreambuf(_In_z_ const char* _Getptr, streamsize _Count) {
// construct with [_Getptr, _Getptr + _Count), immutable
_Init(_Count, const_cast<char*>(_Getptr), nullptr, _Constant);
}
__CLR_OR_THIS_CALL strstreambuf(
_In_opt_z_ unsigned char* _Getptr, streamsize _Count, _In_opt_z_ unsigned char* _Putptr = nullptr) {
// construct with [_Getptr, _Getptr + _Count), possibly mutable
_Init(_Count, reinterpret_cast<char*>(_Getptr), reinterpret_cast<char*>(_Putptr));
}
__CLR_OR_THIS_CALL strstreambuf(_In_opt_z_ const unsigned char* _Getptr, streamsize _Count) {
// construct with [_Getptr, _Getptr + _Count), immutable
_Init(_Count, const_cast<char*>(reinterpret_cast<const char*>(_Getptr)), nullptr, _Constant);
}
__CLR_OR_THIS_CALL strstreambuf(strstreambuf&& _Right) {
_Init();
_Assign_rv(_STD move(_Right));
}
strstreambuf& __CLR_OR_THIS_CALL operator=(strstreambuf&& _Right) {
_Assign_rv(_STD move(_Right));
return *this;
}
void __CLR_OR_THIS_CALL _Assign_rv(strstreambuf&& _Right) {
if (this != _STD addressof(_Right)) {
_Tidy();
this->swap(_Right);
}
}
void __CLR_OR_THIS_CALL swap(strstreambuf& _Right) {
if (this != _STD addressof(_Right)) {
_Mysb::swap(_Right);
_STD swap(_Minsize, _Right._Minsize);
_STD swap(_Pendsave, _Right._Pendsave);
_STD swap(_Seekhigh, _Right._Seekhigh);
_STD swap(_Strmode, _Right._Strmode);
_STD swap(_Palloc, _Right._Palloc);
_STD swap(_Pfree, _Right._Pfree);
}
}
virtual __CLR_OR_THIS_CALL ~strstreambuf() noexcept {
_Tidy();
}
void __CLR_OR_THIS_CALL freeze(bool _Freezeit = true) { // freeze or unfreeze writing
if (_Strmode & _Dynamic) {
if (_Freezeit && !(_Strmode & _Frozen)) { // disable writing
_Strmode |= _Frozen;
_Pendsave = epptr();
setp(pbase(), pptr(), eback());
} else if (!_Freezeit && (_Strmode & _Frozen)) { // re-enable writing
_Strmode &= ~_Frozen;
setp(pbase(), pptr(), _Pendsave);
}
}
}
_NODISCARD char* __CLR_OR_THIS_CALL str() { // freeze and return pointer to character array
freeze();
return eback();
}
_NODISCARD streamsize __CLR_OR_THIS_CALL pcount() const {
return pptr() ? static_cast<streamsize>(pptr() - pbase()) : 0;
}
__CLR_OR_THIS_CALL strstreambuf(
_In_opt_z_ signed char* _Getptr, streamsize _Count, _In_opt_z_ signed char* _Putptr = nullptr) {
// construct with [_Getptr, _Getptr + _Count), possibly mutable
_Init(_Count, reinterpret_cast<char*>(_Getptr), reinterpret_cast<char*>(_Putptr));
}
__CLR_OR_THIS_CALL strstreambuf(const signed char* _Getptr, streamsize _Count) {
// construct with [_Getptr, _Getptr + _Count), immutable
_Init(_Count, const_cast<char*>(reinterpret_cast<const char*>(_Getptr)), nullptr, _Constant);
}
void clear() { // free any allocated storage
_Tidy();
}
protected:
virtual int __CLR_OR_THIS_CALL overflow(int _Meta = EOF) override { // try to extend write area
if (_Meta == EOF) {
return 0; // nothing to write
}
if (pptr() && pptr() < epptr()) {
return static_cast<unsigned char>(*_Pninc() = static_cast<char>(_Meta));
}
if (!(_Strmode & _Dynamic) || (_Strmode & (_Constant | _Frozen))) {
return EOF; // can't extend
}
// okay to extend
const size_t _Oldsize = gptr() ? static_cast<size_t>(epptr() - eback()) : 0;
size_t _Newsize;
if (_Oldsize < _MINSIZE) {
_Newsize = _MINSIZE;
} else if (_Oldsize < INT_MAX / 2) { // grow by 50 percent
_Newsize = _Oldsize << 1;
} else if (_Oldsize < INT_MAX) {
_Newsize = INT_MAX;
} else { // buffer can't grow, fail
return EOF;
}
const auto _Ptr = _Alloc(_Newsize);
if (!_Ptr) { // couldn't grow, return failure
return EOF;
}
_CSTD memcpy(_Ptr, eback(), _Oldsize); // copy existing
if (_Strmode & _Allocated) { // buffer to free
_Free(eback());
}
_Strmode |= _Allocated;
_Seekhigh = _Ptr + _Oldsize;
const ptrdiff_t _Old_get_offset = gptr() - eback();
const ptrdiff_t _Old_put_base_offset = pbase() - eback();
const ptrdiff_t _Old_put_offset = pptr() - eback();
setp(_Ptr + _Old_put_base_offset, _Ptr + _Old_put_offset, _Ptr + _Newsize);
setg(_Ptr, _Ptr + _Old_get_offset, _Ptr + _Old_get_offset + 1);
return static_cast<unsigned char>(*_Pninc() = static_cast<char>(_Meta));
}
virtual int __CLR_OR_THIS_CALL pbackfail(int _Meta = EOF) override { // try to putback a character
const auto _Old_gptr = gptr();
if (_Old_gptr && eback() < _Old_gptr) { // if the input sequence has a putback position available
if (_Meta == EOF) {
_Meta = 0; // a value other than EOF
} else if (!(_Strmode & _Constant)) { // non constant, overwrite no matter what
_Old_gptr[-1] = static_cast<char>(_Meta);
} else if (_Old_gptr[-1] != static_cast<char>(_Meta)) { // constant, unequal, can't put it back
return EOF;
}
gbump(-1);
return _Meta;
}
return EOF;
}
virtual int __CLR_OR_THIS_CALL underflow() override { // read if read position available
const auto _Old_gptr = gptr();
if (!_Old_gptr) {
return EOF; // no read buffer
}
if (_Old_gptr < egptr()) { // If the input sequence has a read position available, the function signals success
// by returning static_cast<unsigned char>(*gnext)
return static_cast<unsigned char>(*_Old_gptr);
}
const auto _Old_pptr = pptr();
if (_Old_pptr && _Old_pptr > egptr()
&& _Old_gptr
< _Old_pptr) { // Otherwise, if the current write next pointer pnext is not a null pointer and is
// greater than the current read end pointer gend, makes a read position available by
// assigning to gend a value greater than gnext and no greater than pnext.
if (_Seekhigh < _Old_pptr) { // TRANSITION, ABI: appears unused, maintained for ABI compat
_Seekhigh = _Old_pptr;
}
setg(eback(), gptr(), _Old_pptr);
return static_cast<unsigned char>(*_Old_gptr);
}
return EOF;
}
virtual streampos __CLR_OR_THIS_CALL seekoff(
streamoff _Off, ios_base::seekdir _Way, ios_base::openmode _Which = ios_base::in | ios_base::out) override {
// seek by specified offset
if (pptr() && _Seekhigh < pptr()) { // TRANSITION, ABI: appears unused, maintained for ABI compat
_Seekhigh = pptr(); // update high water mark
}
if ((_Which & ios_base::in && !gptr())
|| (_Which & ios_base::out && !pptr())) { // N4727 [depr.strstreambuf.virtuals]/14:
// For a sequence to be positioned, if its next pointer
// is a null pointer, the positioning operation fails.
return pos_type(off_type(-1));
}
const auto _Seeklow = eback();
const auto _Seekdist = _Seekhigh - _Seeklow;
// [depr.strstreambuf.virtuals]/15 effectively says check that the result will be in range
// [_Seeklow, _Seekhigh]; but we want to calculate this without potential integer overflow
switch (_Way) {
case ios_base::beg:
// check that _Off is in acceptable range [0, _Seekdist]
if (static_cast<unsigned long long>(_Off)
> static_cast<unsigned long long>(_Seekdist)) { // negative wraparound to positive to save a compare
return pos_type(off_type(-1));
}
break;
case ios_base::end:
// check that _Off is in acceptable range [-_Seekdist, 0]
// is: _Off + _Seekdist in range [0, _Seekdist]
if (static_cast<unsigned long long>(_Off) + _Seekdist > static_cast<unsigned long long>(_Seekdist)) {
return pos_type(off_type(-1));
}
_Off += _Seekdist;
break;
case ios_base::cur: {
constexpr auto _Both = ios_base::in | ios_base::out;
if ((_Which & _Both)
== _Both) { // prohibited by N4727 [depr.strstreambuf.virtuals] Table 137 "seekoff positioning"
return pos_type(off_type(-1));
}
off_type _Oldoff;
off_type _Oldleft;
if (_Which & ios_base::in) {
_Oldoff = gptr() - eback();
_Oldleft = _Seekhigh - gptr();
} else if (_Which & ios_base::out) {
_Oldoff = pptr() - pbase();
_Oldleft = _Seekhigh - pptr();
} else {
return pos_type(off_type(-1));
}
if (_Off < -_Oldoff // runs off beginning
|| _Off > _Oldleft) { // runs off end
return pos_type(off_type(-1));
}
_Off += _Oldoff;
}
break;
default:
return pos_type(off_type(-1));
}
if (_Which & ios_base::in) {
gbump(static_cast<int>(_Off - (gptr() - eback())));
}
if (_Which & ios_base::out) {
pbump(static_cast<int>(_Off - (pptr() - pbase())));
}
return pos_type(_Off);
}
virtual pos_type __CLR_OR_THIS_CALL seekpos(
pos_type _Sp, ios_base::openmode _Which = ios_base::in | ios_base::out) override {
// seek to memorized position
if (pptr() && _Seekhigh < pptr()) { // TRANSITION, ABI: appears unused, maintained for ABI compat
_Seekhigh = pptr(); // update high water mark
}
if (((_Which & ios_base::in) && !gptr()) || ((_Which & ios_base::out) && !pptr())) {
return pos_type(off_type(-1));
}
const auto _Off = static_cast<off_type>(_Sp);
const auto _Seeklow = eback();
const auto _Seekdist = _Seekhigh - _Seeklow;
if (_Off > _Seekdist) {
return pos_type(off_type(-1));
}
if (_Which & ios_base::in) {
gbump(static_cast<int>(_Off - (gptr() - eback())));
}
if (_Which & ios_base::out) {
pbump(static_cast<int>(_Off - (pptr() - pbase())));
}
return pos_type(_Off);
}
void __CLR_OR_THIS_CALL _Init(
streamsize _Count = 0, char* _Gp = nullptr, char* _Pp = nullptr, _Strstate _Mode = 0) {
// initialize with possibly static buffer
streambuf::_Init();
_Minsize = _MINSIZE;
_Pendsave = nullptr;
_Seekhigh = nullptr;
_Palloc = nullptr;
_Pfree = nullptr;
_Strmode = _Mode;
if (_Gp) { // make static
size_t _Size;
if (_Count == 0) {
_Size = _CSTD strlen(_Gp);
} else if (static_cast<unsigned long long>(_Count) < static_cast<unsigned long long>(INT_MAX)) {
_Size = static_cast<size_t>(_Count);
} else {
_Size = INT_MAX;
}
_Seekhigh = _Gp + _Size;
if (_Pp) { // make writable too
setg(_Gp, _Gp, _Pp);
setp(_Pp, _Pp + _Size);
} else { // set read pointers only
setg(_Gp, _Gp, _Gp + _Size);
}
} else { // make dynamic
_Strmode |= _Dynamic;
if (_Count > INT_MAX) {
_Minsize = INT_MAX;
} else if (_Minsize < _Count) {
_Minsize = static_cast<int>(_Count);
}
}
}
void __CLR_OR_THIS_CALL _Tidy() noexcept { // free any allocated storage
if ((_Strmode & (_Allocated | _Frozen)) == _Allocated) {
_Free(eback());
}
_Seekhigh = nullptr;
_Strmode &= ~(_Allocated | _Frozen);
}
private:
enum { // constant for default minimum buffer size
_MINSIZE = 32
};
char* _Alloc(const size_t _To_allocate) const {
if (_Palloc) {
return static_cast<char*>(_Palloc(_To_allocate));
}
return static_cast<char*>(_CSTD _malloc_dbg(_To_allocate, _CRT_BLOCK, __FILE__, __LINE__));
}
void _Free(char* _Ptr) const {
if (_Pfree) {
_Pfree(_Ptr);
return;
}
_CSTD free(_Ptr);
}
int _Minsize; // the minimum buffer size
char* _Pendsave; // the saved end pointer during freeze
char* _Seekhigh; // the high-water pointer in character array
_Strstate _Strmode; // the stream state
void*(__CLRCALL_OR_CDECL* _Palloc)(size_t); // the pointer to allocator function
void(__CLRCALL_OR_CDECL* _Pfree)(void*); // the pointer to free function
};
// strstreambuf OPERATORS
inline void swap(strstreambuf& _Left, strstreambuf& _Right) {
_Left.swap(_Right);
}
// CLASS istrstream
class istrstream : public istream { // input stream associated with a character array
public:
using _Mybase = istream;
using _Mysb = strstreambuf;
explicit __CLR_OR_THIS_CALL istrstream(const char* _Ptr) : _Mybase(&_Strbuffer), _Strbuffer(_Ptr, 0) {
// construct with NTBS
}
__CLR_OR_THIS_CALL istrstream(const char* _Ptr, streamsize _Count)
: _Mybase(&_Strbuffer), _Strbuffer(_Ptr, _Count) {
// construct with [_Ptr, _Ptr + _Count)
}
explicit __CLR_OR_THIS_CALL istrstream(char* _Ptr) : _Mybase(&_Strbuffer), _Strbuffer(_Ptr, 0) {
// construct with NTBS
}
__CLR_OR_THIS_CALL istrstream(char* _Ptr, int _Count) : _Mybase(&_Strbuffer), _Strbuffer(_Ptr, _Count) {
// construct with [_Ptr, _Ptr + _Count)
}
__CLR_OR_THIS_CALL istrstream(istrstream&& _Right) : _Mybase(&_Strbuffer) {
_Assign_rv(_STD move(_Right));
}
istrstream& __CLR_OR_THIS_CALL operator=(istrstream&& _Right) {
_Assign_rv(_STD move(_Right));
return *this;
}
void __CLR_OR_THIS_CALL _Assign_rv(istrstream&& _Right) {
if (this != _STD addressof(_Right)) {
_Strbuffer.clear();
this->swap(_Right);
}
}
void __CLR_OR_THIS_CALL swap(istrstream& _Right) {
if (this != _STD addressof(_Right)) {
_Mybase::swap(_Right);
_Strbuffer.swap(_Right._Strbuffer);
}
}
virtual __CLR_OR_THIS_CALL ~istrstream() noexcept {}
_NODISCARD _Mysb* __CLR_OR_THIS_CALL rdbuf() const {
return const_cast<_Mysb*>(&_Strbuffer);
}
_NODISCARD char* __CLR_OR_THIS_CALL str() { // freeze and return pointer to character array
return _Strbuffer.str();
}
private:
_Mysb _Strbuffer; // the string buffer
};
// istrstream OPERATORS
inline void swap(istrstream& _Left, istrstream& _Right) {
_Left.swap(_Right);
}
// CLASS ostrstream
class ostrstream : public ostream { // output stream associated with a character array
public:
using _Mybase = ostream;
using _Mysb = strstreambuf;
__CLR_OR_THIS_CALL ostrstream() : ostream(&_Strbuffer), _Strbuffer() {}
__CLR_OR_THIS_CALL ostrstream(char* _Ptr, streamsize _Count, ios_base::openmode _Mode = ios_base::out)
: ostream(&_Strbuffer),
_Strbuffer(_Ptr, _Count, _Ptr && (_Mode & ios_base::app) != 0 ? _Ptr + _CSTD strlen(_Ptr) : _Ptr) {
// construct with [_Ptr, _Ptr + _Count)
}
__CLR_OR_THIS_CALL ostrstream(ostrstream&& _Right) : _Mybase(&_Strbuffer) {
_Assign_rv(_STD move(_Right));
}
ostrstream& __CLR_OR_THIS_CALL operator=(ostrstream&& _Right) {
_Assign_rv(_STD move(_Right));
return *this;
}
void __CLR_OR_THIS_CALL _Assign_rv(ostrstream&& _Right) {
if (this != _STD addressof(_Right)) {
_Strbuffer.clear();
this->swap(_Right);
}
}
void __CLR_OR_THIS_CALL swap(ostrstream& _Right) {
if (this != _STD addressof(_Right)) {
_Mybase::swap(_Right);
_Strbuffer.swap(_Right._Strbuffer);
}
}
virtual __CLR_OR_THIS_CALL ~ostrstream() noexcept {}
_NODISCARD _Mysb* __CLR_OR_THIS_CALL rdbuf() const {
return const_cast<_Mysb*>(&_Strbuffer);
}
void __CLR_OR_THIS_CALL freeze(bool _Freezeit = true) { // freeze or unfreeze writing
_Strbuffer.freeze(_Freezeit);
}
_NODISCARD char* __CLR_OR_THIS_CALL str() { // freeze and return pointer to character array
return _Strbuffer.str();
}
_NODISCARD streamsize __CLR_OR_THIS_CALL pcount() const {
return _Strbuffer.pcount();
}
private:
_Mysb _Strbuffer; // the string buffer
};
// ostrstream OPERATORS
inline void swap(ostrstream& _Left, ostrstream& _Right) {
_Left.swap(_Right);
}
// CLASS strstream
class strstream : public iostream { // input/output stream associated with character array buffer
public:
using _Mybase = iostream;
using _Mysb = strstreambuf;
using char_type = char;
using int_type = int;
using pos_type = streampos;
using off_type = streamoff;
__CLR_OR_THIS_CALL strstream() : _Mybase(&_Strbuffer), _Strbuffer() {}
__CLR_OR_THIS_CALL strstream(char* _Ptr, streamsize _Count, ios_base::openmode _Mode = ios_base::in | ios_base::out)
: iostream(&_Strbuffer),
_Strbuffer(_Ptr, _Count, _Ptr && (_Mode & ios_base::app) != 0 ? _Ptr + _CSTD strlen(_Ptr) : _Ptr) {
// construct with [_Ptr, _Ptr + _Count)
}
__CLR_OR_THIS_CALL strstream(strstream&& _Right) : _Mybase(&_Strbuffer) {
_Assign_rv(_STD move(_Right));
}
strstream& __CLR_OR_THIS_CALL operator=(strstream&& _Right) {
_Assign_rv(_STD move(_Right));
return *this;
}
void __CLR_OR_THIS_CALL _Assign_rv(strstream&& _Right) {
if (this != _STD addressof(_Right)) {
_Strbuffer.clear();
this->swap(_Right);
}
}
void __CLR_OR_THIS_CALL swap(strstream& _Right) {
if (this != _STD addressof(_Right)) {
_Mybase::swap(_Right);
_Strbuffer.swap(_Right._Strbuffer);
}
}
virtual __CLR_OR_THIS_CALL ~strstream() noexcept {}
_NODISCARD _Mysb* __CLR_OR_THIS_CALL rdbuf() const {
return const_cast<_Mysb*>(&_Strbuffer);
}
void __CLR_OR_THIS_CALL freeze(bool _Freezeit = true) { // freeze or unfreeze writing
_Strbuffer.freeze(_Freezeit);
}
_NODISCARD char* __CLR_OR_THIS_CALL str() { // freeze and return pointer to character array
return _Strbuffer.str();
}
_NODISCARD streamsize __CLR_OR_THIS_CALL pcount() const {
return _Strbuffer.pcount();
}
private:
_Mysb _Strbuffer; // the string buffer
};
// strstream OPERATORS
inline void swap(strstream& _Left, strstream& _Right) {
_Left.swap(_Right);
}
_STD_END
#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)
#pragma pack(pop)
#endif // _STL_COMPILER_PREPROCESSOR
#endif // _STRSTREAM_