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