@@ -57,6 +57,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
private:
istream_type* _M_stream;
_Tp _M_value;
+ // This bool becomes false at end-of-stream. It should be sufficient to
+ // check _M_stream != nullptr instead, but historically we did not set
+ // _M_stream to null when reaching the end, so we need to keep this flag.
bool _M_ok;
public:
@@ -66,7 +69,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// Construct start of input stream iterator.
istream_iterator(istream_type& __s)
- : _M_stream(std::__addressof(__s))
+ : _M_stream(std::__addressof(__s)), _M_ok(true)
{ _M_read(); }
istream_iterator(const istream_iterator& __obj)
@@ -76,6 +79,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#if __cplusplus >= 201103L
istream_iterator& operator=(const istream_iterator&) = default;
+ ~istream_iterator() = default;
#endif
const _Tp&
@@ -111,37 +115,38 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return __tmp;
}
+ private:
bool
_M_equal(const istream_iterator& __x) const
- { return (_M_ok == __x._M_ok) && (!_M_ok || _M_stream == __x._M_stream); }
+ {
+ // Ideally this would just return _M_stream == __x._M_stream,
+ // but code compiled with old versions never sets _M_stream to null.
+ return (_M_ok == __x._M_ok) && (!_M_ok || _M_stream == __x._M_stream);
+ }
- private:
void
_M_read()
{
- _M_ok = (_M_stream && *_M_stream) ? true : false;
- if (_M_ok)
- {
- *_M_stream >> _M_value;
- _M_ok = *_M_stream ? true : false;
- }
+ if (_M_stream && !(*_M_stream >> _M_value))
+ {
+ _M_stream = 0;
+ _M_ok = false;
+ }
}
+
+ /// Return true if the iterators refer to the same stream,
+ /// or are both at end-of-stream.
+ friend bool
+ operator==(const istream_iterator& __x, const istream_iterator& __y)
+ { return __x._M_equal(__y); }
+
+ /// Return true if the iterators refer to different streams,
+ /// or if one is at end-of-stream and the other is not.
+ friend bool
+ operator!=(const istream_iterator& __x, const istream_iterator& __y)
+ { return !__x._M_equal(__y); }
};
- /// Return true if x and y are both end or not end, or x and y are the same.
- template<typename _Tp, typename _CharT, typename _Traits, typename _Dist>
- inline bool
- operator==(const istream_iterator<_Tp, _CharT, _Traits, _Dist>& __x,
- const istream_iterator<_Tp, _CharT, _Traits, _Dist>& __y)
- { return __x._M_equal(__y); }
-
- /// Return false if x and y are both end or not end, or x and y are the same.
- template <class _Tp, class _CharT, class _Traits, class _Dist>
- inline bool
- operator!=(const istream_iterator<_Tp, _CharT, _Traits, _Dist>& __x,
- const istream_iterator<_Tp, _CharT, _Traits, _Dist>& __y)
- { return !__x._M_equal(__y); }
-
/**
* @brief Provides output iterator semantics for streams.
*
@@ -171,6 +176,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
const _CharT* _M_string;
public:
+#if __cplusplus > 201703L
+ constexpr ostream_iterator() noexcept
+ : _M_stream(nullptr), _M_string(nullptr) { }
+#endif
+
/// Construct from an ostream.
ostream_iterator(ostream_type& __s)
: _M_stream(std::__addressof(__s)), _M_string(0) {}
@@ -186,7 +196,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
* @param __c CharT delimiter string to insert.
*/
ostream_iterator(ostream_type& __s, const _CharT* __c)
- : _M_stream(&__s), _M_string(__c) { }
+ : _M_stream(std::__addressof(__s)), _M_string(__c) { }
/// Copy constructor.
ostream_iterator(const ostream_iterator& __obj)
@@ -205,7 +215,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_M_message(__gnu_debug::__msg_output_ostream)
._M_iterator(*this));
*_M_stream << __value;
- if (_M_string) *_M_stream << _M_string;
+ if (_M_string)
+ *_M_stream << _M_string;
return *this;
}
new file mode 100644
@@ -0,0 +1,77 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// C++98 24.5.1 Template class istream_iterator
+
+#include <iterator>
+#include <sstream>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+void test01()
+{
+ using namespace std;
+
+ const int N = 6;
+ int arr[N] = { };
+ using __gnu_test::test_container;
+ using __gnu_test::output_iterator_wrapper;
+ test_container<int, output_iterator_wrapper> con(arr, arr+N);
+ output_iterator_wrapper<int> out = con.begin();
+
+ istringstream ss("1 2 3 4 5");
+ std::istream_iterator<int> iter(ss), end;
+ while (iter != end)
+ *out++ = *iter++;
+ VERIFY( iter == end );
+ for (int i = 0; i < N; ++i)
+ VERIFY( arr[i] == (i + 1) % N );
+
+ std::istream_iterator<int> iter2(ss);
+ VERIFY( iter2 == end );
+
+ ss.clear();
+ ss.str("-1 -2 -3");
+ VERIFY( iter == end );
+
+#ifndef _GLIBCXX_DEBUG
+ // This is undefined, so aborts under debug mode.
+ // Without debug mode, it should not extract anything from the stream,
+ // and the iterator should remain at end-of-stream.
+ ++iter;
+ VERIFY( iter == end );
+#endif
+
+ std::istream_iterator<int> iter3(ss);
+ VERIFY( iter3 != end );
+ VERIFY( iter3 != iter );
+ VERIFY( *iter3 == -1 );
+ ++iter3;
+ VERIFY( *iter3 == -2 );
+
+ iter2 = iter3;
+ VERIFY( *iter2 == -2 );
+ ++iter2;
+ VERIFY( *iter2 == -3 );
+ ++iter2;
+ VERIFY( iter2 == end );
+}
+
+int main()
+{
+ test01();
+}
new file mode 100644
@@ -0,0 +1,48 @@
+// Copyright (C) 2016-2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do compile { target c++11 } }
+
+#include <iterator>
+#include <sstream>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ std::ostringstream ss;
+ std::ostream_iterator<int> iter(ss);
+ for (int i = 0; i < 5; ++i)
+ *iter++ = i;
+ VERIFY( ss.str() == "01234" );
+}
+
+void
+test02()
+{
+ std::ostringstream ss;
+ std::ostream_iterator<int> iter(ss, " - ");
+ for (int i = 0; i < 5; ++i)
+ *iter++ = i;
+ VERIFY( ss.str() == "0 - 1 - 2 - 3 - 4 - " );
+}
+
+int main()
+{
+ test01();
+ test02();
+}
@@ -33,4 +33,5 @@ test01()
{
std::basic_ostream<char, adl::traits> os(nullptr);
std::ostream_iterator<int, char, adl::traits> oi(os);
+ std::ostream_iterator<int, char, adl::traits> oi2(os, "");
}
new file mode 100644
@@ -0,0 +1,24 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <iterator>
+
+constexpr std::ostream_iterator<int> iter1;
+constexpr std::ostream_iterator<int> iter2{};