streambuf_iterator.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. // Streambuf iterators
  2. // Copyright (C) 1997-2023 Free Software Foundation, Inc.
  3. //
  4. // This file is part of the GNU ISO C++ Library. This library is free
  5. // software; you can redistribute it and/or modify it under the
  6. // terms of the GNU General Public License as published by the
  7. // Free Software Foundation; either version 3, or (at your option)
  8. // any later version.
  9. // This library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // Under Section 7 of GPL version 3, you are granted additional
  14. // permissions described in the GCC Runtime Library Exception, version
  15. // 3.1, as published by the Free Software Foundation.
  16. // You should have received a copy of the GNU General Public License and
  17. // a copy of the GCC Runtime Library Exception along with this program;
  18. // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
  19. // <http://www.gnu.org/licenses/>.
  20. /** @file bits/streambuf_iterator.h
  21. * This is an internal header file, included by other library headers.
  22. * Do not attempt to use it directly. @headername{iterator}
  23. */
  24. #ifndef _STREAMBUF_ITERATOR_H
  25. #define _STREAMBUF_ITERATOR_H 1
  26. #pragma GCC system_header
  27. #include <streambuf>
  28. #include <bits/stl_iterator_base_types.h>
  29. #include <debug/debug.h>
  30. namespace std _GLIBCXX_VISIBILITY(default)
  31. {
  32. _GLIBCXX_BEGIN_NAMESPACE_VERSION
  33. /**
  34. * @addtogroup iterators
  35. * @{
  36. */
  37. // Ignore warnings about std::iterator.
  38. #pragma GCC diagnostic push
  39. #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
  40. // 24.5.3 Template class istreambuf_iterator
  41. /// Provides input iterator semantics for streambufs.
  42. template<typename _CharT, typename _Traits>
  43. class istreambuf_iterator
  44. : public iterator<input_iterator_tag, _CharT, typename _Traits::off_type,
  45. _CharT*, _CharT>
  46. {
  47. public:
  48. // Types:
  49. ///@{
  50. /// Public typedefs
  51. #if __cplusplus < 201103L
  52. typedef _CharT& reference; // Changed to _CharT by LWG 445
  53. #elif __cplusplus > 201703L
  54. // _GLIBCXX_RESOLVE_LIB_DEFECTS
  55. // 3188. istreambuf_iterator::pointer should not be unspecified
  56. using pointer = void;
  57. #endif
  58. typedef _CharT char_type;
  59. typedef _Traits traits_type;
  60. typedef typename _Traits::int_type int_type;
  61. typedef basic_streambuf<_CharT, _Traits> streambuf_type;
  62. typedef basic_istream<_CharT, _Traits> istream_type;
  63. ///@}
  64. template<typename _CharT2>
  65. friend typename __gnu_cxx::__enable_if<__is_char<_CharT2>::__value,
  66. ostreambuf_iterator<_CharT2> >::__type
  67. copy(istreambuf_iterator<_CharT2>, istreambuf_iterator<_CharT2>,
  68. ostreambuf_iterator<_CharT2>);
  69. template<bool _IsMove, typename _CharT2>
  70. friend typename __gnu_cxx::__enable_if<__is_char<_CharT2>::__value,
  71. _CharT2*>::__type
  72. __copy_move_a2(istreambuf_iterator<_CharT2>,
  73. istreambuf_iterator<_CharT2>, _CharT2*);
  74. template<typename _CharT2, typename _Size>
  75. friend typename __gnu_cxx::__enable_if<__is_char<_CharT2>::__value,
  76. _CharT2*>::__type
  77. __copy_n_a(istreambuf_iterator<_CharT2>, _Size, _CharT2*, bool);
  78. template<typename _CharT2>
  79. friend typename __gnu_cxx::__enable_if<__is_char<_CharT2>::__value,
  80. istreambuf_iterator<_CharT2> >::__type
  81. find(istreambuf_iterator<_CharT2>, istreambuf_iterator<_CharT2>,
  82. const _CharT2&);
  83. template<typename _CharT2, typename _Distance>
  84. friend typename __gnu_cxx::__enable_if<__is_char<_CharT2>::__value,
  85. void>::__type
  86. advance(istreambuf_iterator<_CharT2>&, _Distance);
  87. private:
  88. // 24.5.3 istreambuf_iterator
  89. // p 1
  90. // If the end of stream is reached (streambuf_type::sgetc()
  91. // returns traits_type::eof()), the iterator becomes equal to
  92. // the "end of stream" iterator value.
  93. // NB: This implementation assumes the "end of stream" value
  94. // is EOF, or -1.
  95. mutable streambuf_type* _M_sbuf;
  96. int_type _M_c;
  97. public:
  98. /// Construct end of input stream iterator.
  99. _GLIBCXX_CONSTEXPR istreambuf_iterator() _GLIBCXX_USE_NOEXCEPT
  100. : _M_sbuf(0), _M_c(traits_type::eof()) { }
  101. #if __cplusplus > 201703L && __cpp_lib_concepts
  102. constexpr istreambuf_iterator(default_sentinel_t) noexcept
  103. : istreambuf_iterator() { }
  104. #endif
  105. #if __cplusplus >= 201103L
  106. istreambuf_iterator(const istreambuf_iterator&) noexcept = default;
  107. ~istreambuf_iterator() = default;
  108. #endif
  109. /// Construct start of input stream iterator.
  110. istreambuf_iterator(istream_type& __s) _GLIBCXX_USE_NOEXCEPT
  111. : _M_sbuf(__s.rdbuf()), _M_c(traits_type::eof()) { }
  112. /// Construct start of streambuf iterator.
  113. istreambuf_iterator(streambuf_type* __s) _GLIBCXX_USE_NOEXCEPT
  114. : _M_sbuf(__s), _M_c(traits_type::eof()) { }
  115. #if __cplusplus >= 201103L
  116. istreambuf_iterator&
  117. operator=(const istreambuf_iterator&) noexcept = default;
  118. #endif
  119. /// Return the current character pointed to by iterator. This returns
  120. /// streambuf.sgetc(). It cannot be assigned. NB: The result of
  121. /// operator*() on an end of stream is undefined.
  122. _GLIBCXX_NODISCARD
  123. char_type
  124. operator*() const
  125. {
  126. int_type __c = _M_get();
  127. #ifdef _GLIBCXX_DEBUG_PEDANTIC
  128. // Dereferencing a past-the-end istreambuf_iterator is a
  129. // libstdc++ extension
  130. __glibcxx_requires_cond(!_S_is_eof(__c),
  131. _M_message(__gnu_debug::__msg_deref_istreambuf)
  132. ._M_iterator(*this));
  133. #endif
  134. return traits_type::to_char_type(__c);
  135. }
  136. /// Advance the iterator. Calls streambuf.sbumpc().
  137. istreambuf_iterator&
  138. operator++()
  139. {
  140. __glibcxx_requires_cond(_M_sbuf &&
  141. (!_S_is_eof(_M_c) || !_S_is_eof(_M_sbuf->sgetc())),
  142. _M_message(__gnu_debug::__msg_inc_istreambuf)
  143. ._M_iterator(*this));
  144. _M_sbuf->sbumpc();
  145. _M_c = traits_type::eof();
  146. return *this;
  147. }
  148. /// Advance the iterator. Calls streambuf.sbumpc().
  149. istreambuf_iterator
  150. operator++(int)
  151. {
  152. __glibcxx_requires_cond(_M_sbuf &&
  153. (!_S_is_eof(_M_c) || !_S_is_eof(_M_sbuf->sgetc())),
  154. _M_message(__gnu_debug::__msg_inc_istreambuf)
  155. ._M_iterator(*this));
  156. istreambuf_iterator __old = *this;
  157. __old._M_c = _M_sbuf->sbumpc();
  158. _M_c = traits_type::eof();
  159. return __old;
  160. }
  161. // _GLIBCXX_RESOLVE_LIB_DEFECTS
  162. // 110 istreambuf_iterator::equal not const
  163. // NB: there is also number 111 (NAD) relevant to this function.
  164. /// Return true both iterators are end or both are not end.
  165. _GLIBCXX_NODISCARD
  166. bool
  167. equal(const istreambuf_iterator& __b) const
  168. { return _M_at_eof() == __b._M_at_eof(); }
  169. private:
  170. int_type
  171. _M_get() const
  172. {
  173. int_type __ret = _M_c;
  174. if (_M_sbuf && _S_is_eof(__ret) && _S_is_eof(__ret = _M_sbuf->sgetc()))
  175. _M_sbuf = 0;
  176. return __ret;
  177. }
  178. bool
  179. _M_at_eof() const
  180. { return _S_is_eof(_M_get()); }
  181. static bool
  182. _S_is_eof(int_type __c)
  183. {
  184. const int_type __eof = traits_type::eof();
  185. return traits_type::eq_int_type(__c, __eof);
  186. }
  187. #if __cplusplus > 201703L && __cpp_lib_concepts
  188. [[nodiscard]]
  189. friend bool
  190. operator==(const istreambuf_iterator& __i, default_sentinel_t)
  191. { return __i._M_at_eof(); }
  192. #endif
  193. };
  194. template<typename _CharT, typename _Traits>
  195. _GLIBCXX_NODISCARD
  196. inline bool
  197. operator==(const istreambuf_iterator<_CharT, _Traits>& __a,
  198. const istreambuf_iterator<_CharT, _Traits>& __b)
  199. { return __a.equal(__b); }
  200. #if __cpp_impl_three_way_comparison < 201907L
  201. template<typename _CharT, typename _Traits>
  202. _GLIBCXX_NODISCARD
  203. inline bool
  204. operator!=(const istreambuf_iterator<_CharT, _Traits>& __a,
  205. const istreambuf_iterator<_CharT, _Traits>& __b)
  206. { return !__a.equal(__b); }
  207. #endif
  208. /// Provides output iterator semantics for streambufs.
  209. template<typename _CharT, typename _Traits>
  210. class ostreambuf_iterator
  211. : public iterator<output_iterator_tag, void, void, void, void>
  212. {
  213. public:
  214. // Types:
  215. ///@{
  216. /// Public typedefs
  217. #if __cplusplus > 201703L
  218. using difference_type = ptrdiff_t;
  219. #endif
  220. typedef _CharT char_type;
  221. typedef _Traits traits_type;
  222. typedef basic_streambuf<_CharT, _Traits> streambuf_type;
  223. typedef basic_ostream<_CharT, _Traits> ostream_type;
  224. ///@}
  225. template<typename _CharT2>
  226. friend typename __gnu_cxx::__enable_if<__is_char<_CharT2>::__value,
  227. ostreambuf_iterator<_CharT2> >::__type
  228. copy(istreambuf_iterator<_CharT2>, istreambuf_iterator<_CharT2>,
  229. ostreambuf_iterator<_CharT2>);
  230. private:
  231. streambuf_type* _M_sbuf;
  232. bool _M_failed;
  233. public:
  234. #if __cplusplus > 201703L
  235. constexpr
  236. ostreambuf_iterator() noexcept
  237. : _M_sbuf(nullptr), _M_failed(true) { }
  238. #endif
  239. /// Construct output iterator from ostream.
  240. ostreambuf_iterator(ostream_type& __s) _GLIBCXX_USE_NOEXCEPT
  241. : _M_sbuf(__s.rdbuf()), _M_failed(!_M_sbuf) { }
  242. /// Construct output iterator from streambuf.
  243. ostreambuf_iterator(streambuf_type* __s) _GLIBCXX_USE_NOEXCEPT
  244. : _M_sbuf(__s), _M_failed(!_M_sbuf) { }
  245. /// Write character to streambuf. Calls streambuf.sputc().
  246. ostreambuf_iterator&
  247. operator=(_CharT __c)
  248. {
  249. if (!_M_failed &&
  250. _Traits::eq_int_type(_M_sbuf->sputc(__c), _Traits::eof()))
  251. _M_failed = true;
  252. return *this;
  253. }
  254. /// Return *this.
  255. _GLIBCXX_NODISCARD
  256. ostreambuf_iterator&
  257. operator*()
  258. { return *this; }
  259. /// Return *this.
  260. ostreambuf_iterator&
  261. operator++(int)
  262. { return *this; }
  263. /// Return *this.
  264. ostreambuf_iterator&
  265. operator++()
  266. { return *this; }
  267. /// Return true if previous operator=() failed.
  268. _GLIBCXX_NODISCARD
  269. bool
  270. failed() const _GLIBCXX_USE_NOEXCEPT
  271. { return _M_failed; }
  272. ostreambuf_iterator&
  273. _M_put(const _CharT* __ws, streamsize __len)
  274. {
  275. if (__builtin_expect(!_M_failed, true)
  276. && __builtin_expect(this->_M_sbuf->sputn(__ws, __len) != __len,
  277. false))
  278. _M_failed = true;
  279. return *this;
  280. }
  281. };
  282. #pragma GCC diagnostic pop
  283. // Overloads for streambuf iterators.
  284. template<typename _CharT>
  285. typename __gnu_cxx::__enable_if<__is_char<_CharT>::__value,
  286. ostreambuf_iterator<_CharT> >::__type
  287. copy(istreambuf_iterator<_CharT> __first,
  288. istreambuf_iterator<_CharT> __last,
  289. ostreambuf_iterator<_CharT> __result)
  290. {
  291. if (__first._M_sbuf && !__last._M_sbuf && !__result._M_failed)
  292. {
  293. bool __ineof;
  294. __copy_streambufs_eof(__first._M_sbuf, __result._M_sbuf, __ineof);
  295. if (!__ineof)
  296. __result._M_failed = true;
  297. }
  298. return __result;
  299. }
  300. template<bool _IsMove, typename _CharT>
  301. typename __gnu_cxx::__enable_if<__is_char<_CharT>::__value,
  302. ostreambuf_iterator<_CharT> >::__type
  303. __copy_move_a2(_CharT* __first, _CharT* __last,
  304. ostreambuf_iterator<_CharT> __result)
  305. {
  306. const streamsize __num = __last - __first;
  307. if (__num > 0)
  308. __result._M_put(__first, __num);
  309. return __result;
  310. }
  311. template<bool _IsMove, typename _CharT>
  312. typename __gnu_cxx::__enable_if<__is_char<_CharT>::__value,
  313. ostreambuf_iterator<_CharT> >::__type
  314. __copy_move_a2(const _CharT* __first, const _CharT* __last,
  315. ostreambuf_iterator<_CharT> __result)
  316. {
  317. const streamsize __num = __last - __first;
  318. if (__num > 0)
  319. __result._M_put(__first, __num);
  320. return __result;
  321. }
  322. template<bool _IsMove, typename _CharT>
  323. typename __gnu_cxx::__enable_if<__is_char<_CharT>::__value,
  324. _CharT*>::__type
  325. __copy_move_a2(istreambuf_iterator<_CharT> __first,
  326. istreambuf_iterator<_CharT> __last, _CharT* __result)
  327. {
  328. typedef istreambuf_iterator<_CharT> __is_iterator_type;
  329. typedef typename __is_iterator_type::traits_type traits_type;
  330. typedef typename __is_iterator_type::streambuf_type streambuf_type;
  331. typedef typename traits_type::int_type int_type;
  332. if (__first._M_sbuf && !__last._M_sbuf)
  333. {
  334. streambuf_type* __sb = __first._M_sbuf;
  335. int_type __c = __sb->sgetc();
  336. while (!traits_type::eq_int_type(__c, traits_type::eof()))
  337. {
  338. const streamsize __n = __sb->egptr() - __sb->gptr();
  339. if (__n > 1)
  340. {
  341. traits_type::copy(__result, __sb->gptr(), __n);
  342. __sb->__safe_gbump(__n);
  343. __result += __n;
  344. __c = __sb->underflow();
  345. }
  346. else
  347. {
  348. *__result++ = traits_type::to_char_type(__c);
  349. __c = __sb->snextc();
  350. }
  351. }
  352. }
  353. return __result;
  354. }
  355. template<typename _CharT, typename _Size>
  356. typename __gnu_cxx::__enable_if<__is_char<_CharT>::__value,
  357. _CharT*>::__type
  358. __copy_n_a(istreambuf_iterator<_CharT> __it, _Size __n, _CharT* __result,
  359. bool __strict __attribute__((__unused__)))
  360. {
  361. if (__n == 0)
  362. return __result;
  363. __glibcxx_requires_cond(__it._M_sbuf,
  364. _M_message(__gnu_debug::__msg_inc_istreambuf)
  365. ._M_iterator(__it));
  366. _CharT* __beg = __result;
  367. __result += __it._M_sbuf->sgetn(__beg, __n);
  368. __glibcxx_requires_cond(!__strict || __result - __beg == __n,
  369. _M_message(__gnu_debug::__msg_inc_istreambuf)
  370. ._M_iterator(__it));
  371. return __result;
  372. }
  373. template<typename _CharT>
  374. typename __gnu_cxx::__enable_if<__is_char<_CharT>::__value,
  375. istreambuf_iterator<_CharT> >::__type
  376. find(istreambuf_iterator<_CharT> __first,
  377. istreambuf_iterator<_CharT> __last, const _CharT& __val)
  378. {
  379. typedef istreambuf_iterator<_CharT> __is_iterator_type;
  380. typedef typename __is_iterator_type::traits_type traits_type;
  381. typedef typename __is_iterator_type::streambuf_type streambuf_type;
  382. typedef typename traits_type::int_type int_type;
  383. const int_type __eof = traits_type::eof();
  384. if (__first._M_sbuf && !__last._M_sbuf)
  385. {
  386. const int_type __ival = traits_type::to_int_type(__val);
  387. streambuf_type* __sb = __first._M_sbuf;
  388. int_type __c = __sb->sgetc();
  389. while (!traits_type::eq_int_type(__c, __eof)
  390. && !traits_type::eq_int_type(__c, __ival))
  391. {
  392. streamsize __n = __sb->egptr() - __sb->gptr();
  393. if (__n > 1)
  394. {
  395. const _CharT* __p = traits_type::find(__sb->gptr(),
  396. __n, __val);
  397. if (__p)
  398. __n = __p - __sb->gptr();
  399. __sb->__safe_gbump(__n);
  400. __c = __sb->sgetc();
  401. }
  402. else
  403. __c = __sb->snextc();
  404. }
  405. __first._M_c = __eof;
  406. }
  407. return __first;
  408. }
  409. template<typename _CharT, typename _Distance>
  410. typename __gnu_cxx::__enable_if<__is_char<_CharT>::__value,
  411. void>::__type
  412. advance(istreambuf_iterator<_CharT>& __i, _Distance __n)
  413. {
  414. if (__n == 0)
  415. return;
  416. __glibcxx_assert(__n > 0);
  417. __glibcxx_requires_cond(!__i._M_at_eof(),
  418. _M_message(__gnu_debug::__msg_inc_istreambuf)
  419. ._M_iterator(__i));
  420. typedef istreambuf_iterator<_CharT> __is_iterator_type;
  421. typedef typename __is_iterator_type::traits_type traits_type;
  422. typedef typename __is_iterator_type::streambuf_type streambuf_type;
  423. typedef typename traits_type::int_type int_type;
  424. const int_type __eof = traits_type::eof();
  425. streambuf_type* __sb = __i._M_sbuf;
  426. while (__n > 0)
  427. {
  428. streamsize __size = __sb->egptr() - __sb->gptr();
  429. if (__size > __n)
  430. {
  431. __sb->__safe_gbump(__n);
  432. break;
  433. }
  434. __sb->__safe_gbump(__size);
  435. __n -= __size;
  436. if (traits_type::eq_int_type(__sb->underflow(), __eof))
  437. {
  438. __glibcxx_requires_cond(__n == 0,
  439. _M_message(__gnu_debug::__msg_inc_istreambuf)
  440. ._M_iterator(__i));
  441. break;
  442. }
  443. }
  444. __i._M_c = __eof;
  445. }
  446. /// @} group iterators
  447. _GLIBCXX_END_NAMESPACE_VERSION
  448. } // namespace
  449. #endif