[gcc r14-11174] libstdc++: Avoid unnecessary copies in ranges::min/max [PR112349]
Patrick Palka
ppalka@gcc.gnu.org
Thu Jan 9 23:47:55 GMT 2025
https://gcc.gnu.org/g:f236c897af48c3ae52095a894d57e66065b8ad87
commit r14-11174-gf236c897af48c3ae52095a894d57e66065b8ad87
Author: Patrick Palka <ppalka@redhat.com>
Date: Fri Dec 13 13:17:29 2024 -0500
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>
(cherry picked from commit b8314ebff2495ee22f9e2203093bdada9843a0f5)
Diff:
---
libstdc++-v3/include/bits/ranges_algo.h | 4 ++--
libstdc++-v3/include/bits/ranges_util.h | 4 ++--
.../testsuite/25_algorithms/max/constrained.cc | 25 ++++++++++++++++++++++
.../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 6347ec98606a..a29d387dc711 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -2909,11 +2909,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 34d8b1e8f143..aba5b6a88c0c 100644
--- a/libstdc++-v3/include/bits/ranges_util.h
+++ b/libstdc++-v3/include/bits/ranges_util.h
@@ -733,11 +733,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 e7269e1b734a..ad2d47f2f101 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 7198df69adf7..17048fda6394 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();
}
More information about the Libstdc++-cvs
mailing list