Line data Source code
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 :
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 17 : _GLIBCXX_CONSTEXPR istreambuf_iterator() _GLIBCXX_USE_NOEXCEPT
115 17 : : _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 17 : istreambuf_iterator(istream_type& __s) _GLIBCXX_USE_NOEXCEPT
130 17 : : _M_sbuf(__s.rdbuf()), _M_c(traits_type::eof()) { }
131 :
132 : /// Construct start of streambuf iterator.
133 0 : istreambuf_iterator(streambuf_type* __s) _GLIBCXX_USE_NOEXCEPT
134 0 : : _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 5833 : operator*() const
146 : {
147 5833 : 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 11666 : return traits_type::to_char_type(__c);
157 : }
158 :
159 : /// Advance the iterator. Calls streambuf.sbumpc().
160 : istreambuf_iterator&
161 5833 : 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 5833 : _M_sbuf->sbumpc();
169 5833 : _M_c = traits_type::eof();
170 5833 : 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 5867 : equal(const istreambuf_iterator& __b) const
194 5867 : { return _M_at_eof() == __b._M_at_eof(); }
195 :
196 : private:
197 : int_type
198 17567 : _M_get() const
199 : {
200 17567 : int_type __ret = _M_c;
201 17567 : if (_M_sbuf && _S_is_eof(__ret) && _S_is_eof(__ret = _M_sbuf->sgetc()))
202 17 : _M_sbuf = 0;
203 17567 : return __ret;
204 : }
205 :
206 : bool
207 11734 : _M_at_eof() const
208 11734 : { return _S_is_eof(_M_get()); }
209 :
210 : static bool
211 35112 : _S_is_eof(int_type __c)
212 : {
213 35112 : const int_type __eof = traits_type::eof();
214 35112 : 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 5867 : operator!=(const istreambuf_iterator<_CharT, _Traits>& __a,
233 : const istreambuf_iterator<_CharT, _Traits>& __b)
234 5867 : { 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 0 : ostreambuf_iterator(ostream_type& __s) _GLIBCXX_USE_NOEXCEPT
274 0 : : _M_sbuf(__s.rdbuf()), _M_failed(!_M_sbuf) { }
275 :
276 : /// Construct output iterator from streambuf.
277 9 : ostreambuf_iterator(streambuf_type* __s) _GLIBCXX_USE_NOEXCEPT
278 9 : : _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 9 : failed() const _GLIBCXX_USE_NOEXCEPT
308 9 : { 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
|