xref: /netbsd-src/external/gpl3/gcc/dist/libstdc++-v3/include/std/spanstream (revision 0a3071956a3a9fdebdbf7f338cf2d439b45fc728)
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
42namespace std _GLIBCXX_VISIBILITY(default)
43{
44_GLIBCXX_BEGIN_NAMESPACE_VERSION
45
46#define __cpp_lib_spanstream 202106L
47
48template<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
213template<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
219using spanbuf = basic_spanbuf<char>;
220using wspanbuf = basic_spanbuf<wchar_t>;
221
222template<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
305template<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
311using ispanstream = basic_ispanstream<char>;
312using wispanstream = basic_ispanstream<wchar_t>;
313
314template<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
373template<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
379using ospanstream = basic_ospanstream<char>;
380using wospanstream = basic_ospanstream<wchar_t>;
381
382template<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
441template<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
447using spanstream = basic_spanstream<char>;
448using 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