diff --git a/llvm/include/llvm/ADT/ArrayRef.h b/llvm/include/llvm/ADT/ArrayRef.h index 0349623e5f8d..c12688e6dd49 100644 --- a/llvm/include/llvm/ADT/ArrayRef.h +++ b/llvm/include/llvm/ADT/ArrayRef.h @@ -12,6 +12,7 @@ #include "llvm/ADT/Hashing.h" #include "llvm/ADT/None.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include #include @@ -165,12 +166,6 @@ namespace llvm { return std::equal(begin(), end(), RHS.begin()); } - /// slice(n) - Chop off the first N elements of the array. - ArrayRef slice(size_t N) const { - assert(N <= size() && "Invalid specifier"); - return ArrayRef(data()+N, size()-N); - } - /// slice(n, m) - Chop off the first N elements of the array, and keep M /// elements in the array. ArrayRef slice(size_t N, size_t M) const { @@ -178,6 +173,9 @@ namespace llvm { return ArrayRef(data()+N, M); } + /// slice(n) - Chop off the first N elements of the array. + ArrayRef slice(size_t N) const { return slice(N, size() - N); } + /// \brief Drop the first \p N elements of the array. ArrayRef drop_front(size_t N = 1) const { assert(size() >= N && "Dropping more elements than exist"); @@ -190,6 +188,18 @@ namespace llvm { return slice(0, size() - N); } + /// \brief Return a copy of *this with the first N elements satisfying the + /// given predicate removed. + template ArrayRef drop_while(PredicateT Pred) const { + return ArrayRef(find_if_not(*this, Pred), end()); + } + + /// \brief Return a copy of *this with the first N elements not satisfying + /// the given predicate removed. + template ArrayRef drop_until(PredicateT Pred) const { + return ArrayRef(find_if(*this, Pred), end()); + } + /// \brief Return a copy of *this with only the first \p N elements. ArrayRef take_front(size_t N = 1) const { if (N >= size()) @@ -204,6 +214,18 @@ namespace llvm { return drop_front(size() - N); } + /// \brief Return the first N elements of this Array that satisfy the given + /// predicate. + template ArrayRef take_while(PredicateT Pred) const { + return ArrayRef(begin(), find_if_not(*this, Pred)); + } + + /// \brief Return the first N elements of this Array that don't satisfy the + /// given predicate. + template ArrayRef take_until(PredicateT Pred) const { + return ArrayRef(begin(), find_if(*this, Pred)); + } + /// @} /// @name Operator Overloads /// @{ @@ -317,17 +339,16 @@ namespace llvm { return data()[this->size()-1]; } - /// slice(n) - Chop off the first N elements of the array. - MutableArrayRef slice(size_t N) const { - assert(N <= this->size() && "Invalid specifier"); - return MutableArrayRef(data()+N, this->size()-N); - } - /// slice(n, m) - Chop off the first N elements of the array, and keep M /// elements in the array. MutableArrayRef slice(size_t N, size_t M) const { - assert(N+M <= this->size() && "Invalid specifier"); - return MutableArrayRef(data()+N, M); + assert(N + M <= this->size() && "Invalid specifier"); + return MutableArrayRef(this->data() + N, M); + } + + /// slice(n) - Chop off the first N elements of the array. + MutableArrayRef slice(size_t N) const { + return slice(N, this->size() - N); } /// \brief Drop the first \p N elements of the array. @@ -341,6 +362,20 @@ namespace llvm { return slice(0, this->size() - N); } + /// \brief Return a copy of *this with the first N elements satisfying the + /// given predicate removed. + template + MutableArrayRef drop_while(PredicateT Pred) const { + return MutableArrayRef(find_if_not(*this, Pred), end()); + } + + /// \brief Return a copy of *this with the first N elements not satisfying + /// the given predicate removed. + template + MutableArrayRef drop_until(PredicateT Pred) const { + return MutableArrayRef(find_if(*this, Pred), end()); + } + /// \brief Return a copy of *this with only the first \p N elements. MutableArrayRef take_front(size_t N = 1) const { if (N >= this->size()) @@ -355,6 +390,20 @@ namespace llvm { return drop_front(this->size() - N); } + /// \brief Return the first N elements of this Array that satisfy the given + /// predicate. + template + MutableArrayRef take_while(PredicateT Pred) const { + return MutableArrayRef(begin(), find_if_not(*this, Pred)); + } + + /// \brief Return the first N elements of this Array that don't satisfy the + /// given predicate. + template + MutableArrayRef take_until(PredicateT Pred) const { + return MutableArrayRef(begin(), find_if(*this, Pred)); + } + /// @} /// @name Operator Overloads /// @{ diff --git a/llvm/include/llvm/ADT/STLExtras.h b/llvm/include/llvm/ADT/STLExtras.h index 1d3242dfb07f..f11a2fc5943f 100644 --- a/llvm/include/llvm/ADT/STLExtras.h +++ b/llvm/include/llvm/ADT/STLExtras.h @@ -622,6 +622,11 @@ auto find_if(R &&Range, const T &Pred) -> decltype(Range.begin()) { return std::find_if(Range.begin(), Range.end(), Pred); } +template +auto find_if_not(R &&Range, PredicateT Pred) -> decltype(Range.begin()) { + return std::find_if_not(Range.begin(), Range.end(), Pred); +} + /// Provide wrappers to std::remove_if which take ranges instead of having to /// pass begin/end explicitly. template diff --git a/llvm/unittests/ADT/ArrayRefTest.cpp b/llvm/unittests/ADT/ArrayRefTest.cpp index ca75800f0925..65b4cbcd6689 100644 --- a/llvm/unittests/ADT/ArrayRefTest.cpp +++ b/llvm/unittests/ADT/ArrayRefTest.cpp @@ -102,6 +102,28 @@ TEST(ArrayRefTest, DropFront) { EXPECT_EQ(1U, AR3.drop_front(AR3.size() - 1).size()); } +TEST(ArrayRefTest, DropWhile) { + static const int TheNumbers[] = {1, 3, 5, 8, 10, 11}; + ArrayRef AR1(TheNumbers); + ArrayRef Expected = AR1.drop_front(3); + EXPECT_EQ(Expected, AR1.drop_while([](const int &N) { return N % 2 == 1; })); + + EXPECT_EQ(AR1, AR1.drop_while([](const int &N) { return N < 0; })); + EXPECT_EQ(ArrayRef(), + AR1.drop_while([](const int &N) { return N > 0; })); +} + +TEST(ArrayRefTest, DropUntil) { + static const int TheNumbers[] = {1, 3, 5, 8, 10, 11}; + ArrayRef AR1(TheNumbers); + ArrayRef Expected = AR1.drop_front(3); + EXPECT_EQ(Expected, AR1.drop_until([](const int &N) { return N % 2 == 0; })); + + EXPECT_EQ(ArrayRef(), + AR1.drop_until([](const int &N) { return N < 0; })); + EXPECT_EQ(AR1, AR1.drop_until([](const int &N) { return N > 0; })); +} + TEST(ArrayRefTest, TakeBack) { static const int TheNumbers[] = {4, 8, 15, 16, 23, 42}; ArrayRef AR1(TheNumbers); @@ -116,6 +138,28 @@ TEST(ArrayRefTest, TakeFront) { EXPECT_TRUE(AR1.take_front(2).equals(AR2)); } +TEST(ArrayRefTest, TakeWhile) { + static const int TheNumbers[] = {1, 3, 5, 8, 10, 11}; + ArrayRef AR1(TheNumbers); + ArrayRef Expected = AR1.take_front(3); + EXPECT_EQ(Expected, AR1.take_while([](const int &N) { return N % 2 == 1; })); + + EXPECT_EQ(ArrayRef(), + AR1.take_while([](const int &N) { return N < 0; })); + EXPECT_EQ(AR1, AR1.take_while([](const int &N) { return N > 0; })); +} + +TEST(ArrayRefTest, TakeUntil) { + static const int TheNumbers[] = {1, 3, 5, 8, 10, 11}; + ArrayRef AR1(TheNumbers); + ArrayRef Expected = AR1.take_front(3); + EXPECT_EQ(Expected, AR1.take_until([](const int &N) { return N % 2 == 0; })); + + EXPECT_EQ(AR1, AR1.take_until([](const int &N) { return N < 0; })); + EXPECT_EQ(ArrayRef(), + AR1.take_until([](const int &N) { return N > 0; })); +} + TEST(ArrayRefTest, Equals) { static const int A1[] = {1, 2, 3, 4, 5, 6, 7, 8}; ArrayRef AR1(A1);