diff --git a/llvm/include/llvm/ADT/STLExtras.h b/llvm/include/llvm/ADT/STLExtras.h index 23da931a63de1..3057c187bcf15 100644 --- a/llvm/include/llvm/ADT/STLExtras.h +++ b/llvm/include/llvm/ADT/STLExtras.h @@ -1975,6 +1975,14 @@ template bool is_sorted(R &&Range) { return std::is_sorted(adl_begin(Range), adl_end(Range)); } +/// Check if elements in a range \p R are sorted with respect to a comparator \p +/// C. constexpr allows use in static_assert +/// TODO: Remove and use std::is_sorted once upgraded to Cpp20 +template > +constexpr bool is_sorted_constexpr(R &&Range, Cmp C = Cmp{}) { + return llvm::is_sorted_constexpr(adl_begin(Range), adl_end(Range), C); +} + /// Provide wrappers to std::includes which take ranges instead of having to /// pass begin/end explicitly. /// This function checks if the sorted range \p R2 is a subsequence of the diff --git a/llvm/include/llvm/ADT/STLForwardCompat.h b/llvm/include/llvm/ADT/STLForwardCompat.h index d61c880747502..a02b7f7a8a410 100644 --- a/llvm/include/llvm/ADT/STLForwardCompat.h +++ b/llvm/include/llvm/ADT/STLForwardCompat.h @@ -18,6 +18,7 @@ #define LLVM_ADT_STLFORWARDCOMPAT_H #include "llvm/Support/Compiler.h" +#include #include #include #include @@ -158,6 +159,23 @@ invoke(FnT &&Fn, ArgsT &&...Args) { // NOLINT(readability-identifier-naming) std::forward_as_tuple(std::forward(Args)...)); } +/// Check if elements in range \p First to \p Last are sorted with respect to a +/// comparator \p C. constexpr allows use in static_assert +/// TODO: Use std::is_sorted once upgraded to C++20 since that becomes constexpr +template > +constexpr bool is_sorted_constexpr(ForwardIterator First, ForwardIterator Last, + Cmp C = Cmp{}) { + if (First == Last) + return true; + ForwardIterator Prev = First; + for (ForwardIterator I = std::next(First); I != Last; ++I) { + if (C(*I, *Prev)) + return false; + Prev = I; + } + return true; +} + //===----------------------------------------------------------------------===// // Features from C++23 //===----------------------------------------------------------------------===// diff --git a/llvm/unittests/ADT/STLExtrasTest.cpp b/llvm/unittests/ADT/STLExtrasTest.cpp index fe71945e4a794..cc9ae25800f58 100644 --- a/llvm/unittests/ADT/STLExtrasTest.cpp +++ b/llvm/unittests/ADT/STLExtrasTest.cpp @@ -1937,4 +1937,14 @@ TEST(STLExtrasTest, AdjacentFind) { EXPECT_EQ(*std::next(It13), 3); } +// Compile-time tests for llvm::is_sorted_constexpr +// Check to ensure range based functions as expected +static constexpr std::array CSorted{{1, 2, 2, 3, 5}}; +static_assert(llvm::is_sorted_constexpr(CSorted), + "Non-descending order with duplicates should be sorted"); +static_assert(llvm::is_sorted_constexpr(CSorted, std::less<>()), + "Explicit std::less non-descending order should be sorted"); +static_assert(!llvm::is_sorted_constexpr(CSorted, std::greater<>()), + "Non-descending order should not be sorted by std::greater"); + } // namespace diff --git a/llvm/unittests/ADT/STLForwardCompatTest.cpp b/llvm/unittests/ADT/STLForwardCompatTest.cpp index 8831062109cb3..68976a7fede45 100644 --- a/llvm/unittests/ADT/STLForwardCompatTest.cpp +++ b/llvm/unittests/ADT/STLForwardCompatTest.cpp @@ -10,6 +10,7 @@ #include "CountCopyAndMove.h" #include "gtest/gtest.h" +#include #include #include #include @@ -605,5 +606,40 @@ TEST(STLForwardCompatTest, BindFrontBindBack) { EXPECT_TRUE(any_of(V, Spec1)); } +// Compile-time tests for llvm::is_sorted_constexpr +static constexpr int CEmptyHelper[]{-1}; +static_assert(llvm::is_sorted_constexpr(std::begin(CEmptyHelper), + std::begin(CEmptyHelper)), + "Empty range should be sorted"); + +static constexpr int CSingle[]{42}; +static_assert(llvm::is_sorted_constexpr(std::begin(CSingle), std::end(CSingle)), + "Single element range should be sorted"); +static_assert(llvm::is_sorted_constexpr(std::begin(CSingle), std::end(CSingle), + std::greater<>()), + "Single element range should be sorted with std::greater"); + +static constexpr int CSorted[]{1, 2, 2, 3, 5}; +static_assert(llvm::is_sorted_constexpr(std::begin(CSorted), std::end(CSorted)), + "Non-descending order with duplicates should be sorted"); +static_assert(llvm::is_sorted_constexpr(std::begin(CSorted), std::end(CSorted), + std::less<>()), + "Explicit std::less non-descending order should be sorted"); +static_assert(!llvm::is_sorted_constexpr(std::begin(CSorted), std::end(CSorted), + std::greater<>()), + "Non-descending order should not be sorted by std::greater"); + +static constexpr int CUnsorted[]{1, 3, 2, 4, 5}; +static_assert(!llvm::is_sorted_constexpr(std::begin(CUnsorted), + std::end(CUnsorted)), + "Unsorted range should not be sorted"); + +static constexpr int CDesc[]{9, 7, 7, 3, 0}; +static_assert(llvm::is_sorted_constexpr(std::begin(CDesc), std::end(CDesc), + std::greater<>()), + "Non-ascending order with std::greater should be sorted"); +static_assert(llvm::is_sorted_constexpr(std::rbegin(CDesc), std::rend(CDesc)), + "Reverse iterators should be supported."); + } // namespace } // namespace llvm