diff --git a/libcxx/docs/Status/RangesPaper.csv b/libcxx/docs/Status/RangesPaper.csv --- a/libcxx/docs/Status/RangesPaper.csv +++ b/libcxx/docs/Status/RangesPaper.csv @@ -91,11 +91,11 @@ | [iterator.cust.move] | [default.sentinels]",Zoe Carver,✅ `[stream.iterators] `_," -| Updates to istream_iterator -| `Updates to ostream_iterator `_ -| Updates to istreambuf_iterator -| `Updates to ostreambuf_iterator `_ -",[default.sentinels],Various,In progress +| `Updates to istream_iterator `_ +| `Updates to ostream_iterator `_ +| `Updates to istreambuf_iterator `_ +| `Updates to ostreambuf_iterator `_ +",[default.sentinels],Various,✅ `[range.access] `_,"| `ranges::begin `_ | `ranges::end `_ | `range::cbegin `_ diff --git a/libcxx/include/__iterator/istream_iterator.h b/libcxx/include/__iterator/istream_iterator.h --- a/libcxx/include/__iterator/istream_iterator.h +++ b/libcxx/include/__iterator/istream_iterator.h @@ -11,6 +11,7 @@ #define _LIBCPP___ITERATOR_ISTREAM_ITERATOR_H #include <__config> +#include <__iterator/default_sentinel.h> #include <__iterator/iterator.h> #include <__iterator/iterator_traits.h> #include <__memory/addressof.h> @@ -45,6 +46,9 @@ _Tp __value_; public: _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR istream_iterator() : __in_stream_(nullptr), __value_() {} +#if !defined(_LIBCPP_HAS_NO_CONCEPTS) + _LIBCPP_HIDE_FROM_ABI constexpr istream_iterator(default_sentinel_t) : istream_iterator() {} +#endif // !defined(_LIBCPP_HAS_NO_CONCEPTS) _LIBCPP_INLINE_VISIBILITY istream_iterator(istream_type& __s) : __in_stream_(_VSTD::addressof(__s)) { if (!(*__in_stream_ >> __value_)) @@ -67,6 +71,12 @@ bool operator==(const istream_iterator<_Up, _CharU, _TraitsU, _DistanceU>& __x, const istream_iterator<_Up, _CharU, _TraitsU, _DistanceU>& __y); + +#if !defined(_LIBCPP_HAS_NO_CONCEPTS) + friend _LIBCPP_HIDE_FROM_ABI bool operator==(const istream_iterator& __i, default_sentinel_t) { + return !__i.__in_stream_; + } +#endif // !defined(_LIBCPP_HAS_NO_CONCEPTS) }; template diff --git a/libcxx/include/__iterator/istreambuf_iterator.h b/libcxx/include/__iterator/istreambuf_iterator.h --- a/libcxx/include/__iterator/istreambuf_iterator.h +++ b/libcxx/include/__iterator/istreambuf_iterator.h @@ -11,6 +11,7 @@ #define _LIBCPP___ITERATOR_ISTREAMBUF_ITERATOR_H #include <__config> +#include <__iterator/default_sentinel.h> #include <__iterator/iterator.h> #include <__iterator/iterator_traits.h> #include // for forward declaration of basic_streambuf @@ -65,6 +66,10 @@ } public: _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR istreambuf_iterator() _NOEXCEPT : __sbuf_(nullptr) {} +#if !defined(_LIBCPP_HAS_NO_CONCEPTS) + _LIBCPP_INLINE_VISIBILITY constexpr istreambuf_iterator(default_sentinel_t) _NOEXCEPT + : istreambuf_iterator() {} +#endif // !defined(_LIBCPP_HAS_NO_CONCEPTS) _LIBCPP_INLINE_VISIBILITY istreambuf_iterator(istream_type& __s) _NOEXCEPT : __sbuf_(__s.rdbuf()) {} _LIBCPP_INLINE_VISIBILITY istreambuf_iterator(streambuf_type* __s) _NOEXCEPT @@ -86,6 +91,12 @@ _LIBCPP_INLINE_VISIBILITY bool equal(const istreambuf_iterator& __b) const {return __test_for_eof() == __b.__test_for_eof();} + +#if !defined(_LIBCPP_HAS_NO_CONCEPTS) + friend _LIBCPP_HIDE_FROM_ABI bool operator==(const istreambuf_iterator& __i, default_sentinel_t __s) { + return __i.equal(__s); + } +#endif // !defined(_LIBCPP_HAS_NO_CONCEPTS) }; template diff --git a/libcxx/include/iterator b/libcxx/include/iterator --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -448,7 +448,8 @@ typedef traits traits_type; typedef basic_istream istream_type; - constexpr istream_iterator(); + istream_iterator(); // constexpr since C++11 + constexpr istream_iterator(default_sentinel_t); // since C++20 istream_iterator(istream_type& s); istream_iterator(const istream_iterator& x); ~istream_iterator(); @@ -457,6 +458,7 @@ const T* operator->() const; istream_iterator& operator++(); istream_iterator operator++(int); + friend bool operator==(const istream_iterator& i, default_sentinel_t); // since C++20 }; template @@ -510,7 +512,9 @@ typedef basic_streambuf streambuf_type; typedef basic_istream istream_type; - istreambuf_iterator() noexcept; + istreambuf_iterator() throw; // until C++11 + constexpr istreambuf_iterator() noexcept; // since C++11 + constexpr istreambuf_iterator(default_sentinel_t) noexcept; // since C++20 istreambuf_iterator(istream_type& s) noexcept; istreambuf_iterator(streambuf_type* s) noexcept; istreambuf_iterator(a-private-type) noexcept; @@ -521,6 +525,7 @@ a-private-type operator++(int); bool equal(const istreambuf_iterator& b) const; + friend bool operator==(const istreambuf_iterator& i, default_sentinel_t s); // since C++20 }; template diff --git a/libcxx/test/std/iterators/stream.iterators/istream.iterator/istream.iterator.cons/default.pass.cpp b/libcxx/test/std/iterators/stream.iterators/istream.iterator/istream.iterator.cons/default.pass.cpp --- a/libcxx/test/std/iterators/stream.iterators/istream.iterator/istream.iterator.cons/default.pass.cpp +++ b/libcxx/test/std/iterators/stream.iterators/istream.iterator/istream.iterator.cons/default.pass.cpp @@ -10,9 +10,11 @@ // class istream_iterator -// constexpr istream_iterator(); +// istream_iterator(); // constexpr since C++11 // C++17 says: If is_trivially_default_constructible_v is true, then this // constructor is a constexpr constructor. +// +// constexpr istream_iterator(default_sentinel_t); // since C++20 #include #include @@ -50,6 +52,21 @@ #endif } +#if TEST_STD_VER > 17 + { + typedef std::istream_iterator T; + + T it1(std::default_sentinel); + assert(it1 == T()); + + T it2 = std::default_sentinel; + assert(it2 == it1); + + constexpr T it3(std::default_sentinel); + (void)it3; + } +#endif + #if TEST_STD_VER > 14 test_trivial()(); test_trivial()(); diff --git a/libcxx/test/std/iterators/stream.iterators/istream.iterator/istream.iterator.ops/equal.pass.cpp b/libcxx/test/std/iterators/stream.iterators/istream.iterator/istream.iterator.ops/equal.pass.cpp --- a/libcxx/test/std/iterators/stream.iterators/istream.iterator/istream.iterator.ops/equal.pass.cpp +++ b/libcxx/test/std/iterators/stream.iterators/istream.iterator/istream.iterator.ops/equal.pass.cpp @@ -24,8 +24,8 @@ #include "test_macros.h" -int main(int, char**) -{ +int main(int, char**) { + { std::istringstream inf1(" 1 23"); std::istringstream inf2(" 1 23"); std::istream_iterator i1(inf1); @@ -53,6 +53,32 @@ assert(std::operator==(i1, i2)); assert(std::operator!=(i1, i3)); + } + +#if TEST_STD_VER > 17 + { + std::istream_iterator i1; + std::istream_iterator i2(std::default_sentinel); + assert(i1 == i2); + + assert(i1 == std::default_sentinel); + assert(i2 == std::default_sentinel); + assert(std::default_sentinel == i1); + assert(std::default_sentinel == i2); + assert(!(i1 != std::default_sentinel)); + assert(!(i2 != std::default_sentinel)); + assert(!(std::default_sentinel != i1)); + assert(!(std::default_sentinel != i2)); + + std::istringstream stream(" 1 23"); + std::istream_iterator i3(stream); + + assert(!(i3 == std::default_sentinel)); + assert(!(std::default_sentinel == i3)); + assert(i3 != std::default_sentinel); + assert(std::default_sentinel != i3); + } +#endif return 0; } diff --git a/libcxx/test/std/iterators/stream.iterators/istreambuf.iterator/istreambuf.iterator.cons/default.pass.cpp b/libcxx/test/std/iterators/stream.iterators/istreambuf.iterator/istreambuf.iterator.cons/default.pass.cpp --- a/libcxx/test/std/iterators/stream.iterators/istreambuf.iterator/istreambuf.iterator.cons/default.pass.cpp +++ b/libcxx/test/std/iterators/stream.iterators/istreambuf.iterator/istreambuf.iterator.cons/default.pass.cpp @@ -10,7 +10,9 @@ // istreambuf_iterator // -// istreambuf_iterator() throw(); +// istreambuf_iterator() throw; // until C++11 +// constexpr istreambuf_iterator() noexcept; // since C++11 +// constexpr istreambuf_iterator(default_sentinel_t) noexcept; // since C++20 // // All specializations of istreambuf_iterator shall have a trivial copy constructor, // a constexpr default constructor and a trivial destructor. @@ -21,28 +23,48 @@ #include "test_macros.h" -int main(int, char**) -{ - { - typedef std::istreambuf_iterator T; - T it; - assert(it == T()); +int main(int, char**) { + { + typedef std::istreambuf_iterator T; + T it; + assert(it == T()); #if TEST_STD_VER >= 11 - constexpr T it2; - (void)it2; + constexpr T it2; + (void)it2; +#endif + + ASSERT_NOEXCEPT(T()); + } + +#if TEST_STD_VER > 17 + { + typedef std::istreambuf_iterator T; + + T it1(std::default_sentinel); + assert(it1 == T()); + + T it2 = std::default_sentinel; + assert(it2 == it1); + + constexpr T it3(std::default_sentinel); + (void)it3; + + ASSERT_NOEXCEPT(T(std::default_sentinel)); + } #endif - } #ifndef TEST_HAS_NO_WIDE_CHARACTERS - { - typedef std::istreambuf_iterator T; - T it; - assert(it == T()); + { + typedef std::istreambuf_iterator T; + T it; + assert(it == T()); #if TEST_STD_VER >= 11 - constexpr T it2; - (void)it2; + constexpr T it2; + (void)it2; #endif - } + + ASSERT_NOEXCEPT(T()); + } #endif // TEST_HAS_NO_WIDE_CHARACTERS return 0; diff --git a/libcxx/test/std/iterators/stream.iterators/istreambuf.iterator/istreambuf.iterator_op!=/not_equal.pass.cpp b/libcxx/test/std/iterators/stream.iterators/istreambuf.iterator/istreambuf.iterator_op!=/not_equal.pass.cpp --- a/libcxx/test/std/iterators/stream.iterators/istreambuf.iterator/istreambuf.iterator_op!=/not_equal.pass.cpp +++ b/libcxx/test/std/iterators/stream.iterators/istreambuf.iterator/istreambuf.iterator_op!=/not_equal.pass.cpp @@ -20,87 +20,106 @@ #include "test_macros.h" -int main(int, char**) -{ - { - std::istringstream inf1("abc"); - std::istringstream inf2("def"); - std::istreambuf_iterator i1(inf1); - std::istreambuf_iterator i2(inf2); - std::istreambuf_iterator i3; - std::istreambuf_iterator i4; - std::istreambuf_iterator i5(nullptr); - - assert(!(i1 != i1)); - assert(!(i1 != i2)); - assert( (i1 != i3)); - assert( (i1 != i4)); - assert( (i1 != i5)); - - assert(!(i2 != i1)); - assert(!(i2 != i2)); - assert( (i2 != i3)); - assert( (i2 != i4)); - assert( (i2 != i5)); - - assert( (i3 != i1)); - assert( (i3 != i2)); - assert(!(i3 != i3)); - assert(!(i3 != i4)); - assert(!(i3 != i5)); - - assert( (i4 != i1)); - assert( (i4 != i2)); - assert(!(i4 != i3)); - assert(!(i4 != i4)); - assert(!(i4 != i5)); - - assert( (i5 != i1)); - assert( (i5 != i2)); - assert(!(i5 != i3)); - assert(!(i5 != i4)); - assert(!(i5 != i5)); - } +int main(int, char**) { + { + std::istringstream inf1("abc"); + std::istringstream inf2("def"); + std::istreambuf_iterator i1(inf1); + std::istreambuf_iterator i2(inf2); + std::istreambuf_iterator i3; + std::istreambuf_iterator i4; + std::istreambuf_iterator i5(nullptr); + + assert(!(i1 != i1)); + assert(!(i1 != i2)); + assert( (i1 != i3)); + assert( (i1 != i4)); + assert( (i1 != i5)); + + assert(!(i2 != i1)); + assert(!(i2 != i2)); + assert( (i2 != i3)); + assert( (i2 != i4)); + assert( (i2 != i5)); + + assert( (i3 != i1)); + assert( (i3 != i2)); + assert(!(i3 != i3)); + assert(!(i3 != i4)); + assert(!(i3 != i5)); + + assert( (i4 != i1)); + assert( (i4 != i2)); + assert(!(i4 != i3)); + assert(!(i4 != i4)); + assert(!(i4 != i5)); + + assert( (i5 != i1)); + assert( (i5 != i2)); + assert(!(i5 != i3)); + assert(!(i5 != i4)); + assert(!(i5 != i5)); + } + +#if TEST_STD_VER > 17 + { + std::istreambuf_iterator i1; + std::istreambuf_iterator i2(std::default_sentinel); + assert(i1 == i2); + + assert(!(i1 != std::default_sentinel)); + assert(!(i2 != std::default_sentinel)); + assert(!(std::default_sentinel != i1)); + assert(!(std::default_sentinel != i2)); + + std::istringstream stream(" 1 23"); + std::istreambuf_iterator i3(stream); + + assert(i3 != std::default_sentinel); + assert(std::default_sentinel != i3); + } +#endif + #ifndef TEST_HAS_NO_WIDE_CHARACTERS - { - std::wistringstream inf1(L"abc"); - std::wistringstream inf2(L"def"); - std::istreambuf_iterator i1(inf1); - std::istreambuf_iterator i2(inf2); - std::istreambuf_iterator i3; - std::istreambuf_iterator i4; - std::istreambuf_iterator i5(nullptr); - - assert(!(i1 != i1)); - assert(!(i1 != i2)); - assert( (i1 != i3)); - assert( (i1 != i4)); - assert( (i1 != i5)); - - assert(!(i2 != i1)); - assert(!(i2 != i2)); - assert( (i2 != i3)); - assert( (i2 != i4)); - assert( (i2 != i5)); - - assert( (i3 != i1)); - assert( (i3 != i2)); - assert(!(i3 != i3)); - assert(!(i3 != i4)); - assert(!(i3 != i5)); - - assert( (i4 != i1)); - assert( (i4 != i2)); - assert(!(i4 != i3)); - assert(!(i4 != i4)); - assert(!(i4 != i5)); - - assert( (i5 != i1)); - assert( (i5 != i2)); - assert(!(i5 != i3)); - assert(!(i5 != i4)); - assert(!(i5 != i5)); - } + { + std::wistringstream inf1(L"abc"); + std::wistringstream inf2(L"def"); + std::istreambuf_iterator i1(inf1); + std::istreambuf_iterator i2(inf2); + std::istreambuf_iterator i3; + std::istreambuf_iterator i4; + std::istreambuf_iterator i5(nullptr); + + assert(!(i1 != i1)); + assert(!(i1 != i2)); + assert( (i1 != i3)); + assert( (i1 != i4)); + assert( (i1 != i5)); + + assert(!(i2 != i1)); + assert(!(i2 != i2)); + assert( (i2 != i3)); + assert( (i2 != i4)); + assert( (i2 != i5)); + + assert( (i3 != i1)); + assert( (i3 != i2)); + assert(!(i3 != i3)); + assert(!(i3 != i4)); + assert(!(i3 != i5)); + + assert( (i4 != i1)); + assert( (i4 != i2)); + assert(!(i4 != i3)); + assert(!(i4 != i4)); + assert(!(i4 != i5)); + + assert( (i5 != i1)); + assert( (i5 != i2)); + assert(!(i5 != i3)); + assert(!(i5 != i4)); + assert(!(i5 != i5)); + } #endif // TEST_HAS_NO_WIDE_CHARACTERS return 0; diff --git a/libcxx/test/std/iterators/stream.iterators/istreambuf.iterator/istreambuf.iterator_op==/equal.pass.cpp b/libcxx/test/std/iterators/stream.iterators/istreambuf.iterator/istreambuf.iterator_op==/equal.pass.cpp --- a/libcxx/test/std/iterators/stream.iterators/istreambuf.iterator/istreambuf.iterator_op==/equal.pass.cpp +++ b/libcxx/test/std/iterators/stream.iterators/istreambuf.iterator/istreambuf.iterator_op==/equal.pass.cpp @@ -20,87 +20,106 @@ #include "test_macros.h" -int main(int, char**) -{ - { - std::istringstream inf1("abc"); - std::istringstream inf2("def"); - std::istreambuf_iterator i1(inf1); - std::istreambuf_iterator i2(inf2); - std::istreambuf_iterator i3; - std::istreambuf_iterator i4; - std::istreambuf_iterator i5(nullptr); - - assert( (i1 == i1)); - assert( (i1 == i2)); - assert(!(i1 == i3)); - assert(!(i1 == i4)); - assert(!(i1 == i5)); - - assert( (i2 == i1)); - assert( (i2 == i2)); - assert(!(i2 == i3)); - assert(!(i2 == i4)); - assert(!(i2 == i5)); - - assert(!(i3 == i1)); - assert(!(i3 == i2)); - assert( (i3 == i3)); - assert( (i3 == i4)); - assert( (i3 == i5)); - - assert(!(i4 == i1)); - assert(!(i4 == i2)); - assert( (i4 == i3)); - assert( (i4 == i4)); - assert( (i4 == i5)); - - assert(!(i5 == i1)); - assert(!(i5 == i2)); - assert( (i5 == i3)); - assert( (i5 == i4)); - assert( (i5 == i5)); - } +int main(int, char**) { + { + std::istringstream inf1("abc"); + std::istringstream inf2("def"); + std::istreambuf_iterator i1(inf1); + std::istreambuf_iterator i2(inf2); + std::istreambuf_iterator i3; + std::istreambuf_iterator i4; + std::istreambuf_iterator i5(nullptr); + + assert( (i1 == i1)); + assert( (i1 == i2)); + assert(!(i1 == i3)); + assert(!(i1 == i4)); + assert(!(i1 == i5)); + + assert( (i2 == i1)); + assert( (i2 == i2)); + assert(!(i2 == i3)); + assert(!(i2 == i4)); + assert(!(i2 == i5)); + + assert(!(i3 == i1)); + assert(!(i3 == i2)); + assert( (i3 == i3)); + assert( (i3 == i4)); + assert( (i3 == i5)); + + assert(!(i4 == i1)); + assert(!(i4 == i2)); + assert( (i4 == i3)); + assert( (i4 == i4)); + assert( (i4 == i5)); + + assert(!(i5 == i1)); + assert(!(i5 == i2)); + assert( (i5 == i3)); + assert( (i5 == i4)); + assert( (i5 == i5)); + } + +#if TEST_STD_VER > 17 + { + std::istreambuf_iterator i1; + std::istreambuf_iterator i2(std::default_sentinel); + assert(i1 == i2); + + assert(i1 == std::default_sentinel); + assert(i2 == std::default_sentinel); + assert(std::default_sentinel == i1); + assert(std::default_sentinel == i2); + + std::istringstream stream(" 1 23"); + std::istreambuf_iterator i3(stream); + + assert(!(i3 == std::default_sentinel)); + assert(!(std::default_sentinel == i3)); + } +#endif + #ifndef TEST_HAS_NO_WIDE_CHARACTERS - { - std::wistringstream inf1(L"abc"); - std::wistringstream inf2(L"def"); - std::istreambuf_iterator i1(inf1); - std::istreambuf_iterator i2(inf2); - std::istreambuf_iterator i3; - std::istreambuf_iterator i4; - std::istreambuf_iterator i5(nullptr); - - assert( (i1 == i1)); - assert( (i1 == i2)); - assert(!(i1 == i3)); - assert(!(i1 == i4)); - assert(!(i1 == i5)); - - assert( (i2 == i1)); - assert( (i2 == i2)); - assert(!(i2 == i3)); - assert(!(i2 == i4)); - assert(!(i2 == i5)); - - assert(!(i3 == i1)); - assert(!(i3 == i2)); - assert( (i3 == i3)); - assert( (i3 == i4)); - assert( (i3 == i5)); - - assert(!(i4 == i1)); - assert(!(i4 == i2)); - assert( (i4 == i3)); - assert( (i4 == i4)); - assert( (i4 == i5)); - - assert(!(i5 == i1)); - assert(!(i5 == i2)); - assert( (i5 == i3)); - assert( (i5 == i4)); - assert( (i5 == i5)); - } + { + std::wistringstream inf1(L"abc"); + std::wistringstream inf2(L"def"); + std::istreambuf_iterator i1(inf1); + std::istreambuf_iterator i2(inf2); + std::istreambuf_iterator i3; + std::istreambuf_iterator i4; + std::istreambuf_iterator i5(nullptr); + + assert( (i1 == i1)); + assert( (i1 == i2)); + assert(!(i1 == i3)); + assert(!(i1 == i4)); + assert(!(i1 == i5)); + + assert( (i2 == i1)); + assert( (i2 == i2)); + assert(!(i2 == i3)); + assert(!(i2 == i4)); + assert(!(i2 == i5)); + + assert(!(i3 == i1)); + assert(!(i3 == i2)); + assert( (i3 == i3)); + assert( (i3 == i4)); + assert( (i3 == i5)); + + assert(!(i4 == i1)); + assert(!(i4 == i2)); + assert( (i4 == i3)); + assert( (i4 == i4)); + assert( (i4 == i5)); + + assert(!(i5 == i1)); + assert(!(i5 == i2)); + assert( (i5 == i3)); + assert( (i5 == i4)); + assert( (i5 == i5)); + } #endif // TEST_HAS_NO_WIDE_CHARACTERS return 0;