diff options
author | Sam McCall <sam.mccall@gmail.com> | 2018-10-04 13:12:23 +0000 |
---|---|---|
committer | Sam McCall <sam.mccall@gmail.com> | 2018-10-04 13:12:23 +0000 |
commit | 87f69eaf4e5022aa98b4b8c340efb72101fd16f5 (patch) | |
tree | ce4f11a633ad7793d75dc2d1229a3443ab84b7f9 /clang-tools-extra/unittests/clangd/DexTests.cpp | |
parent | 82a3b1c687472d805498276cfb0a41f4c3e616e2 (diff) | |
download | bcm5719-llvm-87f69eaf4e5022aa98b4b8c340efb72101fd16f5.tar.gz bcm5719-llvm-87f69eaf4e5022aa98b4b8c340efb72101fd16f5.zip |
[clangd] Dex: FALSE iterator, peephole optimizations, fix AND bug
Summary:
The FALSE iterator will be used in a followup patch to fix a logic bug in Dex
(currently, tokens that don't have posting lists in the index are simply dropped
from the query, changing semantics).
It can usually be optimized away, so added the following opmitizations:
- simplify booleans inside AND/OR
- replace effectively-empty AND/OR with booleans
- flatten nested AND/ORs
While working on this, found a bug in the AND iterator: its constructor sync()
assumes that ReachedEnd is set if applicable, but the constructor never sets it.
This crashes if a non-first iterator is nonempty.
Reviewers: ilya-biryukov
Subscribers: ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D52789
llvm-svn: 343774
Diffstat (limited to 'clang-tools-extra/unittests/clangd/DexTests.cpp')
-rw-r--r-- | clang-tools-extra/unittests/clangd/DexTests.cpp | 58 |
1 files changed, 46 insertions, 12 deletions
diff --git a/clang-tools-extra/unittests/clangd/DexTests.cpp b/clang-tools-extra/unittests/clangd/DexTests.cpp index d1d5b4c7eeb..c36573c1a80 100644 --- a/clang-tools-extra/unittests/clangd/DexTests.cpp +++ b/clang-tools-extra/unittests/clangd/DexTests.cpp @@ -109,6 +109,18 @@ TEST(DexIterators, AndThreeLists) { EXPECT_TRUE(And->reachedEnd()); } +TEST(DexIterators, AndEmpty) { + Corpus C{10000}; + const PostingList L1({1}); + const PostingList L2({2}); + // These iterators are empty, but the optimizer can't tell. + auto Empty1 = C.intersect(L1.iterator(), L2.iterator()); + auto Empty2 = C.intersect(L1.iterator(), L2.iterator()); + // And syncs iterators on construction, and used to fail on empty children. + auto And = C.intersect(std::move(Empty1), std::move(Empty2)); + EXPECT_TRUE(And->reachedEnd()); +} + TEST(DexIterators, OrTwoLists) { Corpus C{10000}; const PostingList L0({0, 5, 7, 10, 42, 320, 9000}); @@ -270,18 +282,8 @@ TEST(DexIterators, Limit) { } TEST(DexIterators, True) { - Corpus C{0}; - auto TrueIterator = C.all(); - EXPECT_TRUE(TrueIterator->reachedEnd()); - EXPECT_THAT(consumeIDs(*TrueIterator), ElementsAre()); - - C = Corpus{7}; - const PostingList L0({1, 2, 5, 7}); - TrueIterator = C.all(); - EXPECT_THAT(TrueIterator->peek(), 0); - auto AndIterator = C.intersect(L0.iterator(), move(TrueIterator)); - EXPECT_FALSE(AndIterator->reachedEnd()); - EXPECT_THAT(consumeIDs(*AndIterator), ElementsAre(1, 2, 5)); + EXPECT_TRUE(Corpus{0}.all()->reachedEnd()); + EXPECT_THAT(consumeIDs(*Corpus{4}.all()), ElementsAre(0, 1, 2, 3)); } TEST(DexIterators, Boost) { @@ -313,6 +315,38 @@ TEST(DexIterators, Boost) { EXPECT_THAT(ElementBoost, 3); } +TEST(DexIterators, Optimizations) { + Corpus C{5}; + const PostingList L1({1}); + const PostingList L2({2}); + const PostingList L3({3}); + + // empty and/or yield true/false + EXPECT_EQ(llvm::to_string(*C.intersect()), "true"); + EXPECT_EQ(llvm::to_string(*C.unionOf()), "false"); + + // true/false inside and/or short-circuit + EXPECT_EQ(llvm::to_string(*C.intersect(L1.iterator(), C.all())), "[1]"); + EXPECT_EQ(llvm::to_string(*C.intersect(L1.iterator(), C.none())), "false"); + // Not optimized to avoid breaking boosts. + EXPECT_EQ(llvm::to_string(*C.unionOf(L1.iterator(), C.all())), + "(| [1] true)"); + EXPECT_EQ(llvm::to_string(*C.unionOf(L1.iterator(), C.none())), "[1]"); + + // and/or nested inside and/or are flattened + EXPECT_EQ(llvm::to_string(*C.intersect( + L1.iterator(), C.intersect(L1.iterator(), L1.iterator()))), + "(& [1] [1] [1])"); + EXPECT_EQ(llvm::to_string(*C.unionOf( + L1.iterator(), C.unionOf(L2.iterator(), L3.iterator()))), + "(| [1] [2] [3])"); + + // optimizations combine over multiple levels + EXPECT_EQ(llvm::to_string(*C.intersect( + C.intersect(L1.iterator(), C.intersect()), C.unionOf(C.all()))), + "[1]"); +} + //===----------------------------------------------------------------------===// // Search token tests. //===----------------------------------------------------------------------===// |