#include "Iterator.h"
#include "llvm/ADT/STLExtras.h"
#include <algorithm>
#include <cassert>
#include <numeric>
namespace clang {
namespace clangd {
namespace dex {
namespace {
class AndIterator : public Iterator {
public:
explicit AndIterator(std::vector<std::unique_ptr<Iterator>> AllChildren)
: Iterator(Kind::And), Children(std::move(AllChildren)) {
assert(!Children.empty() && "AND iterator should have at least one child.");
for (const auto &Child : Children)
ReachedEnd |= Child->reachedEnd();
sync();
llvm::sort(Children, [](const std::unique_ptr<Iterator> &LHS,
const std::unique_ptr<Iterator> &RHS) {
return LHS->estimateSize() < RHS->estimateSize();
});
}
bool reachedEnd() const override { return ReachedEnd; }
void advance() override {
assert(!reachedEnd() && "AND iterator can't advance() at the end.");
Children.front()->advance();
sync();
}
void advanceTo(DocID ID) override {
assert(!reachedEnd() && "AND iterator can't advanceTo() at the end.");
Children.front()->advanceTo(ID);
sync();
}
DocID peek() const override { return Children.front()->peek(); }
float consume() override {
assert(!reachedEnd() && "AND iterator can't consume() at the end.");
float Boost = 1;
for (const auto &Child : Children)
Boost *= Child->consume();
return Boost;
}
size_t estimateSize() const override {
return Children.front()->estimateSize();
}
private:
llvm::raw_ostream &dump(llvm::raw_ostream &OS) const override {
OS << "(& ";
auto *Separator = "";
for (const auto &Child : Children) {
OS << Separator << *Child;
Separator = " ";
}
OS << ')';
return OS;
}
void sync() {
ReachedEnd |= Children.front()->reachedEnd();
if (ReachedEnd)
return;
auto SyncID = Children.front()->peek();
bool NeedsAdvance = false;
do {
NeedsAdvance = false;
for (auto &Child : Children) {
Child->advanceTo(SyncID);
ReachedEnd |= Child->reachedEnd();
if (ReachedEnd)
return;
auto Candidate = Child->peek();
if (Candidate > SyncID) {
SyncID = Candidate;
NeedsAdvance = true;
break;
}
}
} while (NeedsAdvance);
}
std::vector<std::unique_ptr<Iterator>> Children;
bool ReachedEnd = false;
friend Corpus;
};
class OrIterator : public Iterator {
public:
explicit OrIterator(std::vector<std::unique_ptr<Iterator>> AllChildren)
: Iterator(Kind::Or), Children(std::move(AllChildren)) {
assert(!Children.empty() && "OR iterator should have at least one child.");
}
bool reachedEnd() const override {
for (const auto &Child : Children)
if (!Child->reachedEnd())
return false;
return true;
}
void advance() override {
assert(!reachedEnd() && "OR iterator can't advance() at the end.");
const auto SmallestID = peek();
for (const auto &Child : Children)
if (!Child->reachedEnd() && Child->peek() == SmallestID)
Child->advance();
}
void advanceTo(DocID ID) override {
assert(!reachedEnd() && "OR iterator can't advanceTo() at the end.");
for (const auto &Child : Children)
if (!Child->reachedEnd())
Child->advanceTo(ID);
}
DocID peek() const override {
assert(!reachedEnd() && "OR iterator can't peek() at the end.");
DocID Result = std::numeric_limits<DocID>::max();
for (const auto &Child : Children)
if (!Child->reachedEnd())
Result = std::min(Result, Child->peek());
return Result;
}
float consume() override {
assert(!reachedEnd() && "OR iterator can't consume() at the end.");
const DocID ID = peek();
float Boost = 1;
for (const auto &Child : Children)
if (!Child->reachedEnd() && Child->peek() == ID)
Boost = std::max(Boost, Child->consume());
return Boost;
}
size_t estimateSize() const override {
size_t Size = 0;
for (const auto &Child : Children)
Size = std::max(Size, Child->estimateSize());
return Size;
}
private:
llvm::raw_ostream &dump(llvm::raw_ostream &OS) const override {
OS << "(| ";
auto *Separator = "";
for (const auto &Child : Children) {
OS << Separator << *Child;
Separator = " ";
}
OS << ')';
return OS;
}
std::vector<std::unique_ptr<Iterator>> Children;
friend Corpus;
};
class TrueIterator : public Iterator {
public:
explicit TrueIterator(DocID Size) : Iterator(Kind::True), Size(Size) {}
bool reachedEnd() const override { return Index >= Size; }
void advance() override {
assert(!reachedEnd() && "TRUE iterator can't advance() at the end.");
++Index;
}
void advanceTo(DocID ID) override {
assert(!reachedEnd() && "TRUE iterator can't advanceTo() at the end.");
Index = std::min(ID, Size);
}
DocID peek() const override {
assert(!reachedEnd() && "TRUE iterator can't peek() at the end.");
return Index;
}
float consume() override {
assert(!reachedEnd() && "TRUE iterator can't consume() at the end.");
return 1;
}
size_t estimateSize() const override { return Size; }
private:
llvm::raw_ostream &dump(llvm::raw_ostream &OS) const override {
return OS << "true";
}
DocID Index = 0;
DocID Size;
};
class FalseIterator : public Iterator {
public:
FalseIterator() : Iterator(Kind::False) {}
bool reachedEnd() const override { return true; }
void advance() override { assert(false); }
void advanceTo(DocID ID) override { assert(false); }
DocID peek() const override {
assert(false);
return 0;
}
float consume() override {
assert(false);
return 1;
}
size_t estimateSize() const override { return 0; }
private:
llvm::raw_ostream &dump(llvm::raw_ostream &OS) const override {
return OS << "false";
}
};
class BoostIterator : public Iterator {
public:
BoostIterator(std::unique_ptr<Iterator> Child, float Factor)
: Child(std::move(Child)), Factor(Factor) {}
bool reachedEnd() const override { return Child->reachedEnd(); }
void advance() override { Child->advance(); }
void advanceTo(DocID ID) override { Child->advanceTo(ID); }
DocID peek() const override { return Child->peek(); }
float consume() override { return Child->consume() * Factor; }
size_t estimateSize() const override { return Child->estimateSize(); }
private:
llvm::raw_ostream &dump(llvm::raw_ostream &OS) const override {
return OS << "(* " << Factor << ' ' << *Child << ')';
}
std::unique_ptr<Iterator> Child;
float Factor;
};
class LimitIterator : public Iterator {
public:
LimitIterator(std::unique_ptr<Iterator> Child, size_t Limit)
: Child(std::move(Child)), Limit(Limit), ItemsLeft(Limit) {}
bool reachedEnd() const override {
return ItemsLeft == 0 || Child->reachedEnd();
}
void advance() override { Child->advance(); }
void advanceTo(DocID ID) override { Child->advanceTo(ID); }
DocID peek() const override { return Child->peek(); }
float consume() override {
assert(!reachedEnd() && "LimitIterator can't consume() at the end.");
--ItemsLeft;
return Child->consume();
}
size_t estimateSize() const override {
return std::min(Child->estimateSize(), Limit);
}
private:
llvm::raw_ostream &dump(llvm::raw_ostream &OS) const override {
return OS << "(LIMIT " << Limit << " " << *Child << ')';
}
std::unique_ptr<Iterator> Child;
size_t Limit;
size_t ItemsLeft;
};
}
std::vector<std::pair<DocID, float>> consume(Iterator &It) {
std::vector<std::pair<DocID, float>> Result;
for (; !It.reachedEnd(); It.advance())
Result.emplace_back(It.peek(), It.consume());
return Result;
}
std::unique_ptr<Iterator>
Corpus::intersect(std::vector<std::unique_ptr<Iterator>> Children) const {
std::vector<std::unique_ptr<Iterator>> RealChildren;
for (auto &Child : Children) {
switch (Child->kind()) {
case Iterator::Kind::True:
break;
case Iterator::Kind::False:
return std::move(Child);
case Iterator::Kind::And: {
auto &NewChildren = static_cast<AndIterator *>(Child.get())->Children;
std::move(NewChildren.begin(), NewChildren.end(),
std::back_inserter(RealChildren));
break;
}
default:
RealChildren.push_back(std::move(Child));
}
}
switch (RealChildren.size()) {
case 0:
return all();
case 1:
return std::move(RealChildren.front());
default:
return std::make_unique<AndIterator>(std::move(RealChildren));
}
}
std::unique_ptr<Iterator>
Corpus::unionOf(std::vector<std::unique_ptr<Iterator>> Children) const {
std::vector<std::unique_ptr<Iterator>> RealChildren;
for (auto &Child : Children) {
switch (Child->kind()) {
case Iterator::Kind::False:
break;
case Iterator::Kind::Or: {
auto &NewChildren = static_cast<OrIterator *>(Child.get())->Children;
std::move(NewChildren.begin(), NewChildren.end(),
std::back_inserter(RealChildren));
break;
}
case Iterator::Kind::True:
default:
RealChildren.push_back(std::move(Child));
}
}
switch (RealChildren.size()) {
case 0:
return none();
case 1:
return std::move(RealChildren.front());
default:
return std::make_unique<OrIterator>(std::move(RealChildren));
}
}
std::unique_ptr<Iterator> Corpus::all() const {
return std::make_unique<TrueIterator>(Size);
}
std::unique_ptr<Iterator> Corpus::none() const {
return std::make_unique<FalseIterator>();
}
std::unique_ptr<Iterator> Corpus::boost(std::unique_ptr<Iterator> Child,
float Factor) const {
if (Factor == 1)
return Child;
if (Child->kind() == Iterator::Kind::False)
return Child;
return std::make_unique<BoostIterator>(std::move(Child), Factor);
}
std::unique_ptr<Iterator> Corpus::limit(std::unique_ptr<Iterator> Child,
size_t Limit) const {
if (Child->kind() == Iterator::Kind::False)
return Child;
return std::make_unique<LimitIterator>(std::move(Child), Limit);
}
}
}
}