This patch adds ranges::basic_istream_view and ranges::istream_view. This seems to be the last missing part of the ranges header.
libstdc++-v3/ChangeLog: * include/std/ranges (ranges::__detail::__stream_extractable, ranges::basic_istream_view, ranges::istream_view): Define. * testsuite/std/ranges/istream_view: New test. --- libstdc++-v3/include/std/ranges | 94 +++++++++++++++++++ .../testsuite/std/ranges/istream_view.cc | 76 +++++++++++++++ 2 files changed, 170 insertions(+) create mode 100644 libstdc++-v3/testsuite/std/ranges/istream_view.cc diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index 8a8fefb6f19..88b98310ef9 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -951,6 +951,100 @@ namespace views inline constexpr _Iota iota{}; } // namespace views + namespace __detail + { + template<typename _Val, typename _CharT, typename _Traits> + concept __stream_extractable + = requires(basic_istream<_CharT, _Traits>& is, _Val& t) { is >> t; }; + } // namespace __detail + + template<movable _Val, typename _CharT, typename _Traits> + requires default_initializable<_Val> + && __detail::__stream_extractable<_Val, _CharT, _Traits> + class basic_istream_view + : public view_interface<basic_istream_view<_Val, _CharT, _Traits>> + { + public: + basic_istream_view() = default; + + constexpr explicit + basic_istream_view(basic_istream<_CharT, _Traits>& __stream) + : _M_stream(std::__addressof(__stream)) + { } + + constexpr auto + begin() + { + if (_M_stream != nullptr) + *_M_stream >> _M_object; + return _Iterator{*this}; + } + + constexpr default_sentinel_t + end() const noexcept + { return default_sentinel; } + + private: + basic_istream<_CharT, _Traits>* _M_stream = nullptr; + _Val _M_object = _Val(); + + struct _Iterator + { + public: + using iterator_category = input_iterator_tag; + using difference_type = ptrdiff_t; + using value_type = _Val; + + _Iterator() = default; + + constexpr explicit + _Iterator(basic_istream_view& __parent) noexcept + : _M_parent(std::__addressof(__parent)) + { } + + _Iterator(const _Iterator&) = delete; + _Iterator(_Iterator&&) = default; + _Iterator& operator=(const _Iterator&) = delete; + _Iterator& operator=(_Iterator&&) = default; + + _Iterator& + operator++() + { + __glibcxx_assert(_M_parent->_M_stream != nullptr); + *_M_parent->_M_stream >> _M_parent->_M_object; + } + + void + operator++(int) + { ++*this; } + + _Val& + operator*() const + { + __glibcxx_assert(_M_parent->_M_stream != nullptr); + return _M_parent->_M_object; + } + + friend bool + operator==(const _Iterator& __x, default_sentinel_t) + { return __x.__at_end(); } + + private: + basic_istream_view* _M_parent = nullptr; + + bool + __at_end() const + { return _M_parent == nullptr || !*_M_parent->_M_stream; } + }; + + friend _Iterator; + }; + + template<typename _Val, typename _CharT, typename _Traits> + basic_istream_view<_Val, _CharT, _Traits> + istream_view(basic_istream<_CharT, _Traits>& __s) + { return basic_istream_view<_Val, _CharT, _Traits>{__s}; } + namespace __detail { struct _Empty { }; diff --git a/libstdc++-v3/testsuite/std/ranges/istream_view.cc b/libstdc++-v3/testsuite/std/ranges/istream_view.cc new file mode 100644 index 00000000000..c573ba57ae8 --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/istream_view.cc @@ -0,0 +1,76 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include <algorithm> +#include <ranges> +#include <sstream> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +namespace ranges = std::ranges; +namespace views = std::views; + +struct X : __gnutest::rvalstruct +{ + char c; + + friend std::istream& + operator>>(std::istream& is, X& m) + { + is >> m.c; + return is; + } +}; + + +void +test01() +{ + std::string s = "0123456789"; + auto ss = std::istringstream{s}; + auto v = ranges::istream_view<X>(ss) | views::transform(&X::c); + VERIFY( ranges::equal(v, s) ); +} + +void +test02() +{ + auto ints = std::istringstream{"0 1 2 3 4"}; + int x[5]; + ranges::copy(ranges::istream_view<int>(ints), x); + VERIFY( ranges::equal(x, (int[]){0,1,2,3,4}) ); +} + +void +test03() +{ + auto input = std::istringstream{"0 1 2 3 4 5 6 7 8 9"}; + auto small = [](const auto x) noexcept { return x < 5; }; + auto v = ranges::istream_view<int>(input) | views::take_while(small); + VERIFY( ranges::equal(v, (int[]){0,1,2,3,4}) ); +} + +int +main() +{ + test01(); + test02(); + test03(); +} -- 2.25.0.191.gde93cc14ab