1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 10:42:39 +01:00

[ADT] Enhance the PriorityWorklist to support bulk insertion.

This is both convenient and more efficient as we can skip any
intermediate reallocation of the vector.

This usage pattern came up in a subsequent patch on the pass manager,
but it seems generically useful so I factored it out and added unittests
here.

llvm-svn: 290952
This commit is contained in:
Chandler Carruth 2017-01-04 11:13:11 +00:00
parent 53828bbf87
commit 5c979966df
2 changed files with 74 additions and 0 deletions

View File

@ -18,6 +18,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Sequence.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Compiler.h"
#include <algorithm>
@ -107,6 +108,35 @@ public:
return false;
}
/// Insert a sequence of new elements into the PriorityWorklist.
template <typename SequenceT>
typename std::enable_if<!std::is_convertible<SequenceT, T>::value>::type
insert(SequenceT &&Input) {
// First pull the input sequence into the vector as a bulk append
// operation.
ptrdiff_t StartIndex = V.size();
V.insert(V.end(), std::begin(Input), std::end(Input));
// Now walk backwards fixing up the index map and deleting any duplicates.
for (auto i : reverse(seq<ptrdiff_t>(StartIndex, V.size()))) {
auto InsertResult = M.insert({V[i], i});
if (InsertResult.second)
continue;
// If the existing index is before this insert's start, nuke that one and
// move it up.
ptrdiff_t &Index = InsertResult.first->second;
if (Index < StartIndex) {
V[Index] = T();
Index = i;
continue;
}
// Otherwise the existing one comes first so just clear out the value in
// this slot.
V[i] = T();
}
}
/// Remove the last element of the PriorityWorklist.
void pop_back() {
assert(!empty() && "Cannot remove an element when empty!");
@ -169,6 +199,11 @@ public:
return true;
}
/// Reverse the items in the PriorityWorklist.
///
/// This does an in-place reversal. Other kinds of reverse aren't easy to
/// support in the face of the worklist semantics.
/// Completely clear the PriorityWorklist
void clear() {
M.clear();

View File

@ -13,6 +13,8 @@
#include "llvm/ADT/PriorityWorklist.h"
#include "gtest/gtest.h"
#include <list>
#include <vector>
namespace {
@ -72,6 +74,43 @@ TYPED_TEST(PriorityWorklistTest, Basic) {
EXPECT_TRUE(W.empty());
}
TYPED_TEST(PriorityWorklistTest, InsertSequence) {
TypeParam W;
ASSERT_TRUE(W.insert(2));
ASSERT_TRUE(W.insert(4));
ASSERT_TRUE(W.insert(7));
// Insert a sequence that has internal duplicates and a duplicate among
// existing entries.
W.insert(std::vector<int>({42, 13, 42, 7, 8}));
EXPECT_EQ(8, W.pop_back_val());
EXPECT_EQ(7, W.pop_back_val());
EXPECT_EQ(42, W.pop_back_val());
EXPECT_EQ(13, W.pop_back_val());
EXPECT_EQ(4, W.pop_back_val());
EXPECT_EQ(2, W.pop_back_val());
ASSERT_TRUE(W.empty());
// Simpler tests with various other input types.
ASSERT_TRUE(W.insert(2));
ASSERT_TRUE(W.insert(7));
// Use a non-random-access container.
W.insert(std::list<int>({7, 5}));
EXPECT_EQ(5, W.pop_back_val());
EXPECT_EQ(7, W.pop_back_val());
EXPECT_EQ(2, W.pop_back_val());
ASSERT_TRUE(W.empty());
ASSERT_TRUE(W.insert(2));
ASSERT_TRUE(W.insert(7));
// Use a raw array.
int A[] = {7, 5};
W.insert(A);
EXPECT_EQ(5, W.pop_back_val());
EXPECT_EQ(7, W.pop_back_val());
EXPECT_EQ(2, W.pop_back_val());
ASSERT_TRUE(W.empty());
}
TYPED_TEST(PriorityWorklistTest, EraseIf) {
TypeParam W;
W.insert(23);