diff options
author | Patrick Palka <ppalka@redhat.com> | 2024-12-13 13:17:29 -0500 |
---|---|---|
committer | Patrick Palka <ppalka@redhat.com> | 2024-12-13 13:17:29 -0500 |
commit | b8314ebff2495ee22f9e2203093bdada9843a0f5 (patch) | |
tree | 79cf37a1df2d3352c97ffb172a34c1aaac68ad0e | |
parent | 2089009210a1774c37e527ead8bbcaaa1a7a9d2d (diff) | |
download | gcc-b8314ebff2495ee22f9e2203093bdada9843a0f5.zip gcc-b8314ebff2495ee22f9e2203093bdada9843a0f5.tar.gz gcc-b8314ebff2495ee22f9e2203093bdada9843a0f5.tar.bz2 |
libstdc++: Avoid unnecessary copies in ranges::min/max [PR112349]
Use a local reference for the (now possibly lifetime extended) result of
*__first so that we copy it only when necessary.
PR libstdc++/112349
libstdc++-v3/ChangeLog:
* include/bits/ranges_algo.h (__min_fn::operator()): Turn local
object __tmp into a reference.
* include/bits/ranges_util.h (__max_fn::operator()): Likewise.
* testsuite/25_algorithms/max/constrained.cc (test04): New test.
* testsuite/25_algorithms/min/constrained.cc (test04): New test.
Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
-rw-r--r-- | libstdc++-v3/include/bits/ranges_algo.h | 4 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/ranges_util.h | 4 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/25_algorithms/max/constrained.cc | 25 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/25_algorithms/min/constrained.cc | 25 |
4 files changed, 54 insertions, 4 deletions
diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h index 80d4f5a..772bf4d 100644 --- a/libstdc++-v3/include/bits/ranges_algo.h +++ b/libstdc++-v3/include/bits/ranges_algo.h @@ -2952,11 +2952,11 @@ namespace ranges auto __result = *__first; while (++__first != __last) { - auto __tmp = *__first; + auto&& __tmp = *__first; if (std::__invoke(__comp, std::__invoke(__proj, __result), std::__invoke(__proj, __tmp))) - __result = std::move(__tmp); + __result = std::forward<decltype(__tmp)>(__tmp); } return __result; } diff --git a/libstdc++-v3/include/bits/ranges_util.h b/libstdc++-v3/include/bits/ranges_util.h index 7be76e0..b7a3c7a 100644 --- a/libstdc++-v3/include/bits/ranges_util.h +++ b/libstdc++-v3/include/bits/ranges_util.h @@ -757,11 +757,11 @@ namespace ranges auto __result = *__first; while (++__first != __last) { - auto __tmp = *__first; + auto&& __tmp = *__first; if (std::__invoke(__comp, std::__invoke(__proj, __tmp), std::__invoke(__proj, __result))) - __result = std::move(__tmp); + __result = std::forward<decltype(__tmp)>(__tmp); } return __result; } diff --git a/libstdc++-v3/testsuite/25_algorithms/max/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/max/constrained.cc index e7269e1..ad2d47f 100644 --- a/libstdc++-v3/testsuite/25_algorithms/max/constrained.cc +++ b/libstdc++-v3/testsuite/25_algorithms/max/constrained.cc @@ -73,10 +73,35 @@ test03() VERIFY( ranges::max({2,3,1,4}, ranges::greater{}, std::negate<>{}) == 4 ); } +void +test04() +{ + // PR libstdc++/112349 - ranges::max/min make unnecessary copies + static int copies, moves; + struct A { + A(int m) : m(m) { } + A(const A& other) : m(other.m) { ++copies; } + A(A&& other) : m(other.m) { ++moves; } + A& operator=(const A& other) { m = other.m; ++copies; return *this; } + A& operator=(A&& other) { m = other.m; ++moves; return *this; } + int m; + }; + A r[5] = {5, 4, 3, 2, 1}; + ranges::max(r, ranges::less{}, &A::m); + VERIFY( copies == 1 ); + VERIFY( moves == 0 ); + copies = moves = 0; + A s[5] = {1, 2, 3, 4, 5}; + ranges::max(s, ranges::less{}, &A::m); + VERIFY( copies == 5 ); + VERIFY( moves == 0 ); +} + int main() { test01(); test02(); test03(); + test04(); } diff --git a/libstdc++-v3/testsuite/25_algorithms/min/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/min/constrained.cc index 7198df6..17048fd 100644 --- a/libstdc++-v3/testsuite/25_algorithms/min/constrained.cc +++ b/libstdc++-v3/testsuite/25_algorithms/min/constrained.cc @@ -73,10 +73,35 @@ test03() VERIFY( ranges::min({2,3,1,4}, ranges::greater{}, std::negate<>{}) == 1 ); } +void +test04() +{ + // PR libstdc++/112349 - ranges::max/min make unnecessary copies + static int copies, moves; + struct A { + A(int m) : m(m) { } + A(const A& other) : m(other.m) { ++copies; } + A(A&& other) : m(other.m) { ++moves; } + A& operator=(const A& other) { m = other.m; ++copies; return *this; } + A& operator=(A&& other) { m = other.m; ++moves; return *this; } + int m; + }; + A r[5] = {5, 4, 3, 2, 1}; + ranges::min(r, ranges::less{}, &A::m); + VERIFY( copies == 5 ); + VERIFY( moves == 0 ); + copies = moves = 0; + A s[5] = {1, 2, 3, 4, 5}; + ranges::min(s, ranges::less{}, &A::m); + VERIFY( copies == 1 ); + VERIFY( moves == 0 ); +} + int main() { test01(); test02(); test03(); + test04(); } |