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