a30a2e43e4
This implements the <spanstream> header, as proposed for C++23 by P0448R4. libstdc++-v3/ChangeLog: * include/Makefile.am: Add spanstream header. * include/Makefile.in: Regenerate. * include/precompiled/stdc++.h: Add spanstream header. * include/std/version (__cpp_lib_spanstream): Define. * include/std/spanstream: New file. * testsuite/27_io/spanstream/1.cc: New test. * testsuite/27_io/spanstream/version.cc: New test.
447 lines
12 KiB
C++
447 lines
12 KiB
C++
// Streams based on std::span -*- C++ -*-
|
|
|
|
// Copyright The GNU Toolchain Authors.
|
|
//
|
|
// This file is part of the GNU ISO C++ Library. This library is free
|
|
// software; you can redistribute it and/or modify it under the
|
|
// terms of the GNU General Public License as published by the
|
|
// Free Software Foundation; either version 3, or (at your option)
|
|
// any later version.
|
|
|
|
// This library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
// Under Section 7 of GPL version 3, you are granted additional
|
|
// permissions described in the GCC Runtime Library Exception, version
|
|
// 3.1, as published by the Free Software Foundation.
|
|
|
|
// You should have received a copy of the GNU General Public License and
|
|
// a copy of the GCC Runtime Library Exception along with this program;
|
|
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|
// <http://www.gnu.org/licenses/>.
|
|
|
|
/** @file spanstream
|
|
* This is a Standard C++ Library header.
|
|
*/
|
|
|
|
#ifndef _GLIBCXX_SPANSTREAM
|
|
#define _GLIBCXX_SPANSTREAM 1
|
|
|
|
#pragma GCC system_header
|
|
|
|
#if __cplusplus > 202002L
|
|
#include <span>
|
|
#include <streambuf>
|
|
#include <istream>
|
|
#include <ostream>
|
|
#include <bits/ranges_base.h>
|
|
|
|
#if __cpp_lib_span
|
|
namespace std _GLIBCXX_VISIBILITY(default)
|
|
{
|
|
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|
|
|
#define __cpp_lib_spanstream 202106L
|
|
|
|
template<typename _CharT, typename _Traits = char_traits<_CharT>>
|
|
class basic_spanbuf
|
|
: public basic_streambuf<_CharT, _Traits>
|
|
{
|
|
using __streambuf_type = basic_streambuf<_CharT, _Traits>;
|
|
|
|
public:
|
|
using char_type = _CharT;
|
|
using int_type = typename _Traits::int_type;
|
|
using pos_type = typename _Traits::pos_type;
|
|
using off_type = typename _Traits::off_type;
|
|
using traits_type = _Traits;
|
|
|
|
// [spanbuf.ctor], constructors
|
|
basic_spanbuf() : basic_spanbuf(ios_base::in | ios_base::out)
|
|
{ }
|
|
|
|
explicit
|
|
basic_spanbuf(ios_base::openmode __which)
|
|
: __streambuf_type(), _M_mode(__which)
|
|
{ }
|
|
|
|
explicit
|
|
basic_spanbuf(std::span<_CharT> __s,
|
|
ios_base::openmode __which = ios_base::in | ios_base::out)
|
|
: __streambuf_type(), _M_mode(__which)
|
|
{ span(__s); }
|
|
|
|
basic_spanbuf(const basic_spanbuf&) = delete;
|
|
|
|
/// Move constructor. In this implementation `rhs` is left unchanged.
|
|
basic_spanbuf(basic_spanbuf&& __rhs)
|
|
: __streambuf_type(__rhs), _M_mode(__rhs._M_mode)
|
|
{ span(__rhs._M_buf); }
|
|
|
|
// [spanbuf.assign], assignment and swap
|
|
basic_spanbuf& operator=(const basic_spanbuf&) = delete;
|
|
|
|
basic_spanbuf&
|
|
operator=(basic_spanbuf&& __rhs)
|
|
{
|
|
basic_spanbuf(std::move(__rhs))->swap(*this);
|
|
return *this;
|
|
}
|
|
|
|
void
|
|
swap(basic_spanbuf& __rhs)
|
|
{
|
|
__streambuf_type::swap(__rhs);
|
|
std::swap(_M_mode, __rhs._M_mode);
|
|
std::swap(_M_buf, __rhs._M_buf);
|
|
}
|
|
|
|
// [spanbuf.members], member functions
|
|
std::span<_CharT>
|
|
span() const noexcept
|
|
{
|
|
if (_M_mode & ios_base::out)
|
|
return {this->pbase(), this->pptr()};
|
|
else
|
|
return _M_buf;
|
|
}
|
|
|
|
void
|
|
span(std::span<_CharT> __s) noexcept
|
|
{
|
|
_M_buf = __s;
|
|
if (_M_mode & ios_base::out)
|
|
{
|
|
this->setp(__s.data(), __s.data() + __s.size());
|
|
if (_M_mode & ios_base::ate)
|
|
this->pbump(__s.size());
|
|
}
|
|
if (_M_mode & ios_base::in)
|
|
this->setg(__s.data(), __s.data(), __s.data() + __s.size());
|
|
}
|
|
|
|
protected:
|
|
// [spanbuf.virtuals], overridden virtual functions
|
|
basic_streambuf<_CharT, _Traits>*
|
|
setbuf(_CharT* __s, streamsize __n) override
|
|
{
|
|
span({__s, __n});
|
|
return this;
|
|
}
|
|
|
|
pos_type
|
|
seekoff(off_type __off, ios_base::seekdir __way,
|
|
ios_base::openmode __which = ios_base::in | ios_base::out) override
|
|
{
|
|
pos_type __ret = pos_type(off_type(-1));
|
|
|
|
if (__way == ios_base::beg)
|
|
{
|
|
if (0 <= __off && __off <= _M_buf.size())
|
|
{
|
|
if (__which & ios_base::in)
|
|
this->setg(this->eback(), this->eback() + __off, this->egptr());
|
|
|
|
if (__which & ios_base::out)
|
|
{
|
|
this->setp(this->pbase(), this->epptr());
|
|
this->pbump(__off);
|
|
}
|
|
|
|
__ret = pos_type(__off);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
off_type __base;
|
|
__which &= (ios_base::in|ios_base::out);
|
|
|
|
if (__which == ios_base::out)
|
|
__base = this->pptr() - this->pbase();
|
|
else if (__way == ios_base::cur)
|
|
{
|
|
if (__which == ios_base::in)
|
|
__base = this->gptr() - this->eback();
|
|
else
|
|
return __ret;
|
|
}
|
|
else if (__way == ios_base::end)
|
|
__base = _M_buf.size();
|
|
|
|
if (__builtin_add_overflow(__base, __off, &__off))
|
|
return __ret;
|
|
|
|
if (__off < 0 || __off > _M_buf.size())
|
|
return __ret;
|
|
|
|
if (__which & ios_base::in)
|
|
this->setg(this->eback(), this->eback() + __off, this->egptr());
|
|
|
|
if (__which & ios_base::out)
|
|
{
|
|
this->setp(this->pbase(), this->epptr());
|
|
this->pbump(__off);
|
|
}
|
|
|
|
__ret = pos_type(__off);
|
|
|
|
}
|
|
return __ret;
|
|
}
|
|
|
|
pos_type
|
|
seekpos(pos_type __sp,
|
|
ios_base::openmode __which = ios_base::in | ios_base::out) override
|
|
{ return seekoff(off_type(__sp), ios_base::beg, __which); }
|
|
|
|
private:
|
|
|
|
ios_base::openmode _M_mode;
|
|
std::span<_CharT> _M_buf;
|
|
};
|
|
|
|
template<typename _CharT, typename _Traits>
|
|
inline void
|
|
swap(basic_spanbuf<_CharT, _Traits>& __x,
|
|
basic_spanbuf<_CharT, _Traits>& __y)
|
|
{ __x.swap(__y); }
|
|
|
|
using spanbuf = basic_spanbuf<char>;
|
|
using wspanbuf = basic_spanbuf<wchar_t>;
|
|
|
|
template<typename _CharT, typename _Traits = char_traits<_CharT>>
|
|
class basic_ispanstream
|
|
: public basic_istream<_CharT, _Traits>
|
|
{
|
|
using __istream_type = basic_istream<_CharT, _Traits>;
|
|
|
|
public:
|
|
using char_type = _CharT;
|
|
using int_type = typename _Traits::int_type;
|
|
using pos_type = typename _Traits::pos_type;
|
|
using off_type = typename _Traits::off_type;
|
|
using traits_type = _Traits;
|
|
|
|
// [ispanstream.ctor], constructors
|
|
explicit
|
|
basic_ispanstream(std::span<_CharT> __s,
|
|
ios_base::openmode __which = ios_base::in)
|
|
: __istream_type(std::__addressof(_M_sb)),
|
|
_M_sb(__s, __which | ios_base::in)
|
|
{ }
|
|
|
|
basic_ispanstream(const basic_ispanstream&) = delete;
|
|
|
|
basic_ispanstream(basic_ispanstream&& __rhs)
|
|
: __istream_type(std::move(__rhs)), _M_sb(std::move(__rhs._M_sb))
|
|
{
|
|
__istream_type::set_rdbuf(std::addressof(_M_sb));
|
|
}
|
|
|
|
template<typename _Ros>
|
|
requires ranges::borrowed_range<_Ros>
|
|
&& (!convertible_to<_Ros, std::span<_CharT>>)
|
|
&& convertible_to<_Ros, std::span<const _CharT>>
|
|
explicit
|
|
basic_ispanstream(_Ros&& __s)
|
|
: __istream_type(std::__addressof(_M_sb)),
|
|
_M_sb(ios_base::in)
|
|
{
|
|
std::span<const _CharT> __sp(std::forward<_Ros>(__s));
|
|
_M_sb.span({const_cast<_CharT*>(__sp.data()), __sp.size()});
|
|
}
|
|
|
|
// [ispanstream.assign], assignment and swap
|
|
basic_ispanstream& operator=(const basic_ispanstream&) = delete;
|
|
basic_ispanstream& operator=(basic_ispanstream&& __rhs) = default;
|
|
|
|
void
|
|
swap(basic_ispanstream& __rhs)
|
|
{
|
|
__istream_type::swap(__rhs);
|
|
_M_sb.swap(__rhs._M_sb);
|
|
}
|
|
|
|
// [ispanstream.members], member functions
|
|
basic_spanbuf<_CharT, _Traits>*
|
|
rdbuf() const noexcept
|
|
{
|
|
return const_cast<basic_spanbuf<_CharT, _Traits>*>(std::__addressof(_M_sb));
|
|
}
|
|
|
|
std::span<const _CharT>
|
|
span() const noexcept
|
|
{ return _M_sb.span(); }
|
|
|
|
void
|
|
span(std::span<_CharT> __s) noexcept
|
|
{ return _M_sb.span(__s); }
|
|
|
|
template<typename _Ros>
|
|
requires ranges::borrowed_range<_Ros>
|
|
&& (!convertible_to<_Ros, std::span<_CharT>>)
|
|
&& convertible_to<_Ros, std::span<const _CharT>>
|
|
void
|
|
span(_Ros&& __s) noexcept
|
|
{
|
|
std::span<const _CharT> __sp(std::forward<_Ros>(__s));
|
|
_M_sb.span({const_cast<_CharT*>(__sp.data()), __sp.size()});
|
|
}
|
|
|
|
private:
|
|
basic_spanbuf<_CharT, _Traits> _M_sb;
|
|
};
|
|
|
|
template<typename _CharT, typename _Traits>
|
|
inline void
|
|
swap(basic_ispanstream<_CharT, _Traits>& __x,
|
|
basic_ispanstream<_CharT, _Traits>& __y)
|
|
{ __x.swap(__y); }
|
|
|
|
using ispanstream = basic_ispanstream<char>;
|
|
using wispanstream = basic_ispanstream<wchar_t>;
|
|
|
|
template<typename _CharT, typename _Traits = char_traits<_CharT>>
|
|
class basic_ospanstream
|
|
: public basic_ostream<_CharT, _Traits>
|
|
{
|
|
using __ostream_type = basic_ostream<_CharT, _Traits>;
|
|
|
|
public:
|
|
using char_type = _CharT;
|
|
using int_type = typename _Traits::int_type;
|
|
using pos_type = typename _Traits::pos_type;
|
|
using off_type = typename _Traits::off_type;
|
|
using traits_type = _Traits;
|
|
|
|
// [ospanstream.ctor], constructors
|
|
explicit
|
|
basic_ospanstream(std::span<_CharT> __s,
|
|
ios_base::openmode __which = ios_base::out)
|
|
: __ostream_type(std::__addressof(_M_sb)),
|
|
_M_sb(__s, __which | ios_base::in)
|
|
{ }
|
|
|
|
basic_ospanstream(const basic_ospanstream&) = delete;
|
|
|
|
basic_ospanstream(basic_ospanstream&& __rhs)
|
|
: __ostream_type(std::move(__rhs)), _M_sb(std::move(__rhs._M_sb))
|
|
{
|
|
__ostream_type::set_rdbuf(std::addressof(_M_sb));
|
|
}
|
|
|
|
// [ospanstream.assign], assignment and swap
|
|
basic_ospanstream& operator=(const basic_ospanstream&) = delete;
|
|
basic_ospanstream& operator=(basic_ospanstream&& __rhs) = default;
|
|
|
|
void
|
|
swap(basic_ospanstream& __rhs)
|
|
{
|
|
__ostream_type::swap(__rhs);
|
|
_M_sb.swap(__rhs._M_sb);
|
|
}
|
|
|
|
// [ospanstream.members], member functions
|
|
basic_spanbuf<_CharT, _Traits>*
|
|
rdbuf() const noexcept
|
|
{
|
|
return const_cast<basic_spanbuf<_CharT, _Traits>*>(std::__addressof(_M_sb));
|
|
}
|
|
|
|
std::span<_CharT>
|
|
span() const noexcept
|
|
{ return _M_sb.span(); }
|
|
|
|
void
|
|
span(std::span<_CharT> __s) noexcept
|
|
{ return _M_sb.span(__s); }
|
|
|
|
private:
|
|
basic_spanbuf<_CharT, _Traits> _M_sb;
|
|
};
|
|
|
|
template<typename _CharT, typename _Traits>
|
|
inline void
|
|
swap(basic_ospanstream<_CharT, _Traits>& __x,
|
|
basic_ospanstream<_CharT, _Traits>& __y)
|
|
{ __x.swap(__y); }
|
|
|
|
using ospanstream = basic_ospanstream<char>;
|
|
using wospanstream = basic_ospanstream<wchar_t>;
|
|
|
|
template<typename _CharT, typename _Traits = char_traits<_CharT>>
|
|
class basic_spanstream
|
|
: public basic_iostream<_CharT, _Traits>
|
|
{
|
|
using __iostream_type = basic_iostream<_CharT, _Traits>;
|
|
|
|
public:
|
|
using char_type = _CharT;
|
|
using int_type = typename _Traits::int_type;
|
|
using pos_type = typename _Traits::pos_type;
|
|
using off_type = typename _Traits::off_type;
|
|
using traits_type = _Traits;
|
|
|
|
// [spanstream.ctor], constructors
|
|
explicit
|
|
basic_spanstream(std::span<_CharT> __s,
|
|
ios_base::openmode __which = ios_base::out | ios_base::in)
|
|
: __iostream_type(std::__addressof(_M_sb)),
|
|
_M_sb(__s, __which)
|
|
{ }
|
|
|
|
basic_spanstream(const basic_spanstream&) = delete;
|
|
|
|
basic_spanstream(basic_spanstream&& __rhs)
|
|
: __iostream_type(std::move(__rhs)), _M_sb(std::move(__rhs._M_sb))
|
|
{
|
|
__iostream_type::set_rdbuf(std::addressof(_M_sb));
|
|
}
|
|
|
|
// [spanstream.assign], assignment and swap
|
|
basic_spanstream& operator=(const basic_spanstream&) = delete;
|
|
basic_spanstream& operator=(basic_spanstream&& __rhs) = default;
|
|
|
|
void
|
|
swap(basic_spanstream& __rhs)
|
|
{
|
|
__iostream_type::swap(__rhs);
|
|
_M_sb.swap(__rhs._M_sb);
|
|
}
|
|
|
|
// [spanstream.members], members
|
|
basic_spanbuf<_CharT, _Traits>*
|
|
rdbuf() const noexcept
|
|
{
|
|
return const_cast<basic_spanbuf<_CharT, _Traits>*>(std::__addressof(_M_sb));
|
|
}
|
|
|
|
std::span<_CharT>
|
|
span() const noexcept
|
|
{ return _M_sb.span(); }
|
|
|
|
void
|
|
span(std::span<_CharT> __s) noexcept
|
|
{ return _M_sb.span(__s); }
|
|
|
|
private:
|
|
basic_spanbuf<_CharT, _Traits> _M_sb;
|
|
};
|
|
|
|
template<typename _CharT, typename _Traits>
|
|
inline void
|
|
swap(basic_spanstream<_CharT, _Traits>& __x,
|
|
basic_spanstream<_CharT, _Traits>& __y)
|
|
{ __x.swap(__y); }
|
|
|
|
using spanstream = basic_spanstream<char>;
|
|
using wspanstream = basic_spanstream<wchar_t>;
|
|
|
|
_GLIBCXX_END_NAMESPACE_VERSION
|
|
} // namespace std
|
|
#endif // __cpp_lib_span
|
|
#endif // C++23
|
|
#endif // _GLIBCXX_SPANSTREAM
|