зеркало из https://github.com/microsoft/STL.git
631 строка
22 KiB
C++
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_
|