libstdc++: Add [range.istream]
authorPatrick Palka <ppalka@redhat.com>
Fri, 7 Feb 2020 00:24:03 +0000 (19:24 -0500)
committerPatrick Palka <ppalka@redhat.com>
Fri, 7 Feb 2020 14:44:53 +0000 (09:44 -0500)
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/ChangeLog
libstdc++-v3/include/std/ranges
libstdc++-v3/testsuite/std/ranges/istream_view.cc [new file with mode: 0644]

index b374eff74087ecd990f5d63208618e7a4270851c..4e010016a0357553d5e19206b1dc37aee85fdb72 100644 (file)
@@ -1,5 +1,9 @@
 2020-02-07  Patrick Palka  <ppalka@redhat.com>
 
+       * include/std/ranges (ranges::__detail::__stream_extractable,
+       ranges::basic_istream_view, ranges::istream_view): Define.
+       * testsuite/std/ranges/istream_view: New test.
+
        Implement C++20 range adaptors
        * include/std/ranges: Include <bits/refwrap.h> and <tuple>.
        (subrange::_S_store_size): Mark as const instead of constexpr to
index 9f4fa3414d0c7c7c747cf41eed8e64b8f630b9a5..dd0c5cf6aa75fc7c84176509f4c9df264a7d388e 100644 (file)
@@ -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._M_at_end(); }
+
+      private:
+       basic_istream_view* _M_parent = nullptr;
+
+       bool
+       _M_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 (file)
index 0000000..1729459
--- /dev/null
@@ -0,0 +1,77 @@
+// 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>
+#include <testsuite_rvalref.h>
+
+namespace ranges = std::ranges;
+namespace views = std::views;
+
+struct X : __gnu_test::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);
+  VERIFY( ranges::equal(v, s, {}, &X::c) );
+}
+
+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();
+}