[libcxx-commits] [PATCH] D145287: [libc++] Fix ranges::binary_search() returning true for cases where the element is not in the range

Nikolas Klauser via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Fri Mar 3 16:40:45 PST 2023


philnik created this revision.
philnik added reviewers: ldionne, Mordante.
Herald added a project: All.
philnik requested review of this revision.
Herald added a project: libc++.
Herald added a subscriber: libcxx-commits.
Herald added a reviewer: libc++.

Fixes #61160


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D145287

Files:
  libcxx/include/__algorithm/ranges_binary_search.h
  libcxx/test/std/algorithms/alg.sorting/alg.binary.search/binary.search/ranges.binary_search.pass.cpp
  libcxx/test/std/algorithms/alg.sorting/alg.binary.search/lower.bound/ranges.lower_bound.pass.cpp
  libcxx/test/std/algorithms/alg.sorting/alg.binary.search/upper.bound/ranges.upper_bound.pass.cpp


Index: libcxx/test/std/algorithms/alg.sorting/alg.binary.search/upper.bound/ranges.upper_bound.pass.cpp
===================================================================
--- libcxx/test/std/algorithms/alg.sorting/alg.binary.search/upper.bound/ranges.upper_bound.pass.cpp
+++ libcxx/test/std/algorithms/alg.sorting/alg.binary.search/upper.bound/ranges.upper_bound.pass.cpp
@@ -193,6 +193,20 @@
       assert(base(ret) == a + 1);
     }
   }
+
+  { // check that the middle of a range is returned when there are smaller and larger elements
+    {
+      int a[] = {1, 2, 3, 4, 6, 7, 8};
+      auto ret = std::ranges::upper_bound(It(a), It(a + 7), 5);
+      assert(base(ret) == a + 4);
+    }
+    {
+      int a[] = {1, 2, 3, 4, 6, 7, 8};
+      auto range = std::ranges::subrange(It(a), It(a + 7));
+      auto ret = std::ranges::upper_bound(range, 5);
+      assert(base(ret) == a + 4);
+    }
+  }
 }
 
 constexpr bool test() {
Index: libcxx/test/std/algorithms/alg.sorting/alg.binary.search/lower.bound/ranges.lower_bound.pass.cpp
===================================================================
--- libcxx/test/std/algorithms/alg.sorting/alg.binary.search/lower.bound/ranges.lower_bound.pass.cpp
+++ libcxx/test/std/algorithms/alg.sorting/alg.binary.search/lower.bound/ranges.lower_bound.pass.cpp
@@ -194,6 +194,20 @@
       assert(base(ret) == a);
     }
   }
+
+  { // check that the middle of a range is returned when there are smaller and larger elements
+    {
+      int a[] = {1, 2, 3, 4, 6, 7, 8};
+      auto ret = std::ranges::lower_bound(It(a), It(a + 7), 5);
+      assert(base(ret) == a + 4);
+    }
+    {
+      int a[] = {1, 2, 3, 4, 6, 7, 8};
+      auto range = std::ranges::subrange(It(a), It(a + 7));
+      auto ret = std::ranges::lower_bound(range, 5);
+      assert(base(ret) == a + 4);
+    }
+  }
 }
 
 constexpr bool test() {
Index: libcxx/test/std/algorithms/alg.sorting/alg.binary.search/binary.search/ranges.binary_search.pass.cpp
===================================================================
--- libcxx/test/std/algorithms/alg.sorting/alg.binary.search/binary.search/ranges.binary_search.pass.cpp
+++ libcxx/test/std/algorithms/alg.sorting/alg.binary.search/binary.search/ranges.binary_search.pass.cpp
@@ -131,6 +131,13 @@
     auto range = std::ranges::subrange(It(a), Sent(It(a + 5)));
     assert(std::ranges::binary_search(range, 1));
   }
+
+  { // check that false is returned when the element doesn't exist, but an element with a greater value is in the range
+    int a[] = {1, 2, 4};
+    assert(!std::ranges::binary_search(It(a), Sent(It(a + 3)), 3));
+    auto range = std::ranges::subrange(It(a), Sent(It(a + 3)));
+    assert(!std::ranges::binary_search(range, 3));
+  }
 }
 
 constexpr bool test() {
Index: libcxx/include/__algorithm/ranges_binary_search.h
===================================================================
--- libcxx/include/__algorithm/ranges_binary_search.h
+++ libcxx/include/__algorithm/ranges_binary_search.h
@@ -36,7 +36,7 @@
   _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr
   bool operator()(_Iter __first, _Sent __last, const _Type& __value, _Comp __comp = {}, _Proj __proj = {}) const {
     auto __ret = std::__lower_bound_impl<_RangeAlgPolicy>(__first, __last, __value, __comp, __proj);
-    return __ret != __last && !std::invoke(__comp, __value, std::invoke(__proj, *__first));
+    return __ret != __last && !std::invoke(__comp, __value, std::invoke(__proj, *__ret));
   }
 
   template <forward_range _Range, class _Type, class _Proj = identity,
@@ -46,7 +46,7 @@
     auto __first = ranges::begin(__r);
     auto __last = ranges::end(__r);
     auto __ret = std::__lower_bound_impl<_RangeAlgPolicy>(__first, __last, __value, __comp, __proj);
-    return __ret != __last && !std::invoke(__comp, __value, std::invoke(__proj, *__first));
+    return __ret != __last && !std::invoke(__comp, __value, std::invoke(__proj, *__ret));
   }
 };
 } // namespace __binary_search


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D145287.502313.patch
Type: text/x-patch
Size: 3971 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/libcxx-commits/attachments/20230304/376b412a/attachment.bin>


More information about the libcxx-commits mailing list