* [PATCH] libstdc++: P0769R2 Add shift to <algorithm>
@ 2020-02-21 19:29 Patrick Palka
2020-02-21 21:12 ` Patrick Palka
2020-03-02 9:03 ` Stephan Bergmann
0 siblings, 2 replies; 8+ messages in thread
From: Patrick Palka @ 2020-02-21 19:29 UTC (permalink / raw)
To: gcc-patches; +Cc: libstdc++, jwakely, Patrick Palka
This patch adds std::shift_left and std::shift_right. Alhough these are
STL-style algos, they are nonetheless placed in <bits/ranges_algo.h> because
they make use of some functions in the ranges namespace that are more easily
reachable from <bits/ranges_algo.h> than from <bits/stl_algo.h>, namely
ranges::next and ranges::swap_ranges.
This implementation of std::shift_right for non-bidirectional iterators deviates
from the reference implementation a bit. The main difference is that this
implementation is significantly simpler, and yet saves around n/2 additional
iterator increments and n/2 iter_moves at the cost of around n/2 additional
iter_swaps (where n is the shift amount).
libstdc++-v3/ChangeLog:
P0769R2 Add shift to <algorithm>
* include/bits/ranges_algo.h (shift_left, shift_right): New.
* testsuite/25_algorithms/shift_left/1.cc: New test.
* testsuite/25_algorithms/shift_right/1.cc: New test.
---
libstdc++-v3/include/bits/ranges_algo.h | 48 +++++++++++++
.../testsuite/25_algorithms/shift_left/1.cc | 67 +++++++++++++++++++
.../testsuite/25_algorithms/shift_right/1.cc | 67 +++++++++++++++++++
3 files changed, 182 insertions(+)
create mode 100644 libstdc++-v3/testsuite/25_algorithms/shift_left/1.cc
create mode 100644 libstdc++-v3/testsuite/25_algorithms/shift_right/1.cc
diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h
index 7de1072abf0..c36afc6e19b 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -3683,6 +3683,54 @@ namespace ranges
inline constexpr __prev_permutation_fn prev_permutation{};
} // namespace ranges
+
+ template<class ForwardIterator>
+ constexpr ForwardIterator
+ shift_left(ForwardIterator __first, ForwardIterator __last,
+ typename iterator_traits<ForwardIterator>::difference_type __n)
+ {
+ __glibcxx_assert(__n >= 0);
+ if (__n == 0)
+ return __last;
+
+ auto __mid = ranges::next(__first, __n, __last);
+ if (__mid == __last)
+ return __first;
+ return std::move(std::move(__mid), std::move(__last), std::move(__first));
+ }
+
+ template<class ForwardIterator>
+ constexpr ForwardIterator
+ shift_right(ForwardIterator __first, ForwardIterator __last,
+ typename iterator_traits<ForwardIterator>::difference_type __n)
+ {
+ __glibcxx_assert(__n >= 0);
+ if (__n == 0)
+ return __first;
+
+ using _Cat = iterator_traits<ForwardIterator>::iterator_category;
+ if constexpr (derived_from<_Cat, bidirectional_iterator_tag>)
+ {
+ auto __mid = ranges::next(__last, -__n, __first);
+ if (__mid == __first)
+ return __last;
+ return std::move_backward(std::move(__first), std::move(__mid),
+ std::move(__last));
+ }
+ else
+ {
+ auto __result = ranges::next(__first, __n, __last);
+ if (__result == __last)
+ return __last;
+ auto __dest = __result;
+ do
+ __dest = ranges::swap_ranges(__first, __result,
+ std::move(__dest), __last).in2;
+ while (__dest != __last);
+ return __result;
+ }
+ }
+
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
#endif // concepts
diff --git a/libstdc++-v3/testsuite/25_algorithms/shift_left/1.cc b/libstdc++-v3/testsuite/25_algorithms/shift_left/1.cc
new file mode 100644
index 00000000000..9bdb843adbc
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/shift_left/1.cc
@@ -0,0 +1,67 @@
+// 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 <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+using __gnu_test::test_container;
+using __gnu_test::forward_iterator_wrapper;
+using __gnu_test::bidirectional_iterator_wrapper;
+using __gnu_test::random_access_iterator_wrapper;
+
+template<int K, template<typename> typename Wrapper>
+void
+test01()
+{
+ static_assert(K == 10 || K == 11);
+ for (int i = 0; i < 15; i++)
+ {
+ int x[K];
+ for (int t = 0; t < K; t++)
+ x[t] = t;
+ test_container<int, Wrapper> cx(x);
+ auto out = std::shift_left(cx.begin(), cx.end(), i);
+ if (i < K)
+ {
+ VERIFY( out.ptr == x+(K-i) );
+ for (int j = i; j < K-i; j++)
+ VERIFY( x[j] == i+j );
+ }
+ else
+ {
+ VERIFY( out.ptr == x );
+ for (int j = 0; j < K; j++)
+ VERIFY( x[j] == j );
+ }
+ }
+}
+
+int
+main()
+{
+ test01<10, forward_iterator_wrapper>();
+ test01<10, bidirectional_iterator_wrapper>();
+ test01<10, random_access_iterator_wrapper>();
+
+ test01<11, forward_iterator_wrapper>();
+ test01<11, bidirectional_iterator_wrapper>();
+ test01<11, random_access_iterator_wrapper>();
+}
diff --git a/libstdc++-v3/testsuite/25_algorithms/shift_right/1.cc b/libstdc++-v3/testsuite/25_algorithms/shift_right/1.cc
new file mode 100644
index 00000000000..3ce05ed287b
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/shift_right/1.cc
@@ -0,0 +1,67 @@
+// 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 <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+using __gnu_test::test_container;
+using __gnu_test::forward_iterator_wrapper;
+using __gnu_test::bidirectional_iterator_wrapper;
+using __gnu_test::random_access_iterator_wrapper;
+
+template<int K, template<typename> typename Wrapper>
+void
+test01()
+{
+ static_assert(K == 10 || K == 11);
+ for (int i = 0; i < 15; i++)
+ {
+ int x[K];
+ for (int t = 0; t < K; t++)
+ x[t] = t;
+ test_container<int, Wrapper> cx(x);
+ auto out = std::shift_right(cx.begin(), cx.end(), i);
+ if (i < K)
+ {
+ VERIFY( out.ptr == x+i );
+ for (int j = i; j < K; j++)
+ VERIFY( x[j] == j-i );
+ }
+ else
+ {
+ VERIFY( out.ptr == x+K );
+ for (int j = 0; j < K; j++)
+ VERIFY( x[j] == j );
+ }
+ }
+}
+
+int
+main()
+{
+ test01<10, forward_iterator_wrapper>();
+ test01<10, bidirectional_iterator_wrapper>();
+ test01<10, random_access_iterator_wrapper>();
+
+ test01<11, forward_iterator_wrapper>();
+ test01<11, bidirectional_iterator_wrapper>();
+ test01<11, random_access_iterator_wrapper>();
+}
--
2.25.1.291.ge68e29171c
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] libstdc++: P0769R2 Add shift to <algorithm>
2020-02-21 19:29 [PATCH] libstdc++: P0769R2 Add shift to <algorithm> Patrick Palka
@ 2020-02-21 21:12 ` Patrick Palka
2020-02-24 13:47 ` Jonathan Wakely
2020-03-02 9:03 ` Stephan Bergmann
1 sibling, 1 reply; 8+ messages in thread
From: Patrick Palka @ 2020-02-21 21:12 UTC (permalink / raw)
To: Patrick Palka; +Cc: gcc-patches, libstdc++, jwakely
On Fri, 21 Feb 2020, Patrick Palka wrote:
> This patch adds std::shift_left and std::shift_right. Alhough these are
> STL-style algos, they are nonetheless placed in <bits/ranges_algo.h> because
> they make use of some functions in the ranges namespace that are more easily
> reachable from <bits/ranges_algo.h> than from <bits/stl_algo.h>, namely
> ranges::next and ranges::swap_ranges.
>
> This implementation of std::shift_right for non-bidirectional iterators deviates
> from the reference implementation a bit. The main difference is that this
> implementation is significantly simpler, and yet saves around n/2 additional
> iterator increments and n/2 iter_moves at the cost of around n/2 additional
> iter_swaps (where n is the shift amount).
On second thought, this simplification of shift_right is a not a good
idea because the objects that were shifted and that are no longer a part
of the new range do not end up in a moved-from state at the end of the
algorithm. Here is a version of the patch that instead adds something
akin to the reference implementation and improves the tests to verify
this moved-from property of both algorithms.
-- >8 --
Subject: [PATCH] libstdc++: P0769R2 Add shift to <algorithm>
This patch adds std::shift_left and std::shift_right as per P0769R2. Alhough
these are STL-style algos, this patch places them in <bits/ranges_algo.h>
because they make use of some functions in the ranges namespace that are more
easily reachable from <bits/ranges_algo.h> than from <bits/stl_algo.h>, namely
ranges::next. In order to place these algos in <bits/stl_algo.h>, we would need
to include <bits/range_access.h> from <bits/stl_algo.h> which would undesirably
increase the size of <bits/stl_algo.h>.
libstdc++-v3/ChangeLog:
P0769R2 Add shift to <algorithm>
* include/bits/ranges_algo.h (shift_left, shift_right): New.
* testsuite/25_algorithms/shift_left/1.cc: New test.
* testsuite/25_algorithms/shift_right/1.cc: New test.
---
libstdc++-v3/include/bits/ranges_algo.h | 92 ++++++++++++++++
.../testsuite/25_algorithms/shift_left/1.cc | 104 ++++++++++++++++++
.../testsuite/25_algorithms/shift_right/1.cc | 103 +++++++++++++++++
3 files changed, 299 insertions(+)
create mode 100644 libstdc++-v3/testsuite/25_algorithms/shift_left/1.cc
create mode 100644 libstdc++-v3/testsuite/25_algorithms/shift_right/1.cc
diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h
index 7de1072abf0..7d7dbf04103 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -3683,6 +3683,98 @@ namespace ranges
inline constexpr __prev_permutation_fn prev_permutation{};
} // namespace ranges
+
+ template<class ForwardIterator>
+ constexpr ForwardIterator
+ shift_left(ForwardIterator __first, ForwardIterator __last,
+ typename iterator_traits<ForwardIterator>::difference_type __n)
+ {
+ __glibcxx_assert(__n >= 0);
+ if (__n == 0)
+ return __last;
+
+ auto __mid = ranges::next(__first, __n, __last);
+ if (__mid == __last)
+ return __first;
+ return std::move(std::move(__mid), std::move(__last), std::move(__first));
+ }
+
+ template<class ForwardIterator>
+ constexpr ForwardIterator
+ shift_right(ForwardIterator __first, ForwardIterator __last,
+ typename iterator_traits<ForwardIterator>::difference_type __n)
+ {
+ __glibcxx_assert(__n >= 0);
+ if (__n == 0)
+ return __first;
+
+ using _Cat = iterator_traits<ForwardIterator>::iterator_category;
+ if constexpr (derived_from<_Cat, bidirectional_iterator_tag>)
+ {
+ auto __mid = ranges::next(__last, -__n, __first);
+ if (__mid == __first)
+ return __last;
+
+ return std::move_backward(std::move(__first), std::move(__mid),
+ std::move(__last));
+ }
+ else
+ {
+ auto __result = ranges::next(__first, __n, __last);
+ if (__result == __last)
+ return __last;
+
+ auto __dest_head = __first, __dest_tail = __result;
+ while (__dest_head != __result)
+ {
+ if (__dest_tail == __last)
+ {
+ // If we get here, then we must have
+ // 2*n >= distance(__first, __last)
+ // i.e. we are shifting out at least half of the range. In
+ // this case we can safely perform the shift with a single
+ // move.
+ std::move(std::move(__first), std::move(__dest_head),
+ std::move(__result));
+ return __result;
+ }
+ ++__dest_head;
+ ++__dest_tail;
+ }
+
+ for (;;)
+ {
+ // At the start of each iteration of this outer loop, the range
+ // [__first, __result) contains those elements that after shifting
+ // the whole range right by __n, should end up in
+ // [__dest_head, __dest_tail) in order.
+
+ // The below inner loop swaps the elements of [__first, __result)
+ // and [__dest_head, __dest_tail), while simultaneously shifting
+ // the latter range by __n.
+ auto __cursor = __first;
+ while (__cursor != __result)
+ {
+ if (__dest_tail == __last)
+ {
+ // At this point the ranges [__first, result) and
+ // [__dest_head, dest_tail) are disjoint, so we can safely
+ // move the remaining elements.
+ __dest_head = std::move(__cursor, __result,
+ std::move(__dest_head));
+ std::move(std::move(__first), std::move(__cursor),
+ std::move(__dest_head));
+ return __result;
+ }
+ std::iter_swap(__cursor, __dest_head);
+ ++__dest_head;
+ ++__dest_tail;
+ ++__cursor;
+ }
+ }
+ }
+ }
+
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
#endif // concepts
diff --git a/libstdc++-v3/testsuite/25_algorithms/shift_left/1.cc b/libstdc++-v3/testsuite/25_algorithms/shift_left/1.cc
new file mode 100644
index 00000000000..f7a716e0563
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/shift_left/1.cc
@@ -0,0 +1,104 @@
+// 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 <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+using __gnu_test::test_container;
+using __gnu_test::forward_iterator_wrapper;
+using __gnu_test::bidirectional_iterator_wrapper;
+using __gnu_test::random_access_iterator_wrapper;
+
+struct X
+{
+ int a = -1;
+ bool moved_from = false;
+
+ X() = default;
+
+ X(int a)
+ : a(a)
+ { }
+
+ X(const X&) = delete;
+ X& operator=(const X&) = delete;
+
+ X(X&& other)
+ {
+ if (this != &other)
+ *this = std::move(other);
+ }
+
+ X&
+ operator=(X&& other)
+ {
+ a = other.a;
+ other.moved_from = true;
+ moved_from = false;
+ return *this;
+ }
+};
+
+template<int N, template<typename> typename Wrapper>
+void
+test01()
+{
+ for (int n = 0; n < N+5; n++)
+ {
+ X x[N];
+ for (int i = 0; i < N; i++)
+ x[i] = X{i};
+ test_container<X, Wrapper> cx(x);
+ auto out = std::shift_left(cx.begin(), cx.end(), n);
+ if (n < N)
+ {
+ VERIFY( out.ptr == x+(N-n) );
+ for (int i = 0; i < N-n; i++)
+ {
+ VERIFY( x[i].a == n+i );
+ VERIFY( !x[i].moved_from );
+ }
+ for (int i = std::max(n, N-n); i < N; i++)
+ VERIFY( x[i].moved_from );
+ }
+ else
+ {
+ VERIFY( out.ptr == x );
+ for (int i = 0; i < N; i++)
+ {
+ VERIFY( x[i].a == i );
+ VERIFY( !x[i].moved_from );
+ }
+ }
+ }
+}
+
+int
+main()
+{
+ test01<23, forward_iterator_wrapper>();
+ test01<23, bidirectional_iterator_wrapper>();
+ test01<23, random_access_iterator_wrapper>();
+
+ test01<24, forward_iterator_wrapper>();
+ test01<24, bidirectional_iterator_wrapper>();
+ test01<24, random_access_iterator_wrapper>();
+}
diff --git a/libstdc++-v3/testsuite/25_algorithms/shift_right/1.cc b/libstdc++-v3/testsuite/25_algorithms/shift_right/1.cc
new file mode 100644
index 00000000000..cf736ea91b1
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/shift_right/1.cc
@@ -0,0 +1,103 @@
+// 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 <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+using __gnu_test::test_container;
+using __gnu_test::forward_iterator_wrapper;
+using __gnu_test::bidirectional_iterator_wrapper;
+using __gnu_test::random_access_iterator_wrapper;
+
+struct X
+{
+ int a = -1;
+ bool moved_from = false;
+
+ X() = default;
+
+ X(int a)
+ : a(a)
+ { }
+
+ X(const X&) = delete;
+ X& operator=(const X&) = delete;
+
+ X(X&& other)
+ {
+ if (this != &other)
+ *this = std::move(other);
+ }
+
+ X&
+ operator=(X&& other)
+ {
+ a = other.a;
+ other.moved_from = true;
+ moved_from = false;
+ return *this;
+ }
+};
+
+template<int N, template<typename> typename Wrapper>
+void
+test01()
+{
+ for (int n = 0; n < N+5; n++)
+ {
+ X x[N];
+ for (int i = 0; i < N; i++)
+ x[i] = X(i);
+ test_container<X, Wrapper> cx(x);
+ auto out = std::shift_right(cx.begin(), cx.end(), n);
+ if (n < N)
+ {
+ VERIFY( out.ptr == x+n );
+ for (int i = n; i < N; i++)
+ VERIFY( x[i].a == i-n );
+ for (int i = 0; i < std::min(n, N-n); i++)
+ VERIFY( x[i].moved_from );
+ for (int i = std::min(n, N-n); i < std::max(n, N-n); i++)
+ VERIFY( !x[i].moved_from );
+ }
+ else
+ {
+ VERIFY( out.ptr == x+N );
+ for (int i = 0; i < N; i++)
+ {
+ VERIFY( x[i].a == i );
+ VERIFY( !x[i].moved_from );
+ }
+ }
+ }
+}
+
+int
+main()
+{
+ test01<23, forward_iterator_wrapper>();
+ test01<23, bidirectional_iterator_wrapper>();
+ test01<23, random_access_iterator_wrapper>();
+
+ test01<24, forward_iterator_wrapper>();
+ test01<24, bidirectional_iterator_wrapper>();
+ test01<24, random_access_iterator_wrapper>();
+}
--
2.25.1.291.ge68e29171c
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] libstdc++: P0769R2 Add shift to <algorithm>
2020-02-21 21:12 ` Patrick Palka
@ 2020-02-24 13:47 ` Jonathan Wakely
2020-02-24 14:12 ` Patrick Palka
0 siblings, 1 reply; 8+ messages in thread
From: Jonathan Wakely @ 2020-02-24 13:47 UTC (permalink / raw)
To: Patrick Palka; +Cc: gcc-patches, libstdc++
On 21/02/20 16:12 -0500, Patrick Palka wrote:
>On Fri, 21 Feb 2020, Patrick Palka wrote:
>
>> This patch adds std::shift_left and std::shift_right. Alhough these are
>> STL-style algos, they are nonetheless placed in <bits/ranges_algo.h> because
>> they make use of some functions in the ranges namespace that are more easily
>> reachable from <bits/ranges_algo.h> than from <bits/stl_algo.h>, namely
>> ranges::next and ranges::swap_ranges.
>>
>> This implementation of std::shift_right for non-bidirectional iterators deviates
>> from the reference implementation a bit. The main difference is that this
>> implementation is significantly simpler, and yet saves around n/2 additional
>> iterator increments and n/2 iter_moves at the cost of around n/2 additional
>> iter_swaps (where n is the shift amount).
>
>On second thought, this simplification of shift_right is a not a good
>idea because the objects that were shifted and that are no longer a part
>of the new range do not end up in a moved-from state at the end of the
>algorithm. Here is a version of the patch that instead adds something
>akin to the reference implementation and improves the tests to verify
>this moved-from property of both algorithms.
>
>-- >8 --
>
>Subject: [PATCH] libstdc++: P0769R2 Add shift to <algorithm>
>
>This patch adds std::shift_left and std::shift_right as per P0769R2. Alhough
>these are STL-style algos, this patch places them in <bits/ranges_algo.h>
>because they make use of some functions in the ranges namespace that are more
>easily reachable from <bits/ranges_algo.h> than from <bits/stl_algo.h>, namely
>ranges::next. In order to place these algos in <bits/stl_algo.h>, we would need
>to include <bits/range_access.h> from <bits/stl_algo.h> which would undesirably
>increase the size of <bits/stl_algo.h>.
>
>libstdc++-v3/ChangeLog:
>
> P0769R2 Add shift to <algorithm>
> * include/bits/ranges_algo.h (shift_left, shift_right): New.
> * testsuite/25_algorithms/shift_left/1.cc: New test.
> * testsuite/25_algorithms/shift_right/1.cc: New test.
>---
> libstdc++-v3/include/bits/ranges_algo.h | 92 ++++++++++++++++
> .../testsuite/25_algorithms/shift_left/1.cc | 104 ++++++++++++++++++
> .../testsuite/25_algorithms/shift_right/1.cc | 103 +++++++++++++++++
> 3 files changed, 299 insertions(+)
> create mode 100644 libstdc++-v3/testsuite/25_algorithms/shift_left/1.cc
> create mode 100644 libstdc++-v3/testsuite/25_algorithms/shift_right/1.cc
>
>diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h
>index 7de1072abf0..7d7dbf04103 100644
>--- a/libstdc++-v3/include/bits/ranges_algo.h
>+++ b/libstdc++-v3/include/bits/ranges_algo.h
These new algos should go in <bits/stl_algo.h> because they're not in
namespace ranges.
>@@ -3683,6 +3683,98 @@ namespace ranges
> inline constexpr __prev_permutation_fn prev_permutation{};
>
> } // namespace ranges
>+
>+ template<class ForwardIterator>
>+ constexpr ForwardIterator
>+ shift_left(ForwardIterator __first, ForwardIterator __last,
>+ typename iterator_traits<ForwardIterator>::difference_type __n)
>+ {
>+ __glibcxx_assert(__n >= 0);
If I'm reading the current draft correctly, n < 0 is allowed (and does
nothing) so we shouldn't assert here.
>+ if (__n == 0)
>+ return __last;
>+
>+ auto __mid = ranges::next(__first, __n, __last);
>+ if (__mid == __last)
>+ return __first;
>+ return std::move(std::move(__mid), std::move(__last), std::move(__first));
>+ }
>+
>+ template<class ForwardIterator>
>+ constexpr ForwardIterator
>+ shift_right(ForwardIterator __first, ForwardIterator __last,
>+ typename iterator_traits<ForwardIterator>::difference_type __n)
>+ {
>+ __glibcxx_assert(__n >= 0);
Same here.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] libstdc++: P0769R2 Add shift to <algorithm>
2020-02-24 13:47 ` Jonathan Wakely
@ 2020-02-24 14:12 ` Patrick Palka
2020-02-24 14:16 ` Daniel Krügler
2020-02-24 14:28 ` Jonathan Wakely
0 siblings, 2 replies; 8+ messages in thread
From: Patrick Palka @ 2020-02-24 14:12 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: Patrick Palka, gcc-patches, libstdc++
On Mon, 24 Feb 2020, Jonathan Wakely wrote:
> On 21/02/20 16:12 -0500, Patrick Palka wrote:
> > On Fri, 21 Feb 2020, Patrick Palka wrote:
> >
> > > This patch adds std::shift_left and std::shift_right. Alhough these are
> > > STL-style algos, they are nonetheless placed in <bits/ranges_algo.h>
> > > because
> > > they make use of some functions in the ranges namespace that are more
> > > easily
> > > reachable from <bits/ranges_algo.h> than from <bits/stl_algo.h>, namely
> > > ranges::next and ranges::swap_ranges.
> > >
> > > This implementation of std::shift_right for non-bidirectional iterators
> > > deviates
> > > from the reference implementation a bit. The main difference is that this
> > > implementation is significantly simpler, and yet saves around n/2
> > > additional
> > > iterator increments and n/2 iter_moves at the cost of around n/2
> > > additional
> > > iter_swaps (where n is the shift amount).
> >
> > On second thought, this simplification of shift_right is a not a good
> > idea because the objects that were shifted and that are no longer a part
> > of the new range do not end up in a moved-from state at the end of the
> > algorithm. Here is a version of the patch that instead adds something
> > akin to the reference implementation and improves the tests to verify
> > this moved-from property of both algorithms.
> >
> > -- >8 --
> >
> > Subject: [PATCH] libstdc++: P0769R2 Add shift to <algorithm>
> >
> > This patch adds std::shift_left and std::shift_right as per P0769R2.
> > Alhough
> > these are STL-style algos, this patch places them in <bits/ranges_algo.h>
> > because they make use of some functions in the ranges namespace that are
> > more
> > easily reachable from <bits/ranges_algo.h> than from <bits/stl_algo.h>,
> > namely
> > ranges::next. In order to place these algos in <bits/stl_algo.h>, we would
> > need
> > to include <bits/range_access.h> from <bits/stl_algo.h> which would
> > undesirably
> > increase the size of <bits/stl_algo.h>.
> >
> > libstdc++-v3/ChangeLog:
> >
> > P0769R2 Add shift to <algorithm>
> > * include/bits/ranges_algo.h (shift_left, shift_right): New.
> > * testsuite/25_algorithms/shift_left/1.cc: New test.
> > * testsuite/25_algorithms/shift_right/1.cc: New test.
> > ---
> > libstdc++-v3/include/bits/ranges_algo.h | 92 ++++++++++++++++
> > .../testsuite/25_algorithms/shift_left/1.cc | 104 ++++++++++++++++++
> > .../testsuite/25_algorithms/shift_right/1.cc | 103 +++++++++++++++++
> > 3 files changed, 299 insertions(+)
> > create mode 100644 libstdc++-v3/testsuite/25_algorithms/shift_left/1.cc
> > create mode 100644 libstdc++-v3/testsuite/25_algorithms/shift_right/1.cc
> >
> > diff --git a/libstdc++-v3/include/bits/ranges_algo.h
> > b/libstdc++-v3/include/bits/ranges_algo.h
> > index 7de1072abf0..7d7dbf04103 100644
> > --- a/libstdc++-v3/include/bits/ranges_algo.h
> > +++ b/libstdc++-v3/include/bits/ranges_algo.h
>
> These new algos should go in <bits/stl_algo.h> because they're not in
> namespace ranges.
Since their implementation uses ranges::next(__it, __n, __last), putting
them in <bits/stl_algo.h> means we would need to include
<bits/range_access.h> from <bits/stl_algo.h>, or reimplement the
ranges::next() routine in <bits/stl_algo.h> (and its random access
iterator optimization) it seems.
>
> > @@ -3683,6 +3683,98 @@ namespace ranges
> > inline constexpr __prev_permutation_fn prev_permutation{};
> >
> > } // namespace ranges
> > +
> > + template<class ForwardIterator>
> > + constexpr ForwardIterator
> > + shift_left(ForwardIterator __first, ForwardIterator __last,
> > + typename iterator_traits<ForwardIterator>::difference_type __n)
> > + {
> > + __glibcxx_assert(__n >= 0);
>
> If I'm reading the current draft correctly, n < 0 is allowed (and does
> nothing) so we shouldn't assert here.
From what I can tell, this is changed by P1243R4 (Rangify new
algorithms) which adds the precondition n >= 0 to these routines.
>
>
> > + if (__n == 0)
> > + return __last;
> > +
> > + auto __mid = ranges::next(__first, __n, __last);
> > + if (__mid == __last)
> > + return __first;
> > + return std::move(std::move(__mid), std::move(__last),
> > std::move(__first));
> > + }
> > +
> > + template<class ForwardIterator>
> > + constexpr ForwardIterator
> > + shift_right(ForwardIterator __first, ForwardIterator __last,
> > + typename iterator_traits<ForwardIterator>::difference_type
> > __n)
> > + {
> > + __glibcxx_assert(__n >= 0);
>
> Same here.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] libstdc++: P0769R2 Add shift to <algorithm>
2020-02-24 14:12 ` Patrick Palka
@ 2020-02-24 14:16 ` Daniel Krügler
2020-02-24 14:28 ` Jonathan Wakely
1 sibling, 0 replies; 8+ messages in thread
From: Daniel Krügler @ 2020-02-24 14:16 UTC (permalink / raw)
To: Patrick Palka; +Cc: Jonathan Wakely, gcc-patches List, libstdc++
Am Mo., 24. Feb. 2020 um 15:12 Uhr schrieb Patrick Palka <ppalka@redhat.com>:
>
> On Mon, 24 Feb 2020, Jonathan Wakely wrote:
>
[...]
> > > @@ -3683,6 +3683,98 @@ namespace ranges
> > > inline constexpr __prev_permutation_fn prev_permutation{};
> > >
> > > } // namespace ranges
> > > +
> > > + template<class ForwardIterator>
> > > + constexpr ForwardIterator
> > > + shift_left(ForwardIterator __first, ForwardIterator __last,
> > > + typename iterator_traits<ForwardIterator>::difference_type __n)
> > > + {
> > > + __glibcxx_assert(__n >= 0);
> >
> > If I'm reading the current draft correctly, n < 0 is allowed (and does
> > nothing) so we shouldn't assert here.
>
> From what I can tell, this is changed by P1243R4 (Rangify new
> algorithms) which adds the precondition n >= 0 to these routines.
Yes, that's correct. This part of the wording applied the accepted
changes of p1233r1.
- Daniel
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] libstdc++: P0769R2 Add shift to <algorithm>
2020-02-24 14:12 ` Patrick Palka
2020-02-24 14:16 ` Daniel Krügler
@ 2020-02-24 14:28 ` Jonathan Wakely
1 sibling, 0 replies; 8+ messages in thread
From: Jonathan Wakely @ 2020-02-24 14:28 UTC (permalink / raw)
To: Patrick Palka; +Cc: gcc-patches, libstdc++
On 24/02/20 09:12 -0500, Patrick Palka wrote:
>On Mon, 24 Feb 2020, Jonathan Wakely wrote:
>
>> On 21/02/20 16:12 -0500, Patrick Palka wrote:
>> > On Fri, 21 Feb 2020, Patrick Palka wrote:
>> >
>> > > This patch adds std::shift_left and std::shift_right. Alhough these are
>> > > STL-style algos, they are nonetheless placed in <bits/ranges_algo.h>
>> > > because
>> > > they make use of some functions in the ranges namespace that are more
>> > > easily
>> > > reachable from <bits/ranges_algo.h> than from <bits/stl_algo.h>, namely
>> > > ranges::next and ranges::swap_ranges.
>> > >
>> > > This implementation of std::shift_right for non-bidirectional iterators
>> > > deviates
>> > > from the reference implementation a bit. The main difference is that this
>> > > implementation is significantly simpler, and yet saves around n/2
>> > > additional
>> > > iterator increments and n/2 iter_moves at the cost of around n/2
>> > > additional
>> > > iter_swaps (where n is the shift amount).
>> >
>> > On second thought, this simplification of shift_right is a not a good
>> > idea because the objects that were shifted and that are no longer a part
>> > of the new range do not end up in a moved-from state at the end of the
>> > algorithm. Here is a version of the patch that instead adds something
>> > akin to the reference implementation and improves the tests to verify
>> > this moved-from property of both algorithms.
>> >
>> > -- >8 --
>> >
>> > Subject: [PATCH] libstdc++: P0769R2 Add shift to <algorithm>
>> >
>> > This patch adds std::shift_left and std::shift_right as per P0769R2.
>> > Alhough
>> > these are STL-style algos, this patch places them in <bits/ranges_algo.h>
>> > because they make use of some functions in the ranges namespace that are
>> > more
>> > easily reachable from <bits/ranges_algo.h> than from <bits/stl_algo.h>,
>> > namely
>> > ranges::next. In order to place these algos in <bits/stl_algo.h>, we would
>> > need
>> > to include <bits/range_access.h> from <bits/stl_algo.h> which would
>> > undesirably
>> > increase the size of <bits/stl_algo.h>.
>> >
>> > libstdc++-v3/ChangeLog:
>> >
>> > P0769R2 Add shift to <algorithm>
>> > * include/bits/ranges_algo.h (shift_left, shift_right): New.
>> > * testsuite/25_algorithms/shift_left/1.cc: New test.
>> > * testsuite/25_algorithms/shift_right/1.cc: New test.
>> > ---
>> > libstdc++-v3/include/bits/ranges_algo.h | 92 ++++++++++++++++
>> > .../testsuite/25_algorithms/shift_left/1.cc | 104 ++++++++++++++++++
>> > .../testsuite/25_algorithms/shift_right/1.cc | 103 +++++++++++++++++
>> > 3 files changed, 299 insertions(+)
>> > create mode 100644 libstdc++-v3/testsuite/25_algorithms/shift_left/1.cc
>> > create mode 100644 libstdc++-v3/testsuite/25_algorithms/shift_right/1.cc
>> >
>> > diff --git a/libstdc++-v3/include/bits/ranges_algo.h
>> > b/libstdc++-v3/include/bits/ranges_algo.h
>> > index 7de1072abf0..7d7dbf04103 100644
>> > --- a/libstdc++-v3/include/bits/ranges_algo.h
>> > +++ b/libstdc++-v3/include/bits/ranges_algo.h
>>
>> These new algos should go in <bits/stl_algo.h> because they're not in
>> namespace ranges.
>
>Since their implementation uses ranges::next(__it, __n, __last), putting
>them in <bits/stl_algo.h> means we would need to include
><bits/range_access.h> from <bits/stl_algo.h>, or reimplement the
>ranges::next() routine in <bits/stl_algo.h> (and its random access
>iterator optimization) it seems.
Ah right.
>> > @@ -3683,6 +3683,98 @@ namespace ranges
>> > inline constexpr __prev_permutation_fn prev_permutation{};
>> >
>> > } // namespace ranges
>> > +
>> > + template<class ForwardIterator>
>> > + constexpr ForwardIterator
>> > + shift_left(ForwardIterator __first, ForwardIterator __last,
>> > + typename iterator_traits<ForwardIterator>::difference_type __n)
>> > + {
>> > + __glibcxx_assert(__n >= 0);
>>
>> If I'm reading the current draft correctly, n < 0 is allowed (and does
>> nothing) so we shouldn't assert here.
>
From what I can tell, this is changed by P1243R4 (Rangify new
>algorithms) which adds the precondition n >= 0 to these routines.
Thanks, I forgot that paper still changed shuft_left and shift_right
even thogh it didn't add ranges::shift_left and ranges::shift_right.
OK for master then, thanks.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] libstdc++: P0769R2 Add shift to <algorithm>
2020-02-21 19:29 [PATCH] libstdc++: P0769R2 Add shift to <algorithm> Patrick Palka
2020-02-21 21:12 ` Patrick Palka
@ 2020-03-02 9:03 ` Stephan Bergmann
2020-03-02 12:20 ` Jonathan Wakely
1 sibling, 1 reply; 8+ messages in thread
From: Stephan Bergmann @ 2020-03-02 9:03 UTC (permalink / raw)
To: gcc-patches; +Cc: Patrick Palka, libstdc++, jwakely
On 21/02/2020 20:29, Patrick Palka wrote:
> diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h
> index 7de1072abf0..c36afc6e19b 100644
> --- a/libstdc++-v3/include/bits/ranges_algo.h
> +++ b/libstdc++-v3/include/bits/ranges_algo.h
> @@ -3683,6 +3683,54 @@ namespace ranges
> inline constexpr __prev_permutation_fn prev_permutation{};
>
> } // namespace ranges
> +
> + template<class ForwardIterator>
> + constexpr ForwardIterator
> + shift_left(ForwardIterator __first, ForwardIterator __last,
> + typename iterator_traits<ForwardIterator>::difference_type __n)
> + {
> + __glibcxx_assert(__n >= 0);
> + if (__n == 0)
> + return __last;
> +
> + auto __mid = ranges::next(__first, __n, __last);
> + if (__mid == __last)
> + return __first;
> + return std::move(std::move(__mid), std::move(__last), std::move(__first));
> + }
> +
> + template<class ForwardIterator>
> + constexpr ForwardIterator
> + shift_right(ForwardIterator __first, ForwardIterator __last,
> + typename iterator_traits<ForwardIterator>::difference_type __n)
> + {
> + __glibcxx_assert(__n >= 0);
> + if (__n == 0)
> + return __first;
> +
> + using _Cat = iterator_traits<ForwardIterator>::iterator_category;
^ FYI, the above line causes recent Clang 10 trunk with -std=c++20 to
fail due to a "missing" typedef
> + if constexpr (derived_from<_Cat, bidirectional_iterator_tag>)
> + {
> + auto __mid = ranges::next(__last, -__n, __first);
> + if (__mid == __first)
> + return __last;
> + return std::move_backward(std::move(__first), std::move(__mid),
> + std::move(__last));
> + }
> + else
> + {
> + auto __result = ranges::next(__first, __n, __last);
> + if (__result == __last)
> + return __last;
> + auto __dest = __result;
> + do
> + __dest = ranges::swap_ranges(__first, __result,
> + std::move(__dest), __last).in2;
> + while (__dest != __last);
> + return __result;
> + }
> + }
> +
> _GLIBCXX_END_NAMESPACE_VERSION
> } // namespace std
> #endif // concepts
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] libstdc++: P0769R2 Add shift to <algorithm>
2020-03-02 9:03 ` Stephan Bergmann
@ 2020-03-02 12:20 ` Jonathan Wakely
0 siblings, 0 replies; 8+ messages in thread
From: Jonathan Wakely @ 2020-03-02 12:20 UTC (permalink / raw)
To: Stephan Bergmann; +Cc: gcc-patches, Patrick Palka, libstdc++
[-- Attachment #1: Type: text/plain, Size: 1548 bytes --]
On 02/03/20 10:03 +0100, Stephan Bergmann wrote:
>On 21/02/2020 20:29, Patrick Palka wrote:
>>diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h
>>index 7de1072abf0..c36afc6e19b 100644
>>--- a/libstdc++-v3/include/bits/ranges_algo.h
>>+++ b/libstdc++-v3/include/bits/ranges_algo.h
>>@@ -3683,6 +3683,54 @@ namespace ranges
>> inline constexpr __prev_permutation_fn prev_permutation{};
>> } // namespace ranges
>>+
>>+ template<class ForwardIterator>
>>+ constexpr ForwardIterator
>>+ shift_left(ForwardIterator __first, ForwardIterator __last,
>>+ typename iterator_traits<ForwardIterator>::difference_type __n)
>>+ {
>>+ __glibcxx_assert(__n >= 0);
>>+ if (__n == 0)
>>+ return __last;
>>+
>>+ auto __mid = ranges::next(__first, __n, __last);
>>+ if (__mid == __last)
>>+ return __first;
>>+ return std::move(std::move(__mid), std::move(__last), std::move(__first));
>>+ }
>>+
>>+ template<class ForwardIterator>
>>+ constexpr ForwardIterator
>>+ shift_right(ForwardIterator __first, ForwardIterator __last,
>>+ typename iterator_traits<ForwardIterator>::difference_type __n)
>>+ {
>>+ __glibcxx_assert(__n >= 0);
>>+ if (__n == 0)
>>+ return __first;
>>+
>>+ using _Cat = iterator_traits<ForwardIterator>::iterator_category;
>
>^ FYI, the above line causes recent Clang 10 trunk with -std=c++20 to
>fail due to a "missing" typedef
Thanks, fixed by this patch, committed to master now.
[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 909 bytes --]
commit 5fad000324d0bcc87283dc339423bfad6fa42c74
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Mon Mar 2 12:18:45 2020 +0000
libstdc++: Add 'typename' to fix compilation with Clang
* include/bits/ranges_algo.h (shift_right): Add 'typename' to
dependent type.
diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h
index 8fa4a8a9161..a34f75f53d8 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -3710,7 +3710,7 @@ namespace ranges
if (__n == 0)
return __first;
- using _Cat = iterator_traits<ForwardIterator>::iterator_category;
+ using _Cat = typename iterator_traits<ForwardIterator>::iterator_category;
if constexpr (derived_from<_Cat, bidirectional_iterator_tag>)
{
auto __mid = ranges::next(__last, -__n, __first);
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2020-03-02 12:20 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-21 19:29 [PATCH] libstdc++: P0769R2 Add shift to <algorithm> Patrick Palka
2020-02-21 21:12 ` Patrick Palka
2020-02-24 13:47 ` Jonathan Wakely
2020-02-24 14:12 ` Patrick Palka
2020-02-24 14:16 ` Daniel Krügler
2020-02-24 14:28 ` Jonathan Wakely
2020-03-02 9:03 ` Stephan Bergmann
2020-03-02 12:20 ` Jonathan Wakely
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).