libstdc++
streambuf_iterator.h
Go to the documentation of this file.
1 // Streambuf iterators
2 
3 // Copyright (C) 1997-2025 Free Software Foundation, Inc.
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 bits/streambuf_iterator.h
26  * This is an internal header file, included by other library headers.
27  * Do not attempt to use it directly. @headername{iterator}
28  */
29 
30 #ifndef _STREAMBUF_ITERATOR_H
31 #define _STREAMBUF_ITERATOR_H 1
32 
33 #ifdef _GLIBCXX_SYSHDR
34 #pragma GCC system_header
35 #endif
36 
37 #include <streambuf>
39 #include <debug/debug.h>
40 
41 namespace std _GLIBCXX_VISIBILITY(default)
42 {
43 _GLIBCXX_BEGIN_NAMESPACE_VERSION
44 
45  /**
46  * @addtogroup iterators
47  * @{
48  */
49 
50 // Ignore warnings about std::iterator.
51 #pragma GCC diagnostic push
52 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
53  // 24.5.3 Template class istreambuf_iterator
54  /// Provides input iterator semantics for streambufs.
55  template<typename _CharT, typename _Traits>
57  : public iterator<input_iterator_tag, _CharT, typename _Traits::off_type,
58  _CharT*, _CharT>
59  {
60  public:
61  // Types:
62  ///@{
63  /// Public typedefs
64 #if __cplusplus < 201103L
65  typedef _CharT& reference; // Changed to _CharT by LWG 445
66 #elif __cplusplus > 201703L
67  // _GLIBCXX_RESOLVE_LIB_DEFECTS
68  // 3188. istreambuf_iterator::pointer should not be unspecified
69  using pointer = void;
70 #endif
71 
72  typedef _CharT char_type;
73  typedef _Traits traits_type;
74  typedef typename _Traits::int_type int_type;
77  ///@}
78 
79  template<typename _CharT2>
80  friend typename __gnu_cxx::__enable_if<__is_char<_CharT2>::__value,
84 
85  template<bool _IsMove, typename _CharT2>
86  friend typename __gnu_cxx::__enable_if<__is_char<_CharT2>::__value,
87  _CharT2*>::__type
88  __copy_move_a2(istreambuf_iterator<_CharT2>,
90 
91  template<typename _CharT2, typename _Size>
92  friend typename __gnu_cxx::__enable_if<__is_char<_CharT2>::__value,
93  _CharT2*>::__type
94  __copy_n_a(istreambuf_iterator<_CharT2>, _Size, _CharT2*, bool);
95 
96  template<typename _CharT2>
97  friend typename __gnu_cxx::__enable_if<__is_char<_CharT2>::__value,
100  const _CharT2&);
101 
102  template<typename _CharT2, typename _Distance>
103  friend typename __gnu_cxx::__enable_if<__is_char<_CharT2>::__value,
104  void>::__type
105  advance(istreambuf_iterator<_CharT2>&, _Distance);
106 
107  private:
108  // 24.5.3 istreambuf_iterator
109  // p 1
110  // If the end of stream is reached (streambuf_type::sgetc()
111  // returns traits_type::eof()), the iterator becomes equal to
112  // the "end of stream" iterator value.
113  // NB: This implementation assumes the "end of stream" value
114  // is EOF, or -1.
115  mutable streambuf_type* _M_sbuf;
116  int_type _M_c;
117 
118  public:
119  /// Construct end of input stream iterator.
120  _GLIBCXX_CONSTEXPR istreambuf_iterator() _GLIBCXX_USE_NOEXCEPT
121  : _M_sbuf(0), _M_c(traits_type::eof()) { }
122 
123 #if __cplusplus > 201703L && __cpp_lib_concepts
124  constexpr istreambuf_iterator(default_sentinel_t) noexcept
125  : istreambuf_iterator() { }
126 #endif
127 
128 #if __cplusplus >= 201103L
129  istreambuf_iterator(const istreambuf_iterator&) noexcept = default;
130 
131  ~istreambuf_iterator() = default;
132 #endif
133 
134  /// Construct start of input stream iterator.
135  istreambuf_iterator(istream_type& __s) _GLIBCXX_USE_NOEXCEPT
136  : _M_sbuf(__s.rdbuf()), _M_c(traits_type::eof()) { }
137 
138  /// Construct start of streambuf iterator.
139  istreambuf_iterator(streambuf_type* __s) _GLIBCXX_USE_NOEXCEPT
140  : _M_sbuf(__s), _M_c(traits_type::eof()) { }
141 
142 #if __cplusplus >= 201103L
144  operator=(const istreambuf_iterator&) noexcept = default;
145 #endif
146 
147  /// Return the current character pointed to by iterator. This returns
148  /// streambuf.sgetc(). It cannot be assigned. NB: The result of
149  /// operator*() on an end of stream is undefined.
150  _GLIBCXX_NODISCARD
151  char_type
152  operator*() const
153  {
154  int_type __c = _M_get();
155 
156 #ifdef _GLIBCXX_DEBUG_PEDANTIC
157  // Dereferencing a past-the-end istreambuf_iterator is a
158  // libstdc++ extension
159  __glibcxx_requires_cond(!_S_is_eof(__c),
160  _M_message(__gnu_debug::__msg_deref_istreambuf)
161  ._M_iterator(*this));
162 #endif
163  return traits_type::to_char_type(__c);
164  }
165 
166  /// Advance the iterator. Calls streambuf.sbumpc().
169  {
170  __glibcxx_requires_cond(_M_sbuf &&
171  (!_S_is_eof(_M_c) || !_S_is_eof(_M_sbuf->sgetc())),
172  _M_message(__gnu_debug::__msg_inc_istreambuf)
173  ._M_iterator(*this));
174 
175  _M_sbuf->sbumpc();
176  _M_c = traits_type::eof();
177  return *this;
178  }
179 
180  /// Advance the iterator. Calls streambuf.sbumpc().
183  {
184  __glibcxx_requires_cond(_M_sbuf &&
185  (!_S_is_eof(_M_c) || !_S_is_eof(_M_sbuf->sgetc())),
186  _M_message(__gnu_debug::__msg_inc_istreambuf)
187  ._M_iterator(*this));
188 
189  istreambuf_iterator __old = *this;
190  __old._M_c = _M_sbuf->sbumpc();
191  _M_c = traits_type::eof();
192  return __old;
193  }
194 
195  // _GLIBCXX_RESOLVE_LIB_DEFECTS
196  // 110 istreambuf_iterator::equal not const
197  // NB: there is also number 111 (NAD) relevant to this function.
198  /// Return true both iterators are end or both are not end.
199  _GLIBCXX_NODISCARD
200  bool
201  equal(const istreambuf_iterator& __b) const
202  { return _M_at_eof() == __b._M_at_eof(); }
203 
204  private:
205  int_type
206  _M_get() const
207  {
208  int_type __ret = _M_c;
209  if (_M_sbuf && _S_is_eof(__ret) && _S_is_eof(__ret = _M_sbuf->sgetc()))
210  _M_sbuf = 0;
211  return __ret;
212  }
213 
214  bool
215  _M_at_eof() const
216  { return _S_is_eof(_M_get()); }
217 
218  static bool
219  _S_is_eof(int_type __c)
220  {
221  const int_type __eof = traits_type::eof();
222  return traits_type::eq_int_type(__c, __eof);
223  }
224 
225 #if __cplusplus > 201703L && __cpp_lib_concepts
226  [[nodiscard]]
227  friend bool
228  operator==(const istreambuf_iterator& __i, default_sentinel_t)
229  { return __i._M_at_eof(); }
230 #endif
231  };
232 
233  template<typename _CharT, typename _Traits>
234  _GLIBCXX_NODISCARD
235  inline bool
236  operator==(const istreambuf_iterator<_CharT, _Traits>& __a,
237  const istreambuf_iterator<_CharT, _Traits>& __b)
238  { return __a.equal(__b); }
239 
240 #if __cpp_impl_three_way_comparison < 201907L
241  template<typename _CharT, typename _Traits>
242  _GLIBCXX_NODISCARD
243  inline bool
244  operator!=(const istreambuf_iterator<_CharT, _Traits>& __a,
245  const istreambuf_iterator<_CharT, _Traits>& __b)
246  { return !__a.equal(__b); }
247 #endif
248 
249  /// Provides output iterator semantics for streambufs.
250  template<typename _CharT, typename _Traits>
252  : public iterator<output_iterator_tag, void, void, void, void>
253  {
254  public:
255  // Types:
256  ///@{
257  /// Public typedefs
258 #if __cplusplus > 201703L
259  using difference_type = ptrdiff_t;
260 #endif
261  typedef _CharT char_type;
262  typedef _Traits traits_type;
265  ///@}
266 
267  template<typename _CharT2>
268  friend typename __gnu_cxx::__enable_if<__is_char<_CharT2>::__value,
272 
273  private:
274  streambuf_type* _M_sbuf;
275  bool _M_failed;
276 
277  public:
278 
279 #if __cplusplus > 201703L
280  constexpr
281  ostreambuf_iterator() noexcept
282  : _M_sbuf(nullptr), _M_failed(true) { }
283 #endif
284 
285  /// Construct output iterator from ostream.
286  ostreambuf_iterator(ostream_type& __s) _GLIBCXX_USE_NOEXCEPT
287  : _M_sbuf(__s.rdbuf()), _M_failed(!_M_sbuf) { }
288 
289  /// Construct output iterator from streambuf.
290  ostreambuf_iterator(streambuf_type* __s) _GLIBCXX_USE_NOEXCEPT
291  : _M_sbuf(__s), _M_failed(!_M_sbuf) { }
292 
293  /// Write character to streambuf. Calls streambuf.sputc().
295  operator=(_CharT __c)
296  {
297  if (!_M_failed &&
298  _Traits::eq_int_type(_M_sbuf->sputc(__c), _Traits::eof()))
299  _M_failed = true;
300  return *this;
301  }
302 
303  /// Return *this.
304  _GLIBCXX_NODISCARD
307  { return *this; }
308 
309  /// Return *this.
312  { return *this; }
313 
314  /// Return *this.
317  { return *this; }
318 
319  /// Return true if previous operator=() failed.
320  _GLIBCXX_NODISCARD
321  bool
322  failed() const _GLIBCXX_USE_NOEXCEPT
323  { return _M_failed; }
324 
326  _M_put(const _CharT* __ws, streamsize __len)
327  {
328  if (__builtin_expect(!_M_failed, true)
329  && __builtin_expect(this->_M_sbuf->sputn(__ws, __len) != __len,
330  false))
331  _M_failed = true;
332  return *this;
333  }
334  };
335 #pragma GCC diagnostic pop
336 
337  // Overloads for streambuf iterators.
338  template<typename _CharT>
339  typename __gnu_cxx::__enable_if<__is_char<_CharT>::__value,
340  ostreambuf_iterator<_CharT> >::__type
341  copy(istreambuf_iterator<_CharT> __first,
342  istreambuf_iterator<_CharT> __last,
343  ostreambuf_iterator<_CharT> __result)
344  {
345  if (__first._M_sbuf && !__last._M_sbuf && !__result._M_failed)
346  {
347  bool __ineof;
348  __copy_streambufs_eof(__first._M_sbuf, __result._M_sbuf, __ineof);
349  if (!__ineof)
350  __result._M_failed = true;
351  }
352  return __result;
353  }
354 
355  template<bool _IsMove, typename _CharT>
356  typename __gnu_cxx::__enable_if<__is_char<_CharT>::__value,
357  ostreambuf_iterator<_CharT> >::__type
358  __copy_move_a2(_CharT* __first, _CharT* __last,
359  ostreambuf_iterator<_CharT> __result)
360  {
361  const streamsize __num = __last - __first;
362  if (__num > 0)
363  __result._M_put(__first, __num);
364  return __result;
365  }
366 
367  template<bool _IsMove, typename _CharT>
368  typename __gnu_cxx::__enable_if<__is_char<_CharT>::__value,
369  ostreambuf_iterator<_CharT> >::__type
370  __copy_move_a2(const _CharT* __first, const _CharT* __last,
371  ostreambuf_iterator<_CharT> __result)
372  {
373  const streamsize __num = __last - __first;
374  if (__num > 0)
375  __result._M_put(__first, __num);
376  return __result;
377  }
378 
379  template<bool _IsMove, typename _CharT>
380  typename __gnu_cxx::__enable_if<__is_char<_CharT>::__value,
381  _CharT*>::__type
382  __copy_move_a2(istreambuf_iterator<_CharT> __first,
383  istreambuf_iterator<_CharT> __last, _CharT* __result)
384  {
385  typedef istreambuf_iterator<_CharT> __is_iterator_type;
386  typedef typename __is_iterator_type::traits_type traits_type;
387  typedef typename __is_iterator_type::streambuf_type streambuf_type;
388  typedef typename traits_type::int_type int_type;
389 
390  if (__first._M_sbuf && !__last._M_sbuf)
391  {
392  streambuf_type* __sb = __first._M_sbuf;
393  int_type __c = __sb->sgetc();
394  while (!traits_type::eq_int_type(__c, traits_type::eof()))
395  {
396  const streamsize __n = __sb->egptr() - __sb->gptr();
397  if (__n > 1)
398  {
399  traits_type::copy(__result, __sb->gptr(), __n);
400  __sb->__safe_gbump(__n);
401  __result += __n;
402  __c = __sb->underflow();
403  }
404  else
405  {
406  *__result++ = traits_type::to_char_type(__c);
407  __c = __sb->snextc();
408  }
409  }
410  }
411  return __result;
412  }
413 
414  template<typename _CharT, typename _Size>
415  typename __gnu_cxx::__enable_if<__is_char<_CharT>::__value,
416  _CharT*>::__type
417  __copy_n_a(istreambuf_iterator<_CharT> __it, _Size __n, _CharT* __result,
418  bool __strict __attribute__((__unused__)))
419  {
420  if (__n == 0)
421  return __result;
422 
423  __glibcxx_requires_cond(__it._M_sbuf,
424  _M_message(__gnu_debug::__msg_inc_istreambuf)
425  ._M_iterator(__it));
426  _CharT* __beg = __result;
427  __result += __it._M_sbuf->sgetn(__beg, __n);
428  __glibcxx_requires_cond(!__strict || __result - __beg == __n,
429  _M_message(__gnu_debug::__msg_inc_istreambuf)
430  ._M_iterator(__it));
431  return __result;
432  }
433 
434  template<typename _CharT>
435  typename __gnu_cxx::__enable_if<__is_char<_CharT>::__value,
436  istreambuf_iterator<_CharT> >::__type
437  find(istreambuf_iterator<_CharT> __first,
438  istreambuf_iterator<_CharT> __last, const _CharT& __val)
439  {
440  typedef istreambuf_iterator<_CharT> __is_iterator_type;
441  typedef typename __is_iterator_type::traits_type traits_type;
442  typedef typename __is_iterator_type::streambuf_type streambuf_type;
443  typedef typename traits_type::int_type int_type;
444  const int_type __eof = traits_type::eof();
445 
446  if (__first._M_sbuf && !__last._M_sbuf)
447  {
448  const int_type __ival = traits_type::to_int_type(__val);
449  streambuf_type* __sb = __first._M_sbuf;
450  int_type __c = __sb->sgetc();
451  while (!traits_type::eq_int_type(__c, __eof)
452  && !traits_type::eq_int_type(__c, __ival))
453  {
454  streamsize __n = __sb->egptr() - __sb->gptr();
455  if (__n > 1)
456  {
457  const _CharT* __p = traits_type::find(__sb->gptr(),
458  __n, __val);
459  if (__p)
460  __n = __p - __sb->gptr();
461  __sb->__safe_gbump(__n);
462  __c = __sb->sgetc();
463  }
464  else
465  __c = __sb->snextc();
466  }
467 
468  __first._M_c = __eof;
469  }
470 
471  return __first;
472  }
473 
474  template<typename _CharT, typename _Distance>
475  typename __gnu_cxx::__enable_if<__is_char<_CharT>::__value,
476  void>::__type
477  advance(istreambuf_iterator<_CharT>& __i, _Distance __n)
478  {
479  if (__n == 0)
480  return;
481 
482  __glibcxx_assert(__n > 0);
483  __glibcxx_requires_cond(!__i._M_at_eof(),
484  _M_message(__gnu_debug::__msg_inc_istreambuf)
485  ._M_iterator(__i));
486 
487  typedef istreambuf_iterator<_CharT> __is_iterator_type;
488  typedef typename __is_iterator_type::traits_type traits_type;
489  typedef typename __is_iterator_type::streambuf_type streambuf_type;
490  typedef typename traits_type::int_type int_type;
491  const int_type __eof = traits_type::eof();
492 
493  streambuf_type* __sb = __i._M_sbuf;
494  while (__n > 0)
495  {
496  streamsize __size = __sb->egptr() - __sb->gptr();
497  if (__size > __n)
498  {
499  __sb->__safe_gbump(__n);
500  break;
501  }
502 
503  __sb->__safe_gbump(__size);
504  __n -= __size;
505  if (traits_type::eq_int_type(__sb->underflow(), __eof))
506  {
507  __glibcxx_requires_cond(__n == 0,
508  _M_message(__gnu_debug::__msg_inc_istreambuf)
509  ._M_iterator(__i));
510  break;
511  }
512  }
513 
514  __i._M_c = __eof;
515  }
516 
517 /// @} group iterators
518 
519 _GLIBCXX_END_NAMESPACE_VERSION
520 } // namespace
521 
522 #endif
ISO C++ entities toplevel namespace is std.
ptrdiff_t streamsize
Integral type for I/O operation counts and buffer sizes.
Definition: postypes.h:73
constexpr void advance(_InputIterator &__i, _Distance __n)
A generalization of pointer arithmetic.
The actual work of input and output (interface).
Definition: streambuf:127
streamsize sputn(const char_type *__s, streamsize __n)
Entry point for all single-character output functions.
Definition: streambuf:459
int_type sbumpc()
Getting the next character.
Definition: streambuf:325
int_type sgetc()
Getting the next character.
Definition: streambuf:347
int_type sputc(char_type __c)
Entry point for all single-character output functions.
Definition: streambuf:433
Template class basic_istream.
Definition: istream:63
Template class basic_ostream.
Definition: ostream.h:67
Provides input iterator semantics for streambufs.
basic_streambuf< _CharT, _Traits > streambuf_type
Public typedefs.
void pointer
Public typedefs.
istreambuf_iterator & operator++()
Advance the iterator. Calls streambuf.sbumpc().
constexpr istreambuf_iterator() noexcept
Construct end of input stream iterator.
basic_istream< _CharT, _Traits > istream_type
Public typedefs.
char_type operator*() const
Return the current character pointed to by iterator. This returns streambuf.sgetc()....
bool equal(const istreambuf_iterator &__b) const
Return true both iterators are end or both are not end.
_Traits traits_type
Public typedefs.
istreambuf_iterator(istream_type &__s) noexcept
Construct start of input stream iterator.
istreambuf_iterator operator++(int)
Advance the iterator. Calls streambuf.sbumpc().
_CharT char_type
Public typedefs.
istreambuf_iterator(streambuf_type *__s) noexcept
Construct start of streambuf iterator.
_Traits::int_type int_type
Public typedefs.
Provides output iterator semantics for streambufs.
ostreambuf_iterator & operator++()
Return *this.
ostreambuf_iterator & operator*()
Return *this.
ptrdiff_t difference_type
Public typedefs.
bool failed() const noexcept
Return true if previous operator=() failed.
_Traits traits_type
Public typedefs.
basic_ostream< _CharT, _Traits > ostream_type
Public typedefs.
basic_streambuf< _CharT, _Traits > streambuf_type
Public typedefs.
ostreambuf_iterator & operator=(_CharT __c)
Write character to streambuf. Calls streambuf.sputc().
ostreambuf_iterator(ostream_type &__s) noexcept
Construct output iterator from ostream.
ostreambuf_iterator & operator++(int)
Return *this.
_CharT char_type
Public typedefs.
ostreambuf_iterator(streambuf_type *__s) noexcept
Construct output iterator from streambuf.
Common iterator class.