Re: [PATCH 4/3] Add [range.istream]

2020-02-07 Thread Jonathan Wakely

On 07/02/20 09:46 -0500, Patrick Palka wrote:

Fixed and committed with that change.  Thanks for the review!


I've just tested and pushed this fix.

commit 572992c8920d5339a3ac28d442c436d6daa0bfae
Author: Jonathan Wakely 
Date:   Fri Feb 7 16:06:43 2020 +

libstdc++ Fix missing return in istream_view iterator

* include/std/ranges (iota_view): Add braces to prevent -Wempty-body
warning.
(basic_istream_view::_Iterator::operator++()): Add missing return.

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index dd0c5cf6aa7..891ecf75eff 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -872,7 +872,9 @@ namespace ranges
   : _M_value(__value), _M_bound(__bound)
   {
 	if constexpr (totally_ordered_with<_Winc, _Bound>)
-	  __glibcxx_assert( bool(__value <= __bound) );
+	  {
+	__glibcxx_assert( bool(__value <= __bound) );
+	  }
   }
 
   constexpr _Iterator
@@ -1012,6 +1014,7 @@ namespace views
 	{
 	  __glibcxx_assert(_M_parent->_M_stream != nullptr);
 	  *_M_parent->_M_stream >> _M_parent->_M_object;
+	  return *this;
 	}
 
 	void


Re: [PATCH 4/3] Add [range.istream]

2020-02-07 Thread Patrick Palka
On Fri, 7 Feb 2020, Jonathan Wakely wrote:

> On 06/02/20 19:52 -0500, Patrick Palka wrote:
> > 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
> > +  concept __stream_extractable
> > +   = requires(basic_istream<_CharT, _Traits>& is, _Val& t) { is >> t; };
> 
> I was going to ask for "is" and "t" to use reserved names, but those
> names are actually reserved. std::ctype::is is present since C++98 and
> std::binomial_distribution::t() since C++11. So the names are OK.

Phew! :)  I just forgot to uglify those names.

> 
> > +  } // namespace __detail
> > +
> > +  template
> > +requires default_initializable<_Val>
> > +  && __detail::__stream_extractable<_Val, _CharT, _Traits>
> > +class basic_istream_view
> > +: public view_interface>
> > +{
> > +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
> 
> Please rename this to _M_at_end for consistency with the rest of the
> library.
> 
> OK for master with that tweak, thanks.

Fixed and committed with that change.  Thanks for the review!



Re: [PATCH 4/3] Add [range.istream]

2020-02-07 Thread Jonathan Wakely

On 06/02/20 19:52 -0500, Patrick Palka wrote:

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
+  concept __stream_extractable
+   = requires(basic_istream<_CharT, _Traits>& is, _Val& t) { is >> t; };


I was going to ask for "is" and "t" to use reserved names, but those
names are actually reserved. std::ctype::is is present since C++98 and
std::binomial_distribution::t() since C++11. So the names are OK.


+  } // namespace __detail
+
+  template
+requires default_initializable<_Val>
+  && __detail::__stream_extractable<_Val, _CharT, _Traits>
+class basic_istream_view
+: public view_interface>
+{
+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


Please rename this to _M_at_end for consistency with the rest of the
library.

OK for master with that tweak, thanks.



[PATCH 4/3] Add [range.istream]

2020-02-06 Thread Patrick Palka
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
+  concept __stream_extractable
+   = requires(basic_istream<_CharT, _Traits>& is, _Val& t) { is >> t; };
+  } // namespace __detail
+
+  template
+requires default_initializable<_Val>
+  && __detail::__stream_extractable<_Val, _CharT, _Traits>
+class basic_istream_view
+: public view_interface>
+{
+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
+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 000..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
+// .
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+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(ss) | views::transform(::c);
+  VERIFY( ranges::equal(v, s) );
+}
+
+void
+test02()
+{
+  auto ints = std::istringstream{"0 1  2