[libcxx-commits] [PATCH] D142864: [libc++] `<algorithm>`: `ranges::minmax` should dereference iterators only once
Igor Zhukov via Phabricator via libcxx-commits
libcxx-commits at lists.llvm.org
Sun Jan 29 21:15:31 PST 2023
fsb4000 created this revision.
fsb4000 added a project: libc++.
Herald added a project: All.
fsb4000 requested review of this revision.
Herald added a subscriber: libcxx-commits.
Herald added a reviewer: libc++.
In https://reviews.llvm.org/D135248 `libcxx/test/std/algorithms/alg.sorting/alg.min.max/ranges.minmax.pass.cpp` failed because move_iterator became `random_access_iterator` and `ranges::minmax` now chooses this branch.
We can't do `*__result.first` twice because move_iterator will move the value after the first dereference.
This is basically the same bug as I found in MS STL two days ago: https://github.com/microsoft/STL/pull/3366
How can I create the same testcase for input_iterators branch?
I mean after https://reviews.llvm.org/D135248 will be merged the code:
c++
std::shared_ptr<int> a[] = {std::make_shared<int>(42)};
auto range = std::ranges::subrange(std::move_iterator(a), std::move_iterator(a + 1));
auto [min, max] = std::ranges::minmax(range);
assert(a[0] == nullptr);
assert(min != nullptr);
assert(max == min);
will not test the else branch:
// input_iterators can't be copied, so the implementation for input_iterators has to store
// the values instead of a pointer to the correct values
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D142864
Files:
libcxx/include/__algorithm/ranges_minmax.h
Index: libcxx/include/__algorithm/ranges_minmax.h
===================================================================
--- libcxx/include/__algorithm/ranges_minmax.h
+++ libcxx/include/__algorithm/ranges_minmax.h
@@ -74,6 +74,15 @@
if constexpr (forward_range<_Range>) {
auto __result = std::__minmax_element_impl(__first, __last, __comp, __proj);
+ // We can dereference normal pointers many times but some iterators could move their value after
+ // dereferencing so we should dereference them only once. The if constexpr is a pure optimization, we
+ // don't want an additional branch for normal pointers.
+ if constexpr (!is_pointer_v<iterator_t<_Range>>) {
+ if (__result.first == __result.second) {
+ auto __temp = static_cast<_ValueT>(*__result.first);
+ return {__temp, std::move(__temp)};
+ }
+ }
return {*__result.first, *__result.second};
} else {
// input_iterators can't be copied, so the implementation for input_iterators has to store
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D142864.493196.patch
Type: text/x-patch
Size: 1039 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/libcxx-commits/attachments/20230130/ec1bcf71/attachment.bin>
More information about the libcxx-commits
mailing list