Skip to content

Commit

Permalink
Implement P2432R1 Fix istream_view (microsoft#2245)
Browse files Browse the repository at this point in the history
  • Loading branch information
CaseyCarter authored and AreaZR committed Nov 4, 2021
1 parent 9480264 commit e2e2f82
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 21 deletions.
38 changes: 28 additions & 10 deletions stl/inc/ranges
Original file line number Diff line number Diff line change
Expand Up @@ -1328,7 +1328,8 @@ namespace ranges {
_Iterator& operator++() {
#if _ITERATOR_DEBUG_LEVEL != 0
// Per LWG-3489
_STL_VERIFY(!_Parent->_Stream_at_end(), "cannot increment istream_view iterator at end of stream");
_STL_VERIFY(
!_Parent->_Stream_at_end(), "cannot increment basic_istream_view iterator at end of stream");
#endif // _ITERATOR_DEBUG_LEVEL != 0
*_Parent->_Stream >> _Parent->_Val;
return *this;
Expand All @@ -1341,7 +1342,8 @@ namespace ranges {
_NODISCARD _Ty& operator*() const noexcept /* strengthened */ {
#if _ITERATOR_DEBUG_LEVEL != 0
// Per LWG-3489
_STL_VERIFY(!_Parent->_Stream_at_end(), "cannot dereference istream_view iterator at end of stream");
_STL_VERIFY(
!_Parent->_Stream_at_end(), "cannot dereference basic_istream_view iterator at end of stream");
#endif // _ITERATOR_DEBUG_LEVEL != 0
return _Parent->_Val;
}
Expand Down Expand Up @@ -1373,11 +1375,28 @@ namespace ranges {
}
};

template <class _Ty, class _Elem, class _Traits>
_NODISCARD basic_istream_view<_Ty, _Elem, _Traits> istream_view(basic_istream<_Elem, _Traits>& _Stream) noexcept(
is_nothrow_default_constructible_v<_Ty>) /* strengthened */ {
return basic_istream_view<_Ty, _Elem, _Traits>{_Stream};
}
template <class _Ty>
using istream_view = basic_istream_view<_Ty, char>;
template <class _Ty>
using wistream_view = basic_istream_view<_Ty, wchar_t>;

namespace views {
template <class _Ty>
struct _Istream_fn {
// clang-format off
template <class _StreamTy>
requires derived_from<_StreamTy,
basic_istream<typename _StreamTy::char_type, typename _StreamTy::traits_type>>
_NODISCARD constexpr auto operator()(_StreamTy& _Stream) const
noexcept(is_nothrow_default_constructible_v<_Ty>) /* strengthened */ {
// clang-format on
return basic_istream_view<_Ty, typename _StreamTy::char_type, typename _StreamTy::traits_type>(_Stream);
}
};

template <class _Ty>
inline constexpr _Istream_fn<_Ty> istream;
} // namespace views

// clang-format off
template <range _Rng>
Expand Down Expand Up @@ -3257,9 +3276,8 @@ namespace ranges {
// clang-format off
_NODISCARD constexpr auto end() const
requires input_range<const _Vw> && is_reference_v<_InnerRng<true>> {
if constexpr (forward_range<const _Vw> && is_reference_v<_InnerRng<true>>
&& forward_range<_InnerRng<true>> && common_range<const _Vw>
&& common_range<_InnerRng<true>>) {
if constexpr (forward_range<const _Vw> && forward_range<_InnerRng<true>>
&& common_range<const _Vw> && common_range<_InnerRng<true>>) {
// clang-format on
return _Iterator<true>{*this, _RANGES end(_Range)};
} else {
Expand Down
1 change: 1 addition & 0 deletions stl/inc/yvals_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@
// P2325R3 Views Should Not Be Required To Be Default Constructible
// P2328R1 join_view Should Join All views Of ranges
// P2367R0 Remove Misuses Of List-Initialization From Clause 24 Ranges
// P2432R1 Fix istream_view
// P????R? directory_entry::clear_cache()

// _HAS_CXX20 indirectly controls:
Expand Down
58 changes: 47 additions & 11 deletions tests/std/tests/P0896R4_istream_view/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ struct streamable {
streamable() = default;
streamable(const int input) : _val(input) {}

friend istream& operator>>(istream& is, streamable& right) noexcept {
template <class CharT, class Traits>
friend basic_istream<CharT, Traits>& operator>>(basic_istream<CharT, Traits>& is, streamable& right) noexcept {
is >> right._val;
return is;
}

friend bool operator==(const streamable& left, const streamable& right) noexcept = default;
friend bool operator==(const streamable&, const streamable&) noexcept = default;

int _val = 0;
};
Expand Down Expand Up @@ -73,16 +74,51 @@ void test_one_type() {
ranges::copy(empty_constructed, input_empty);
assert(ranges::equal(input_empty, expected_empty));

istringstream intstream{"0 1 2 3"};
T input_value[] = {-1, -1, -1, -1, -1};
ranges::copy(basic_istream_view<T, char>{intstream}, input_value);
assert(ranges::equal(input_value, expected));
{ // using ranges::basic_istream_view with wide stream
wistringstream wintstream{L"0 1 2 3"};
T input_value[] = {-1, -1, -1, -1, -1};
ranges::copy(basic_istream_view<T, wchar_t>{wintstream}, input_value);
assert(ranges::equal(input_value, expected));
}

{ // using ranges::basic_istream_view with narrow stream
istringstream intstream{"0 1 2 3"};
T input_value[] = {-1, -1, -1, -1, -1};
ranges::copy(basic_istream_view<T, char>{intstream}, input_value);
assert(ranges::equal(input_value, expected));
}

{ // Using ranges::istream_view
istringstream intstream{"0 1 2 3"};
T input[] = {-1, -1, -1, -1, -1};
ranges::copy(ranges::istream_view<T>(intstream), input);
static_assert(noexcept(ranges::istream_view<T>(intstream)));
assert(ranges::equal(input, expected));
}

istringstream intstream_view{"0 1 2 3"};
T input_value_view[] = {-1, -1, -1, -1, -1};
ranges::copy(ranges::istream_view<T>(intstream_view), input_value_view);
static_assert(noexcept(ranges::istream_view<T>(intstream_view)));
assert(ranges::equal(input_value_view, expected));
{ // Using ranges::wistream_view
wistringstream wintstream{L"0 1 2 3"};
T input[] = {-1, -1, -1, -1, -1};
ranges::copy(ranges::wistream_view<T>(wintstream), input);
static_assert(noexcept(ranges::wistream_view<T>(wintstream)));
assert(ranges::equal(input, expected));
}

{ // Using views::istream with narrow stream
istringstream intstream{"0 1 2 3"};
T input[] = {-1, -1, -1, -1, -1};
ranges::copy(views::istream<T>(intstream), input);
static_assert(noexcept(views::istream<T>(intstream)));
assert(ranges::equal(input, expected));
}

{ // Using views::istream with wide stream
wistringstream wintstream{L"0 1 2 3"};
T input[] = {-1, -1, -1, -1, -1};
ranges::copy(views::istream<T>(wintstream), input);
static_assert(noexcept(views::istream<T>(wintstream)));
assert(ranges::equal(input, expected));
}
}

istringstream some_stream{"42"};
Expand Down
2 changes: 2 additions & 0 deletions tests/std/tests/P0896R4_ranges_range_machinery/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ STATIC_ASSERT(test_cpo(ranges::views::drop_while));
STATIC_ASSERT(test_cpo(ranges::views::elements<42>));
STATIC_ASSERT(test_cpo(ranges::views::filter));
STATIC_ASSERT(test_cpo(ranges::views::iota));
STATIC_ASSERT(test_cpo(ranges::views::istream<int>));
STATIC_ASSERT(test_cpo(ranges::views::istream<double>));
STATIC_ASSERT(test_cpo(ranges::views::join));
STATIC_ASSERT(test_cpo(ranges::views::keys));
STATIC_ASSERT(test_cpo(ranges::views::lazy_split));
Expand Down

0 comments on commit e2e2f82

Please sign in to comment.