diff mbox series

libstdc++: Use std::move for iterator in ranges::fill [PR117094]

Message ID 20241013235203.1722255-1-jwakely@redhat.com
State New
Headers show
Series libstdc++: Use std::move for iterator in ranges::fill [PR117094] | expand

Commit Message

Jonathan Wakely Oct. 13, 2024, 11:51 p.m. UTC
Tested x86_64-linux.

-- >8 --

Input iterators aren't required to be copyable.

libstdc++-v3/ChangeLog:

	PR libstdc++/117094
	* include/bits/ranges_algobase.h (__fill_fn): Use std::move for
	iterator that might not be copyable.
	* testsuite/25_algorithms/fill/constrained.cc: Check
	non-copyable iterator with sized sentinel.
---
 libstdc++-v3/include/bits/ranges_algobase.h   |  2 +-
 .../25_algorithms/fill/constrained.cc         | 34 +++++++++++++++++++
 2 files changed, 35 insertions(+), 1 deletion(-)

Comments

Patrick Palka Oct. 14, 2024, 3:37 p.m. UTC | #1
LGTM

On Mon, 14 Oct 2024, Jonathan Wakely wrote:

> Tested x86_64-linux.
> 
> -- >8 --
> 
> Input iterators aren't required to be copyable.
> 
> libstdc++-v3/ChangeLog:
> 
> 	PR libstdc++/117094
> 	* include/bits/ranges_algobase.h (__fill_fn): Use std::move for
> 	iterator that might not be copyable.
> 	* testsuite/25_algorithms/fill/constrained.cc: Check
> 	non-copyable iterator with sized sentinel.
> ---
>  libstdc++-v3/include/bits/ranges_algobase.h   |  2 +-
>  .../25_algorithms/fill/constrained.cc         | 34 +++++++++++++++++++
>  2 files changed, 35 insertions(+), 1 deletion(-)
> 
> diff --git a/libstdc++-v3/include/bits/ranges_algobase.h b/libstdc++-v3/include/bits/ranges_algobase.h
> index 3c8d46198c5..0345ea850a4 100644
> --- a/libstdc++-v3/include/bits/ranges_algobase.h
> +++ b/libstdc++-v3/include/bits/ranges_algobase.h
> @@ -592,7 +592,7 @@ namespace ranges
>  	if constexpr (sized_sentinel_for<_Sent, _Out>)
>  	  {
>  	    const auto __len = __last - __first;
> -	    return ranges::fill_n(__first, __len, __value);
> +	    return ranges::fill_n(std::move(__first), __len, __value);
>  	  }
>  	else if constexpr (is_scalar_v<_Tp>)
>  	  {
> diff --git a/libstdc++-v3/testsuite/25_algorithms/fill/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/fill/constrained.cc
> index 126515eddca..7cae99f2d5c 100644
> --- a/libstdc++-v3/testsuite/25_algorithms/fill/constrained.cc
> +++ b/libstdc++-v3/testsuite/25_algorithms/fill/constrained.cc
> @@ -83,9 +83,43 @@ test02()
>    return ok;
>  }
>  
> +void
> +test03()
> +{
> +  // Bug libstdc++/117094 - ranges::fill misses std::move for output_iterator
> +
> +  // Move-only output iterator
> +  struct Iterator
> +  {
> +    using difference_type = long;
> +    Iterator(int* p) : p(p) { }
> +    Iterator(Iterator&&) = default;
> +    Iterator& operator=(Iterator&&) = default;
> +    int& operator*() const { return *p; }
> +    Iterator& operator++() { ++p; return *this; }
> +    Iterator operator++(int) { return Iterator(p++ ); }
> +    int* p;
> +
> +    struct Sentinel
> +    {
> +      const int* p;
> +      bool operator==(const Iterator& i) const { return p == i.p; }
> +      long operator-(const Iterator& i) const { return p - i.p; }
> +    };
> +
> +    long operator-(Sentinel s) const { return p - s.p; }
> +  };
> +  static_assert(std::sized_sentinel_for<Iterator::Sentinel, Iterator>);
> +  int a[2];
> +  std::ranges::fill(Iterator(a), Iterator::Sentinel{a+2}, 999);
> +  VERIFY( a[0] == 999 );
> +  VERIFY( a[1] == 999 );
> +}
> +
>  int
>  main()
>  {
>    test01();
>    static_assert(test02());
> +  test03();
>  }
> -- 
> 2.46.2
> 
>
diff mbox series

Patch

diff --git a/libstdc++-v3/include/bits/ranges_algobase.h b/libstdc++-v3/include/bits/ranges_algobase.h
index 3c8d46198c5..0345ea850a4 100644
--- a/libstdc++-v3/include/bits/ranges_algobase.h
+++ b/libstdc++-v3/include/bits/ranges_algobase.h
@@ -592,7 +592,7 @@  namespace ranges
 	if constexpr (sized_sentinel_for<_Sent, _Out>)
 	  {
 	    const auto __len = __last - __first;
-	    return ranges::fill_n(__first, __len, __value);
+	    return ranges::fill_n(std::move(__first), __len, __value);
 	  }
 	else if constexpr (is_scalar_v<_Tp>)
 	  {
diff --git a/libstdc++-v3/testsuite/25_algorithms/fill/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/fill/constrained.cc
index 126515eddca..7cae99f2d5c 100644
--- a/libstdc++-v3/testsuite/25_algorithms/fill/constrained.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/fill/constrained.cc
@@ -83,9 +83,43 @@  test02()
   return ok;
 }
 
+void
+test03()
+{
+  // Bug libstdc++/117094 - ranges::fill misses std::move for output_iterator
+
+  // Move-only output iterator
+  struct Iterator
+  {
+    using difference_type = long;
+    Iterator(int* p) : p(p) { }
+    Iterator(Iterator&&) = default;
+    Iterator& operator=(Iterator&&) = default;
+    int& operator*() const { return *p; }
+    Iterator& operator++() { ++p; return *this; }
+    Iterator operator++(int) { return Iterator(p++ ); }
+    int* p;
+
+    struct Sentinel
+    {
+      const int* p;
+      bool operator==(const Iterator& i) const { return p == i.p; }
+      long operator-(const Iterator& i) const { return p - i.p; }
+    };
+
+    long operator-(Sentinel s) const { return p - s.p; }
+  };
+  static_assert(std::sized_sentinel_for<Iterator::Sentinel, Iterator>);
+  int a[2];
+  std::ranges::fill(Iterator(a), Iterator::Sentinel{a+2}, 999);
+  VERIFY( a[0] == 999 );
+  VERIFY( a[1] == 999 );
+}
+
 int
 main()
 {
   test01();
   static_assert(test02());
+  test03();
 }