Home | History | Annotate | Line # | Download | only in std
      1 // Streams based on std::span -*- C++ -*-
      2 
      3 // Copyright The GNU Toolchain Authors.
      4 //
      5 // This file is part of the GNU ISO C++ Library.  This library is free
      6 // software; you can redistribute it and/or modify it under the
      7 // terms of the GNU General Public License as published by the
      8 // Free Software Foundation; either version 3, or (at your option)
      9 // any later version.
     10 
     11 // This library is distributed in the hope that it will be useful,
     12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 // GNU General Public License for more details.
     15 
     16 // Under Section 7 of GPL version 3, you are granted additional
     17 // permissions described in the GCC Runtime Library Exception, version
     18 // 3.1, as published by the Free Software Foundation.
     19 
     20 // You should have received a copy of the GNU General Public License and
     21 // a copy of the GCC Runtime Library Exception along with this program;
     22 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     23 // <http://www.gnu.org/licenses/>.
     24 
     25 /** @file spanstream
     26  *  This is a Standard C++ Library header.
     27  */
     28 
     29 #ifndef _GLIBCXX_SPANSTREAM
     30 #define _GLIBCXX_SPANSTREAM 1
     31 
     32 #pragma GCC system_header
     33 
     34 #if __cplusplus > 202002L
     35 #include <span>
     36 #include <streambuf>
     37 #include <istream>
     38 #include <ostream>
     39 #include <bits/ranges_base.h>
     40 
     41 #if __cpp_lib_span
     42 namespace std _GLIBCXX_VISIBILITY(default)
     43 {
     44 _GLIBCXX_BEGIN_NAMESPACE_VERSION
     45 
     46 #define __cpp_lib_spanstream 202106L
     47 
     48 template<typename _CharT, typename _Traits>
     49   class basic_spanbuf
     50   : public basic_streambuf<_CharT, _Traits>
     51   {
     52     using __streambuf_type = basic_streambuf<_CharT, _Traits>;
     53 
     54   public:
     55     using char_type   = _CharT;
     56     using int_type    = typename _Traits::int_type;
     57     using pos_type    = typename _Traits::pos_type;
     58     using off_type    = typename _Traits::off_type;
     59     using traits_type = _Traits;
     60 
     61     // [spanbuf.ctor], constructors
     62     basic_spanbuf() : basic_spanbuf(ios_base::in | ios_base::out)
     63     { }
     64 
     65     explicit
     66     basic_spanbuf(ios_base::openmode __which)
     67     : __streambuf_type(), _M_mode(__which)
     68     { }
     69 
     70     explicit
     71     basic_spanbuf(std::span<_CharT> __s,
     72 		  ios_base::openmode __which = ios_base::in | ios_base::out)
     73     : __streambuf_type(), _M_mode(__which)
     74     { span(__s); }
     75 
     76     basic_spanbuf(const basic_spanbuf&) = delete;
     77 
     78     /** Move constructor.
     79      *
     80      * Transfers the buffer and pointers into the get and put areas from
     81      * `__rhs` to `*this`.
     82      *
     83      * In this implementation `rhs` is left unchanged,
     84      * but that is not guaranteed by the standard.
     85      */
     86     basic_spanbuf(basic_spanbuf&& __rhs)
     87     : __streambuf_type(__rhs), _M_mode(__rhs._M_mode), _M_buf(__rhs._M_buf)
     88     { }
     89 
     90     // [spanbuf.assign], assignment and swap
     91     basic_spanbuf& operator=(const basic_spanbuf&) = delete;
     92 
     93     basic_spanbuf&
     94     operator=(basic_spanbuf&& __rhs)
     95     {
     96       basic_spanbuf(std::move(__rhs)).swap(*this);
     97       return *this;
     98     }
     99 
    100     void
    101     swap(basic_spanbuf& __rhs)
    102     {
    103       __streambuf_type::swap(__rhs);
    104       std::swap(_M_mode, __rhs._M_mode);
    105       std::swap(_M_buf, __rhs._M_buf);
    106     }
    107 
    108     // [spanbuf.members], member functions
    109     std::span<_CharT>
    110     span() const noexcept
    111     {
    112       if (_M_mode & ios_base::out)
    113 	return {this->pbase(), this->pptr()};
    114       else
    115 	return _M_buf;
    116     }
    117 
    118     void
    119     span(std::span<_CharT> __s) noexcept
    120     {
    121       _M_buf = __s;
    122       if (_M_mode & ios_base::out)
    123 	{
    124 	  this->setp(__s.data(), __s.data() + __s.size());
    125 	  if (_M_mode & ios_base::ate)
    126 	    this->pbump(__s.size());
    127 	}
    128       if (_M_mode & ios_base::in)
    129 	this->setg(__s.data(), __s.data(), __s.data() + __s.size());
    130     }
    131 
    132   protected:
    133     // [spanbuf.virtuals], overridden virtual functions
    134     basic_streambuf<_CharT, _Traits>*
    135     setbuf(_CharT* __s, streamsize __n) override
    136     {
    137       __glibcxx_assert(__n >= 0);
    138       this->span(std::span<_CharT>(__s, __n));
    139       return this;
    140     }
    141 
    142     pos_type
    143     seekoff(off_type __off, ios_base::seekdir __way,
    144 	    ios_base::openmode __which = ios_base::in | ios_base::out) override
    145     {
    146       pos_type __ret =  pos_type(off_type(-1));
    147 
    148       if (__way == ios_base::beg)
    149 	{
    150 	  if (0 <= __off && __off <= _M_buf.size())
    151 	    {
    152 	      if (__which & ios_base::in)
    153 		this->setg(this->eback(), this->eback() + __off, this->egptr());
    154 
    155 	      if (__which & ios_base::out)
    156 		{
    157 		  this->setp(this->pbase(), this->epptr());
    158 		  this->pbump(__off);
    159 		}
    160 
    161 	      __ret = pos_type(__off);
    162 	    }
    163 	}
    164       else
    165 	{
    166 	  off_type __base;
    167 	  __which &= (ios_base::in|ios_base::out);
    168 
    169 	  if (__which == ios_base::out)
    170 	    __base = this->pptr() - this->pbase();
    171 	  else if (__way == ios_base::cur)
    172 	    {
    173 	      if (__which == ios_base::in)
    174 		__base = this->gptr() - this->eback();
    175 	      else
    176 		return __ret;
    177 	    }
    178 	  else if (__way == ios_base::end)
    179 	    __base = _M_buf.size();
    180 
    181 	  if (__builtin_add_overflow(__base, __off, &__off))
    182 	    return __ret;
    183 
    184 	  if (__off < 0 || __off > _M_buf.size())
    185 	    return __ret;
    186 
    187 	  if (__which & ios_base::in)
    188 	    this->setg(this->eback(), this->eback() + __off, this->egptr());
    189 
    190 	  if (__which & ios_base::out)
    191 	    {
    192 	      this->setp(this->pbase(), this->epptr());
    193 	      this->pbump(__off);
    194 	    }
    195 
    196 	  __ret = pos_type(__off);
    197 
    198 	}
    199       return __ret;
    200     }
    201 
    202     pos_type
    203     seekpos(pos_type __sp,
    204 	    ios_base::openmode __which = ios_base::in | ios_base::out) override
    205     { return seekoff(off_type(__sp), ios_base::beg, __which); }
    206 
    207   private:
    208 
    209     ios_base::openmode _M_mode;
    210     std::span<_CharT> _M_buf;
    211   };
    212 
    213 template<typename _CharT, typename _Traits>
    214   inline void
    215   swap(basic_spanbuf<_CharT, _Traits>& __x,
    216        basic_spanbuf<_CharT, _Traits>& __y)
    217   { __x.swap(__y); }
    218 
    219 using spanbuf = basic_spanbuf<char>;
    220 using wspanbuf = basic_spanbuf<wchar_t>;
    221 
    222 template<typename _CharT, typename _Traits>
    223   class basic_ispanstream
    224   : public basic_istream<_CharT, _Traits>
    225   {
    226     using __istream_type = basic_istream<_CharT, _Traits>;
    227 
    228   public:
    229     using char_type   = _CharT;
    230     using int_type    = typename _Traits::int_type;
    231     using pos_type    = typename _Traits::pos_type;
    232     using off_type    = typename _Traits::off_type;
    233     using traits_type = _Traits;
    234 
    235     // [ispanstream.ctor], constructors
    236     explicit
    237     basic_ispanstream(std::span<_CharT> __s,
    238 		      ios_base::openmode __which = ios_base::in)
    239     : __istream_type(std::__addressof(_M_sb)),
    240       _M_sb(__s, __which | ios_base::in)
    241     { }
    242 
    243     basic_ispanstream(const basic_ispanstream&) = delete;
    244 
    245     basic_ispanstream(basic_ispanstream&& __rhs)
    246     : __istream_type(std::move(__rhs)), _M_sb(std::move(__rhs._M_sb))
    247     {
    248       __istream_type::set_rdbuf(std::addressof(_M_sb));
    249     }
    250 
    251     template<typename _Ros>
    252       requires ranges::borrowed_range<_Ros>
    253 	&& (!convertible_to<_Ros, std::span<_CharT>>)
    254 	&& convertible_to<_Ros, std::span<const _CharT>>
    255       explicit
    256       basic_ispanstream(_Ros&& __s)
    257       : __istream_type(std::__addressof(_M_sb)),
    258 	_M_sb(ios_base::in)
    259       {
    260 	std::span<const _CharT> __sp(std::forward<_Ros>(__s));
    261 	_M_sb.span({const_cast<_CharT*>(__sp.data()), __sp.size()});
    262       }
    263 
    264     // [ispanstream.assign], assignment and swap
    265     basic_ispanstream& operator=(const basic_ispanstream&) = delete;
    266     basic_ispanstream& operator=(basic_ispanstream&& __rhs) = default;
    267 
    268     void
    269     swap(basic_ispanstream& __rhs)
    270     {
    271       __istream_type::swap(__rhs);
    272       _M_sb.swap(__rhs._M_sb);
    273     }
    274 
    275     // [ispanstream.members], member functions
    276     basic_spanbuf<_CharT, _Traits>*
    277     rdbuf() const noexcept
    278     {
    279       return const_cast<basic_spanbuf<_CharT, _Traits>*>(std::__addressof(_M_sb));
    280     }
    281 
    282     std::span<const _CharT>
    283     span() const noexcept
    284     { return _M_sb.span(); }
    285 
    286     void
    287     span(std::span<_CharT> __s) noexcept
    288     { return _M_sb.span(__s); }
    289 
    290     template<typename _Ros>
    291       requires ranges::borrowed_range<_Ros>
    292 	&& (!convertible_to<_Ros, std::span<_CharT>>)
    293 	&& convertible_to<_Ros, std::span<const _CharT>>
    294       void
    295       span(_Ros&& __s) noexcept
    296       {
    297 	std::span<const _CharT> __sp(std::forward<_Ros>(__s));
    298 	_M_sb.span({const_cast<_CharT*>(__sp.data()), __sp.size()});
    299       }
    300 
    301   private:
    302     basic_spanbuf<_CharT, _Traits> _M_sb;
    303   };
    304 
    305 template<typename _CharT, typename _Traits>
    306   inline void
    307   swap(basic_ispanstream<_CharT, _Traits>& __x,
    308        basic_ispanstream<_CharT, _Traits>& __y)
    309   { __x.swap(__y); }
    310 
    311 using ispanstream = basic_ispanstream<char>;
    312 using wispanstream = basic_ispanstream<wchar_t>;
    313 
    314 template<typename _CharT, typename _Traits>
    315   class basic_ospanstream
    316   : public basic_ostream<_CharT, _Traits>
    317   {
    318     using __ostream_type = basic_ostream<_CharT, _Traits>;
    319 
    320   public:
    321     using char_type   = _CharT;
    322     using int_type    = typename _Traits::int_type;
    323     using pos_type    = typename _Traits::pos_type;
    324     using off_type    = typename _Traits::off_type;
    325     using traits_type = _Traits;
    326 
    327     // [ospanstream.ctor], constructors
    328     explicit
    329     basic_ospanstream(std::span<_CharT> __s,
    330 		      ios_base::openmode __which = ios_base::out)
    331     : __ostream_type(std::__addressof(_M_sb)),
    332       _M_sb(__s, __which | ios_base::in)
    333     { }
    334 
    335     basic_ospanstream(const basic_ospanstream&) = delete;
    336 
    337     basic_ospanstream(basic_ospanstream&& __rhs)
    338     : __ostream_type(std::move(__rhs)), _M_sb(std::move(__rhs._M_sb))
    339     {
    340       __ostream_type::set_rdbuf(std::addressof(_M_sb));
    341     }
    342 
    343     // [ospanstream.assign], assignment and swap
    344     basic_ospanstream& operator=(const basic_ospanstream&) = delete;
    345     basic_ospanstream& operator=(basic_ospanstream&& __rhs) = default;
    346 
    347     void
    348     swap(basic_ospanstream& __rhs)
    349     {
    350       __ostream_type::swap(__rhs);
    351       _M_sb.swap(__rhs._M_sb);
    352     }
    353 
    354     // [ospanstream.members], member functions
    355     basic_spanbuf<_CharT, _Traits>*
    356     rdbuf() const noexcept
    357     {
    358       return const_cast<basic_spanbuf<_CharT, _Traits>*>(std::__addressof(_M_sb));
    359     }
    360 
    361     std::span<_CharT>
    362     span() const noexcept
    363     { return _M_sb.span(); }
    364 
    365     void
    366     span(std::span<_CharT> __s) noexcept
    367     { return _M_sb.span(__s); }
    368 
    369   private:
    370     basic_spanbuf<_CharT, _Traits> _M_sb;
    371   };
    372 
    373 template<typename _CharT, typename _Traits>
    374   inline void
    375   swap(basic_ospanstream<_CharT, _Traits>& __x,
    376        basic_ospanstream<_CharT, _Traits>& __y)
    377   { __x.swap(__y); }
    378 
    379 using ospanstream = basic_ospanstream<char>;
    380 using wospanstream = basic_ospanstream<wchar_t>;
    381 
    382 template<typename _CharT, typename _Traits>
    383   class basic_spanstream
    384   : public basic_iostream<_CharT, _Traits>
    385   {
    386     using __iostream_type = basic_iostream<_CharT, _Traits>;
    387 
    388   public:
    389     using char_type   = _CharT;
    390     using int_type    = typename _Traits::int_type;
    391     using pos_type    = typename _Traits::pos_type;
    392     using off_type    = typename _Traits::off_type;
    393     using traits_type = _Traits;
    394 
    395     // [spanstream.ctor], constructors
    396     explicit
    397     basic_spanstream(std::span<_CharT> __s,
    398 		     ios_base::openmode __which = ios_base::out | ios_base::in)
    399     : __iostream_type(std::__addressof(_M_sb)),
    400       _M_sb(__s, __which)
    401     { }
    402 
    403     basic_spanstream(const basic_spanstream&) = delete;
    404 
    405     basic_spanstream(basic_spanstream&& __rhs)
    406     : __iostream_type(std::move(__rhs)), _M_sb(std::move(__rhs._M_sb))
    407     {
    408       __iostream_type::set_rdbuf(std::addressof(_M_sb));
    409     }
    410 
    411     // [spanstream.assign], assignment and swap
    412     basic_spanstream& operator=(const basic_spanstream&) = delete;
    413     basic_spanstream& operator=(basic_spanstream&& __rhs) = default;
    414 
    415     void
    416     swap(basic_spanstream& __rhs)
    417     {
    418       __iostream_type::swap(__rhs);
    419       _M_sb.swap(__rhs._M_sb);
    420     }
    421 
    422     // [spanstream.members], members
    423     basic_spanbuf<_CharT, _Traits>*
    424     rdbuf() const noexcept
    425     {
    426       return const_cast<basic_spanbuf<_CharT, _Traits>*>(std::__addressof(_M_sb));
    427     }
    428 
    429     std::span<_CharT>
    430     span() const noexcept
    431     { return _M_sb.span(); }
    432 
    433     void
    434     span(std::span<_CharT> __s) noexcept
    435     { return _M_sb.span(__s); }
    436 
    437   private:
    438     basic_spanbuf<_CharT, _Traits> _M_sb;
    439   };
    440 
    441 template<typename _CharT, typename _Traits>
    442   inline void
    443   swap(basic_spanstream<_CharT, _Traits>& __x,
    444        basic_spanstream<_CharT, _Traits>& __y)
    445   { __x.swap(__y); }
    446 
    447 using spanstream = basic_spanstream<char>;
    448 using wspanstream = basic_spanstream<wchar_t>;
    449 
    450 _GLIBCXX_END_NAMESPACE_VERSION
    451 } // namespace std
    452 #endif // __cpp_lib_span
    453 #endif // C++23
    454 #endif // _GLIBCXX_SPANSTREAM
    455