STL/stl/inc/spanstream

397 строки
14 KiB
C++

// spanstream standard header
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#ifndef _SPANSTREAM_
#define _SPANSTREAM_
#include <yvals.h>
#if _STL_COMPILER_PREPROCESSOR
#if !_HAS_CXX23
_EMIT_STL_WARNING(STL4038, "The contents of <spanstream> are available only with C++23 or later.");
#else // ^^^ !_HAS_CXX23 / _HAS_CXX23 vvv
#include <concepts>
#include <istream>
#include <ostream>
#include <span>
#include <streambuf>
#include <xutility>
#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
// In this file, _STD span is qualified to avoid ambiguity with span() member functions.
// This qualification is consistently used even when it isn't strictly necessary.
_EXPORT_STD template <class _Elem, class _Traits>
class basic_spanbuf : public basic_streambuf<_Elem, _Traits> {
private:
using _Mysb = basic_streambuf<_Elem, _Traits>;
public:
using char_type = _Elem;
using int_type = _Traits::int_type;
using pos_type = _Traits::pos_type;
using off_type = _Traits::off_type;
using traits_type = _Traits;
// N4950 [spanbuf.cons], constructors
basic_spanbuf() = default;
explicit basic_spanbuf(ios_base::openmode _Which) : _Mysb(), _Mode(_Which) {}
explicit basic_spanbuf(_STD span<_Elem> _Span, ios_base::openmode _Which = ios_base::in | ios_base::out)
: _Mysb(), _Mode(_Which), _Buf() {
this->span(_Span);
}
basic_spanbuf(const basic_spanbuf&) = delete;
basic_spanbuf(basic_spanbuf&& _Right)
: _Mysb(_STD move(_Right)), _Mode(_Right._Mode), _Buf(_STD exchange(_Right._Buf, {})) {
_Right.setp(nullptr, nullptr, nullptr);
_Right.setg(nullptr, nullptr, nullptr);
}
// N4950 [spanbuf.assign], assignment and swap
basic_spanbuf& operator=(const basic_spanbuf&) = delete;
basic_spanbuf& operator=(basic_spanbuf&& _Right) noexcept /* strengthened */ {
if (this != _STD addressof(_Right)) {
_Buf = _STD span<_Elem>{};
this->setp(nullptr, nullptr, nullptr);
this->setg(nullptr, nullptr, nullptr);
this->swap(_Right);
}
return *this;
}
void swap(basic_spanbuf& _Right) noexcept /* strengthened */ {
_Mysb::swap(_Right);
_STD swap(_Mode, _Right._Mode);
_STD swap(_Buf, _Right._Buf);
}
// N4950 [spanbuf.members], member functions
_NODISCARD _STD span<_Elem> span() const noexcept {
if (_Mode & ios_base::out) {
return _STD span<_Elem>{_Mysb::pbase(), _Mysb::pptr()};
}
return _Buf;
}
void span(_STD span<_Elem> _Span) noexcept {
_Buf = _Span;
const auto _First = _Buf.data();
const auto _Last = _First + _Buf.size();
if (_Mode & ios_base::out) {
if (_Mode & ios_base::ate) {
_Mysb::setp(_First, _Last, _Last);
} else {
_Mysb::setp(_First, _First, _Last);
}
}
if (_Mode & ios_base::in) {
_Mysb::setg(_First, _First, _Last);
}
}
protected:
// N4950 [spanbuf.virtuals], overridden virtual functions
pos_type seekoff(
off_type _Off, ios_base::seekdir _Way, ios_base::openmode _Which = ios_base::in | ios_base::out) override {
const bool _Sequence_in = _Which & ios_base::in;
const bool _Sequence_out = _Which & ios_base::out;
switch (_Way) {
case ios_base::beg:
// N4950 [spanbuf.virtuals]/4.1 baseoff = 0
if (static_cast<size_t>(_Off) > _Buf.size()) { // negative wraparound to positive to save a compare
return pos_type{off_type{-1}}; // N4950 [spanbuf.virtuals]/5 report failure
}
break;
case ios_base::end:
{
// N4950 [spanbuf.virtuals]/4.3 baseoff =
const auto _Baseoff = (_Mode & ios_base::out) && !(_Mode & ios_base::in)
? static_cast<off_type>(_Mysb::pptr() - _Mysb::pbase())
: static_cast<off_type>(_Buf.size());
if (_Off > _STD _Max_limit<off_type>() - _Baseoff) { // overflow, _Baseoff is always non-negative
return pos_type{off_type{-1}}; // report failure
}
_Off += _Baseoff;
if (static_cast<size_t>(_Off) > _Buf.size()) { // negative wraparound to positive to save a compare
return pos_type{off_type{-1}}; // N4950 [spanbuf.virtuals]/5 report failure
}
break;
}
case ios_base::cur:
if (_Sequence_in && _Sequence_out) {
return pos_type{off_type{-1}}; // report failure
} else if (_Sequence_in || _Sequence_out) {
const off_type _Oldoff = _Sequence_in ? static_cast<off_type>(_Mysb::gptr() - _Mysb::eback())
: static_cast<off_type>(_Mysb::pptr() - _Mysb::pbase());
const off_type _Oldleft = static_cast<off_type>(_Buf.size() - _Oldoff);
if (_Off < -_Oldoff || _Off > _Oldleft) { // out of bounds
return pos_type{off_type{-1}};
}
_Off += _Oldoff;
} else {
return pos_type{off_type{-1}}; // report failure
}
break;
default:
return pos_type{off_type{-1}}; // report failure
}
// N4950 [spanbuf.virtuals]/4: For a sequence to be positioned, if its next pointer is a null pointer and newoff
// is not equal to 0, the positioning operation fails.
if (_Off != 0 && ((_Sequence_in && !_Mysb::gptr()) || (_Sequence_out && !_Mysb::pptr()))) {
return pos_type{off_type{-1}}; // report failure
}
if (_Sequence_in) {
_Mysb::gbump(static_cast<int>(_Off - (_Mysb::gptr() - _Mysb::eback())));
}
if (_Sequence_out) {
_Mysb::pbump(static_cast<int>(_Off - (_Mysb::pptr() - _Mysb::pbase())));
}
return pos_type{_Off};
}
pos_type seekpos(pos_type _Pos, ios_base::openmode _Which = ios_base::in | ios_base::out) override {
return seekoff(off_type{_Pos}, ios_base::beg, _Which);
}
_Mysb* setbuf(_Elem* _Buffer, streamsize _Count) override {
this->span(_STD span<_Elem>{_Buffer, static_cast<size_t>(_Count)});
return this;
}
private:
ios_base::openmode _Mode{ios_base::in | ios_base::out};
_STD span<_Elem> _Buf{};
};
_EXPORT_STD template <class _Elem, class _Traits>
void swap(basic_spanbuf<_Elem, _Traits>& _Left, basic_spanbuf<_Elem, _Traits>& _Right) noexcept /* strengthened */ {
_Left.swap(_Right);
}
_EXPORT_STD template <class _Elem, class _Traits>
class basic_ispanstream : public basic_istream<_Elem, _Traits> {
private:
using _Mybase = basic_istream<_Elem, _Traits>;
using _Mysb = basic_spanbuf<_Elem, _Traits>;
public:
using char_type = _Elem;
using int_type = _Traits::int_type;
using pos_type = _Traits::pos_type;
using off_type = _Traits::off_type;
using traits_type = _Traits;
// N4950 [ispanstream.cons], constructors
explicit basic_ispanstream(_STD span<_Elem> _Span, ios_base::openmode _Which = ios_base::in)
: _Mybase(_STD addressof(_Buf)), _Buf(_Span, _Which | ios_base::in) {}
basic_ispanstream(const basic_ispanstream&) = delete;
basic_ispanstream(basic_ispanstream&& _Right) : _Mybase(_STD move(_Right)), _Buf(_STD move(_Right._Buf)) {
_Mybase::set_rdbuf(_STD addressof(_Buf));
}
template <_RANGES borrowed_range _ReadOnlyRange>
requires (
!convertible_to<_ReadOnlyRange, _STD span<_Elem>> && convertible_to<_ReadOnlyRange, _STD span<const _Elem>>)
explicit basic_ispanstream(_ReadOnlyRange&& _Range)
: basic_ispanstream(
_STD span<_Elem>{const_cast<_Elem*>(_RANGES data(_Range)), static_cast<size_t>(_RANGES size(_Range))}) {}
basic_ispanstream& operator=(const basic_ispanstream&) = delete;
basic_ispanstream& operator=(basic_ispanstream&& _Right) noexcept /* strengthened */ {
_Mybase::swap(_Right);
_Buf.swap(_Right._Buf);
return *this;
}
// N4950 [ispanstream.swap], swap
void swap(basic_ispanstream& _Right) noexcept /* strengthened */ {
_Mybase::swap(_Right);
_Buf.swap(_Right._Buf);
}
// N4950 [ispanstream.members], member functions
_NODISCARD _Mysb* rdbuf() const noexcept {
return const_cast<_Mysb*>(_STD addressof(_Buf));
}
_NODISCARD _STD span<const _Elem> span() const noexcept {
return rdbuf()->span();
}
void span(_STD span<_Elem> _Span) noexcept {
rdbuf()->span(_Span);
}
template <_RANGES borrowed_range _ReadOnlyRange>
requires (
!convertible_to<_ReadOnlyRange, _STD span<_Elem>> && convertible_to<_ReadOnlyRange, _STD span<const _Elem>>)
void span(_ReadOnlyRange&& _Range) noexcept {
this->span(
_STD span<_Elem>{const_cast<_Elem*>(_RANGES data(_Range)), static_cast<size_t>(_RANGES size(_Range))});
}
private:
_Mysb _Buf;
};
_EXPORT_STD template <class _Elem, class _Traits>
void swap(basic_ispanstream<_Elem, _Traits>& _Left, basic_ispanstream<_Elem, _Traits>& _Right) noexcept
/* strengthened */ {
_Left.swap(_Right);
}
_EXPORT_STD template <class _Elem, class _Traits>
class basic_ospanstream : public basic_ostream<_Elem, _Traits> {
private:
using _Mybase = basic_ostream<_Elem, _Traits>;
using _Mysb = basic_spanbuf<_Elem, _Traits>;
public:
using char_type = _Elem;
using int_type = _Traits::int_type;
using pos_type = _Traits::pos_type;
using off_type = _Traits::off_type;
using traits_type = _Traits;
// N4950 [ospanstream.cons], constructors
explicit basic_ospanstream(_STD span<_Elem> _Span, ios_base::openmode _Which = ios_base::out)
: _Mybase(_STD addressof(_Buf)), _Buf(_Span, _Which | ios_base::out) {}
basic_ospanstream(const basic_ospanstream&) = delete;
basic_ospanstream(basic_ospanstream&& _Right) : _Mybase(_STD move(_Right)), _Buf(_STD move(_Right._Buf)) {
_Mybase::set_rdbuf(_STD addressof(_Buf));
}
basic_ospanstream& operator=(const basic_ospanstream&) = delete;
basic_ospanstream& operator=(basic_ospanstream&& _Right) noexcept /* strengthened */ {
_Mybase::swap(_Right);
_Buf.swap(_Right._Buf);
return *this;
}
// N4950 [ospanstream.swap], swap
void swap(basic_ospanstream& _Right) noexcept /* strengthened */ {
_Mybase::swap(_Right);
_Buf.swap(_Right._Buf);
}
// N4950 [ospanstream.members], member functions
_NODISCARD _Mysb* rdbuf() const noexcept {
return const_cast<_Mysb*>(_STD addressof(_Buf));
}
_NODISCARD _STD span<_Elem> span() const noexcept {
return rdbuf()->span();
}
void span(_STD span<_Elem> _Span) noexcept {
rdbuf()->span(_Span);
}
private:
_Mysb _Buf;
};
_EXPORT_STD template <class _Elem, class _Traits>
void swap(basic_ospanstream<_Elem, _Traits>& _Left, basic_ospanstream<_Elem, _Traits>& _Right) noexcept
/* strengthened */ {
_Left.swap(_Right);
}
_EXPORT_STD template <class _Elem, class _Traits>
class basic_spanstream : public basic_iostream<_Elem, _Traits> {
private:
using _Mybase = basic_iostream<_Elem, _Traits>;
using _Mysb = basic_spanbuf<_Elem, _Traits>;
public:
using char_type = _Elem;
using int_type = _Traits::int_type;
using pos_type = _Traits::pos_type;
using off_type = _Traits::off_type;
using traits_type = _Traits;
// N4950 [spanstream.cons], constructors
explicit basic_spanstream(_STD span<_Elem> _Span, ios_base::openmode _Which = ios_base::out | ios_base::in)
: _Mybase(_STD addressof(_Buf)), _Buf(_Span, _Which) {}
basic_spanstream(const basic_spanstream&) = delete;
basic_spanstream(basic_spanstream&& _Right) : _Mybase(_STD move(_Right)), _Buf(_STD move(_Right._Buf)) {
_Mybase::set_rdbuf(_STD addressof(_Buf));
}
basic_spanstream& operator=(const basic_spanstream&) = delete;
basic_spanstream& operator=(basic_spanstream&& _Right) noexcept /* strengthened */ {
_Mybase::swap(_Right);
_Buf.swap(_Right._Buf);
return *this;
}
// N4950 [spanstream.swap], swap
void swap(basic_spanstream& _Right) noexcept /* strengthened */ {
_Mybase::swap(_Right);
_Buf.swap(_Right._Buf);
}
// N4950 [spanstream.members], member functions
_NODISCARD _Mysb* rdbuf() const noexcept {
return const_cast<_Mysb*>(_STD addressof(_Buf));
}
_NODISCARD _STD span<_Elem> span() const noexcept {
return rdbuf()->span();
}
void span(_STD span<_Elem> _Span) noexcept {
rdbuf()->span(_Span);
}
private:
_Mysb _Buf;
};
_EXPORT_STD template <class _Elem, class _Traits>
void swap(basic_spanstream<_Elem, _Traits>& _Left, basic_spanstream<_Elem, _Traits>& _Right) noexcept
/* strengthened */ {
_Left.swap(_Right);
}
_STD_END
#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)
#pragma pack(pop)
#endif // ^^^ _HAS_CXX23 ^^^
#endif // _STL_COMPILER_PREPROCESSOR
#endif // _SPANSTREAM_