[clang-tools-extra] [llvm] [llvm][ADT] Add wrapper to `std::search` and `std::adjacent_find` (PR #171666)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Dec 10 12:52:09 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-tidy
Author: Denis Mikhailov (denzor200)
<details>
<summary>Changes</summary>
---
Full diff: https://github.com/llvm/llvm-project/pull/171666.diff
3 Files Affected:
- (modified) clang-tools-extra/clang-tidy/llvm/UseRangesCheck.cpp (+15-14)
- (modified) llvm/include/llvm/ADT/STLExtras.h (+24)
- (modified) llvm/unittests/ADT/STLExtrasTest.cpp (+157)
``````````diff
diff --git a/clang-tools-extra/clang-tidy/llvm/UseRangesCheck.cpp b/clang-tools-extra/clang-tidy/llvm/UseRangesCheck.cpp
index 2c7a644b7a793..5e7392b09fb33 100644
--- a/clang-tools-extra/clang-tidy/llvm/UseRangesCheck.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/UseRangesCheck.cpp
@@ -57,23 +57,24 @@ utils::UseRangesCheck::ReplacerMap UseRangesCheck::getReplacerMap() const {
// Single range algorithms
AddStdToLLVM(llvm::makeIntrusiveRefCnt<StdToLLVMReplacer>(SingleSig),
- {"all_of", "any_of",
- "none_of", "for_each",
- "find", "find_if",
- "find_if_not", "fill",
- "count", "count_if",
- "copy", "copy_if",
- "transform", "replace",
- "remove_if", "stable_sort",
- "partition", "partition_point",
- "is_sorted", "min_element",
- "max_element", "binary_search",
- "lower_bound", "upper_bound",
- "unique", "uninitialized_copy"});
+ {"all_of", "any_of",
+ "none_of", "for_each",
+ "find", "find_if",
+ "find_if_not", "fill",
+ "count", "count_if",
+ "copy", "copy_if",
+ "transform", "replace",
+ "remove_if", "stable_sort",
+ "partition", "partition_point",
+ "is_sorted", "min_element",
+ "max_element", "binary_search",
+ "lower_bound", "upper_bound",
+ "unique", "uninitialized_copy",
+ "adjacent_find"});
// Two range algorithms
AddStdToLLVM(llvm::makeIntrusiveRefCnt<StdToLLVMReplacer>(TwoSig),
- {"equal", "mismatch", "includes"});
+ {"equal", "mismatch", "includes", "search"});
return Results;
}
diff --git a/llvm/include/llvm/ADT/STLExtras.h b/llvm/include/llvm/ADT/STLExtras.h
index af0e4a36be1b1..9b358b0ac39f6 100644
--- a/llvm/include/llvm/ADT/STLExtras.h
+++ b/llvm/include/llvm/ADT/STLExtras.h
@@ -1778,6 +1778,30 @@ OutputIt copy_if(R &&Range, OutputIt Out, UnaryPredicate P) {
return std::copy_if(adl_begin(Range), adl_end(Range), Out, P);
}
+/// Wrapper for std::search.
+template <typename R1, typename R2> auto search(R1 &&Range1, R2 &&Range2) {
+ return std::search(adl_begin(Range1), adl_end(Range1), adl_begin(Range2),
+ adl_end(Range2));
+}
+
+/// Wrapper for std::search.
+template <typename R1, typename R2, typename BinaryPredicate>
+auto search(R1 &&Range1, R2 &&Range2, BinaryPredicate P) {
+ return std::search(adl_begin(Range1), adl_end(Range1), adl_begin(Range2),
+ adl_end(Range2), P);
+}
+
+/// Wrapper for std::adjacent_find.
+template <typename R> auto adjacent_find(R &&Range) {
+ return std::adjacent_find(adl_begin(Range), adl_end(Range));
+}
+
+/// Wrapper for std::adjacent_find.
+template <typename R, typename BinaryPredicate>
+auto adjacent_find(R &&Range, BinaryPredicate P) {
+ return std::adjacent_find(adl_begin(Range), adl_end(Range), P);
+}
+
/// Return the single value in \p Range that satisfies
/// \p P(<member of \p Range> *, AllowRepeats)->T * returning nullptr
/// when no values or multiple values were found.
diff --git a/llvm/unittests/ADT/STLExtrasTest.cpp b/llvm/unittests/ADT/STLExtrasTest.cpp
index 85567775e4ebd..e91412f88e315 100644
--- a/llvm/unittests/ADT/STLExtrasTest.cpp
+++ b/llvm/unittests/ADT/STLExtrasTest.cpp
@@ -1699,4 +1699,161 @@ struct Bar {};
static_assert(is_incomplete_v<Foo>, "Foo is incomplete");
static_assert(!is_incomplete_v<Bar>, "Bar is defined");
+TEST(STLExtrasTest, Search) {
+ // Test finding a subsequence in the middle
+ std::vector<int> Haystack = {1, 2, 3, 4, 5, 6, 7, 8};
+ std::vector<int> Needle = {4, 5, 6};
+ auto It = llvm::search(Haystack, Needle);
+ EXPECT_NE(It, Haystack.end());
+ EXPECT_EQ(It, Haystack.begin() + 3);
+ EXPECT_THAT(std::vector<int>(It, It + 3), ElementsAre(4, 5, 6));
+
+ // Test finding at the beginning
+ std::vector<int> Needle2 = {1, 2, 3};
+ auto It2 = llvm::search(Haystack, Needle2);
+ EXPECT_NE(It2, Haystack.end());
+ EXPECT_EQ(It2, Haystack.begin());
+ EXPECT_THAT(std::vector<int>(It2, It2 + 3), ElementsAre(1, 2, 3));
+
+ // Test finding at the end
+ std::vector<int> Needle3 = {6, 7, 8};
+ auto It3 = llvm::search(Haystack, Needle3);
+ EXPECT_NE(It3, Haystack.end());
+ EXPECT_EQ(It3, Haystack.begin() + 5);
+ EXPECT_THAT(std::vector<int>(It3, It3 + 3), ElementsAre(6, 7, 8));
+
+ // Test not finding a subsequence
+ std::vector<int> Needle4 = {9, 10, 11};
+ auto It4 = llvm::search(Haystack, Needle4);
+ EXPECT_EQ(It4, Haystack.end());
+
+ // Test with empty needle (should find at beginning)
+ std::vector<int> EmptyNeedle;
+ auto It5 = llvm::search(Haystack, EmptyNeedle);
+ EXPECT_NE(It5, Haystack.end());
+ EXPECT_EQ(It5, Haystack.begin());
+
+ // Test with empty haystack
+ std::vector<int> EmptyHaystack;
+ auto It6 = llvm::search(EmptyHaystack, Needle);
+ EXPECT_EQ(It6, EmptyHaystack.end());
+ // Test with both empty
+ auto It7 = llvm::search(EmptyHaystack, EmptyNeedle);
+ EXPECT_EQ(It7, EmptyHaystack.end());
+ EXPECT_EQ(It7, EmptyHaystack.begin());
+
+ // Test with predicate version
+ std::vector<int> Haystack2 = {10, 20, 30, 40, 50};
+ std::vector<int> Needle5 = {20, 30};
+ std::vector<int> Needle6 = {200, 300};
+ auto It8 =
+ llvm::search(Haystack2, Needle5, [](int a, int b) { return a == b; });
+ EXPECT_NE(It8, Haystack2.end());
+ EXPECT_EQ(It8, Haystack2.begin() + 1);
+
+ // Test with predicate that doesn't match
+ auto It9 =
+ llvm::search(Haystack2, Needle6, [](int a, int b) { return a == b; });
+ EXPECT_EQ(It9, Haystack2.end());
+
+ // Test with StringRef
+ StringRef Str = "Hello, World!";
+ StringRef Sub = "World";
+ auto It10 = llvm::search(Str, Sub);
+ EXPECT_NE(It10, Str.end());
+ EXPECT_EQ(*It10, 'W');
+
+ // Test with ArrayRef
+ ArrayRef<int> ArrRef = Haystack;
+ ArrayRef<int> NeedleRef = Needle;
+ auto It11 = llvm::search(ArrRef, NeedleRef);
+ EXPECT_NE(It11, ArrRef.end());
+ EXPECT_EQ(It11, ArrRef.begin() + 3);
+}
+
+TEST(STLExtrasTest, AdjacentFind) {
+ // Test finding adjacent equal elements
+ std::vector<int> V = {1, 2, 3, 3, 4, 5};
+ auto It = llvm::adjacent_find(V);
+ EXPECT_NE(It, V.end());
+ EXPECT_EQ(It, V.begin() + 2);
+ EXPECT_EQ(*It, 3);
+ EXPECT_EQ(*(It + 1), 3);
+
+ // Test not finding adjacent equal elements
+ std::vector<int> V2 = {1, 2, 3, 4, 5};
+ auto It2 = llvm::adjacent_find(V2);
+ EXPECT_EQ(It2, V2.end());
+
+ // Test finding at the beginning
+ std::vector<int> V3 = {1, 1, 2, 3, 4};
+ auto It3 = llvm::adjacent_find(V3);
+ EXPECT_NE(It3, V3.end());
+ EXPECT_EQ(It3, V3.begin());
+ EXPECT_EQ(*It3, 1);
+ EXPECT_EQ(*(It3 + 1), 1);
+
+ // Test finding at the end
+ std::vector<int> V4 = {1, 2, 3, 4, 5, 5};
+ auto It4 = llvm::adjacent_find(V4);
+ EXPECT_NE(It4, V4.end());
+ EXPECT_EQ(It4, V4.begin() + 4);
+ EXPECT_EQ(*It4, 5);
+ EXPECT_EQ(*(It4 + 1), 5);
+
+ // Test with empty range
+ std::vector<int> Empty;
+ auto It5 = llvm::adjacent_find(Empty);
+ EXPECT_EQ(It5, Empty.end());
+
+ // Test with single element
+ std::vector<int> Single = {42};
+ auto It6 = llvm::adjacent_find(Single);
+ EXPECT_EQ(It6, Single.end());
+
+ // Test with predicate version - finding adjacent elements that satisfy
+ // predicate
+ std::vector<int> V5 = {1, 2, 4, 3, 5, 6};
+ auto It7 = llvm::adjacent_find(V5, [](int a, int b) { return a > b; });
+ EXPECT_NE(It7, V5.end());
+ EXPECT_EQ(It7, V5.begin() + 2);
+ EXPECT_EQ(*It7, 4);
+ EXPECT_EQ(*(It7 + 1), 3);
+
+ // Test with predicate that doesn't match
+ std::vector<int> V6 = {1, 2, 3, 4, 5};
+ auto It8 = llvm::adjacent_find(V6, [](int a, int b) { return a > b; });
+ EXPECT_EQ(It8, V6.end());
+
+ // Test with predicate finding equal elements
+ std::vector<int> V7 = {1, 2, 3, 3, 4};
+ auto It9 = llvm::adjacent_find(V7, [](int a, int b) { return a == b; });
+ EXPECT_NE(It9, V7.end());
+ EXPECT_EQ(It9, V7.begin() + 2);
+
+ // Test with StringRef
+ StringRef Str = "Helo";
+ auto It10 = llvm::adjacent_find(Str);
+ EXPECT_EQ(It10, Str.end());
+
+ StringRef Str2 = "Helllo";
+ auto It11 = llvm::adjacent_find(Str2);
+ EXPECT_NE(It11, Str2.end());
+ EXPECT_EQ(*It11, 'l');
+ EXPECT_EQ(*(It11 + 1), 'l');
+
+ // Test with ArrayRef
+ ArrayRef<int> ArrRef = V;
+ auto It12 = llvm::adjacent_find(ArrRef);
+ EXPECT_NE(It12, ArrRef.end());
+ EXPECT_EQ(It12, ArrRef.begin() + 2);
+
+ // Test with list (non-random access iterator)
+ std::list<int> L = {1, 2, 3, 3, 4, 5};
+ auto It13 = llvm::adjacent_find(L);
+ EXPECT_NE(It13, L.end());
+ EXPECT_EQ(*It13, 3);
+ EXPECT_EQ(*std::next(It13), 3);
+}
+
} // namespace
``````````
</details>
https://github.com/llvm/llvm-project/pull/171666
More information about the llvm-commits
mailing list