Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement ranges::istream_view #1334

Merged
merged 9 commits into from
Oct 29, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 20 additions & 9 deletions stl/inc/ranges
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,12 @@ namespace ranges {

_Iterator& operator++() {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(*this != default_sentinel, "cannot increment istream_view iterator at end of stream");
_STL_VERIFY(_Parent != nullptr,
"cannot increment default initialized istream_view iterator"); // Per LWG-XXXX
_STL_VERIFY(
_Parent->_Stream != nullptr, "cannot increment istream_view iterator with uninitialized stream");
_STL_VERIFY(!_Parent->_Stream_at_end(),
"cannot increment istream_view iterator at end of stream"); // Per LWG-XXXX
CaseyCarter marked this conversation as resolved.
Show resolved Hide resolved
#endif // _ITERATOR_DEBUG_LEVEL != 0
*_Parent->_Stream >> _Parent->_Val;
return *this;
Expand All @@ -667,14 +672,19 @@ namespace ranges {
++*this;
}

_Ty& operator*() const {
_NODISCARD _Ty& operator*() const noexcept /* strengthened */ {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(*this != default_sentinel, "cannot dereference istream_view iterator at end of stream");
_STL_VERIFY(_Parent != nullptr,
"cannot dereference default initialized istream_view iterator"); // Per LWG-XXXX
_STL_VERIFY(
_Parent->_Stream != nullptr, "cannot dereference istream_view iterator with uninitialized stream");
_STL_VERIFY(!_Parent->_Stream_at_end(),
"cannot dereference istream_view iterator at end of stream"); // Per LWG-XXXX
CaseyCarter marked this conversation as resolved.
Show resolved Hide resolved
#endif // _ITERATOR_DEBUG_LEVEL != 0
return _Parent->_Val;
}

friend bool operator==(const _Iterator& _Left, default_sentinel_t) {
_NODISCARD friend bool operator==(const _Iterator& _Left, default_sentinel_t) noexcept /* strengthened */ {
return _Left._Parent == nullptr || _Left._Parent->_Stream_at_end();
}
};
Expand All @@ -684,27 +694,28 @@ namespace ranges {

public:
basic_istream_view() = default;
constexpr explicit basic_istream_view(basic_istream<_Elem, _Traits>& _Stream_) noexcept // strengthened
constexpr explicit basic_istream_view(basic_istream<_Elem, _Traits>& _Stream_) noexcept(
is_nothrow_default_constructible_v<_Ty>) // strengthened
: _Stream{_STD addressof(_Stream_)} {}

constexpr auto begin() {
_NODISCARD constexpr auto begin() {
if (_Stream) {
*_Stream >> _Val;
}
return _Iterator{*this};
}

constexpr default_sentinel_t end() const noexcept {
_NODISCARD constexpr default_sentinel_t end() const noexcept {
return default_sentinel;
}

constexpr bool _Stream_at_end() const noexcept {
_NODISCARD constexpr bool _Stream_at_end() const noexcept {
return _Stream == nullptr || !*_Stream;
CaseyCarter marked this conversation as resolved.
Show resolved Hide resolved
}
};

template <class _Ty, class _Elem, class _Traits>
basic_istream_view<_Ty, _Elem, _Traits> istream_view(basic_istream<_Elem, _Traits>& _Stream) {
_NODISCARD basic_istream_view<_Ty, _Elem, _Traits> istream_view(basic_istream<_Elem, _Traits>& _Stream) {
CaseyCarter marked this conversation as resolved.
Show resolved Hide resolved
return basic_istream_view<_Ty, _Elem, _Traits>{_Stream};
}

Expand Down
38 changes: 24 additions & 14 deletions tests/std/tests/P0896R4_views_istream/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <istream>
#include <ranges>
#include <sstream>

#include <range_algorithm_support.hpp>

using namespace std;

static constexpr int expected_empty[] = {-1, -1, -1, -1, -1};
static constexpr int expected_copied[] = {0, 1, 2, 3, -1};
constexpr int expected_empty[] = {-1, -1, -1, -1, -1};

struct streamable {
streamable() = default;
streamable(const int input) : _val(input) {}

friend basic_istream<char>& operator>>(basic_istream<char>& is, streamable& right) noexcept {
friend istream& operator>>(istream& is, streamable& right) noexcept {
is >> right._val;
return is;
}
Expand All @@ -42,17 +42,21 @@ bool test_one_type() {
static_assert(!ranges::common_range<R>);

// validate constructor
auto nonempty_stream = istringstream{"0"};
auto empty_intstream = istringstream{};
same_as<R> auto default_constructed = ranges::basic_istream_view<T, char>{};
same_as<R> auto empty_constructed = ranges::basic_istream_view<T, char>{empty_intstream};
same_as<R> auto value_constructed = ranges::basic_istream_view<T, char>{nonempty_stream};
auto nonempty_stream = istringstream{"0"};
auto empty_intstream = istringstream{};
same_as<R> auto default_constructed = basic_istream_view<T, char>{};
same_as<R> auto empty_constructed = basic_istream_view<T, char>{empty_intstream};
same_as<R> auto non_empty_constructed = basic_istream_view<T, char>{nonempty_stream};

// validate member begin
// NOTE: This moves the stream one element int front
// NOTE: begin() consumes the first token
assert(default_constructed.begin() == default_sentinel);
assert(empty_constructed.begin() == default_sentinel);
assert(value_constructed.begin() != default_sentinel);
assert(non_empty_constructed.begin() != default_sentinel);

// validate default constructed istream::iterator
const auto default_constructed_it = ranges::iterator_t<R>();
assert(default_constructed_it == default_sentinel);

// validate member end
static_assert(same_as<decltype(default_constructed.end()), default_sentinel_t>);
Expand All @@ -75,10 +79,16 @@ bool test_one_type() {
ranges::copy(empty_constructed, input_empty);
assert(ranges::equal(input_empty, expected_empty));

auto intstream = istringstream{"0 1 2 3"};
T input_value[] = {-1, -1, -1, -1, -1};
ranges::copy(ranges::basic_istream_view<T, char>{intstream}, input_value);
assert(ranges::equal(input_value, expected_copied));
const T expected[] = {0, 1, 2, 3, -1};
auto intstream = istringstream{"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));

auto intstream_view = istringstream{"0 1 2 3"};
T input_value_view[] = {-1, -1, -1, -1, -1};
ranges::copy(ranges::istream_view<T, char>(intstream_view), input_value_view);
assert(ranges::equal(input_value_view, expected));

miscco marked this conversation as resolved.
Show resolved Hide resolved
return true;
}
Expand Down
31 changes: 15 additions & 16 deletions tests/std/tests/P0896R4_views_istream_death/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,28 @@ using namespace std;

using iview = ranges::basic_istream_view<int, char>;

void test_predecrement_default_initialized() {
decltype(std::declval<iview>().begin()) it;
void test_preincrement_default_initialized() {
ranges::iterator_t<iview> it;
(void) ++it;
}

void test_postdecrement_default_initialized() {
decltype(std::declval<iview>().begin()) it;
void test_postincrement_default_initialized() {
ranges::iterator_t<iview> it;
(void) it++;
}

void test_dereference_default_initialized() {
decltype(std::declval<iview>().begin()) it;
ranges::iterator_t<iview> it;
(void) *it;
}

void test_predecrement_no_stream() {
void test_preincrement_no_stream() {
iview v;
auto it = v.begin();
(void) ++it;
}

void test_postdecrement_no_stream() {
void test_postincrement_no_stream() {
iview v;
auto it = v.begin();
(void) it++;
Expand All @@ -46,15 +46,14 @@ void test_dereference_no_stream() {
(void) *it;
}


void test_predecrement_end_of_stream() {
void test_preincrement_end_of_stream() {
istringstream stream;
iview view{stream};
auto it = view.begin();
(void) ++it;
}

void test_postdecrement_end_of_stream() {
void test_postincrement_end_of_stream() {
istringstream stream;
iview view{stream};
auto it = view.begin();
Expand All @@ -73,14 +72,14 @@ int main(int argc, char* argv[]) {

#if _ITERATOR_DEBUG_LEVEL != 0
exec.add_death_tests({
test_predecrement_default_initialized,
test_postdecrement_default_initialized,
test_preincrement_default_initialized,
test_postincrement_default_initialized,
test_dereference_default_initialized,
test_predecrement_no_stream,
test_postdecrement_no_stream,
test_preincrement_no_stream,
test_postincrement_no_stream,
test_dereference_no_stream,
test_predecrement_end_of_stream,
test_postdecrement_end_of_stream,
test_preincrement_end_of_stream,
test_postincrement_end_of_stream,
test_dereference_end_of_stream,
});
#endif // _ITERATOR_DEBUG_LEVEL != 0
Expand Down