OutfixInfo: use boost::variant for engines

This commit is contained in:
Justin Viiret 2016-04-15 16:41:35 +10:00 committed by Matthew Barr
parent fa27025bcb
commit 32c866a8f9
6 changed files with 154 additions and 96 deletions

View File

@ -1776,11 +1776,13 @@ bool RoseBuildImpl::addOutfix(const NGHolder &h, const raw_som_dfa &haig) {
bool RoseBuildImpl::addOutfix(const raw_puff &rp) {
if (!mpv_outfix) {
mpv_outfix = make_unique<OutfixInfo>();
mpv_outfix = make_unique<OutfixInfo>(MpvProto());
mpv_outfix->chained = true;
}
mpv_outfix->mpv.puffettes.push_back(rp);
auto *mpv = mpv_outfix->mpv();
assert(mpv);
mpv->puffettes.push_back(rp);
mpv_outfix->maxBAWidth = ROSE_BOUND_INF; /* not ba */
mpv_outfix->minWidth = min(mpv_outfix->minWidth, depth(rp.repeats));
@ -1800,11 +1802,13 @@ bool RoseBuildImpl::addOutfix(const raw_puff &rp) {
bool RoseBuildImpl::addChainTail(const raw_puff &rp, u32 *queue_out,
u32 *event_out) {
if (!mpv_outfix) {
mpv_outfix = make_unique<OutfixInfo>();
mpv_outfix = make_unique<OutfixInfo>(MpvProto());
mpv_outfix->chained = true;
}
mpv_outfix->mpv.triggered_puffettes.push_back(rp);
auto *mpv = mpv_outfix->mpv();
assert(mpv);
mpv->triggered_puffettes.push_back(rp);
mpv_outfix->maxBAWidth = ROSE_BOUND_INF; /* not ba */
mpv_outfix->minWidth = min(mpv_outfix->minWidth, depth(rp.repeats));
@ -1816,7 +1820,7 @@ bool RoseBuildImpl::addChainTail(const raw_puff &rp, u32 *queue_out,
* the caller */
*queue_out = mpv_outfix->get_queue(qif);
*event_out = MQE_TOP_FIRST + mpv_outfix->mpv.triggered_puffettes.size() - 1;
*event_out = MQE_TOP_FIRST + mpv->triggered_puffettes.size() - 1;
return true; /* failure is not yet an option */
}

View File

@ -1264,14 +1264,14 @@ aligned_unique_ptr<NFA> buildOutfix(RoseBuildImpl &tbi, OutfixInfo &outfix) {
const ReportManager &rm = tbi.rm;
aligned_unique_ptr<NFA> n;
if (outfix.rdfa) {
if (auto *rdfa = outfix.rdfa()) {
// Unleash the McClellan!
n = mcclellanCompile(*outfix.rdfa, cc);
} else if (outfix.haig) {
n = mcclellanCompile(*rdfa, cc);
} else if (auto *haig = outfix.haig()) {
// Unleash the Goughfish!
n = goughCompile(*outfix.haig, tbi.ssm.somPrecision(), cc);
} else if (outfix.holder) {
NGHolder &h = *outfix.holder;
n = goughCompile(*haig, tbi.ssm.somPrecision(), cc);
} else if (auto *holder = outfix.holder()) {
NGHolder &h = *holder;
assert(h.kind == NFA_OUTFIX);
// Build NFA.
@ -1294,8 +1294,8 @@ aligned_unique_ptr<NFA> buildOutfix(RoseBuildImpl &tbi, OutfixInfo &outfix) {
}
}
}
} else if (!outfix.mpv.puffettes.empty()) {
assert(0);
} else if (auto *mpv = outfix.mpv()) {
assert(mpv->puffettes.empty());
}
if (n && tbi.cc.grey.reverseAccelerate) {
@ -1310,34 +1310,36 @@ void prepMpv(RoseBuildImpl &tbi, build_context &bc, size_t *historyRequired,
bool *mpv_as_outfix) {
assert(bc.engineOffsets.empty()); // MPV should be first
*mpv_as_outfix = false;
OutfixInfo *mpv = nullptr;
OutfixInfo *mpv_outfix = nullptr;
/* assume outfixes are just above chain tails in queue indices */
for (auto &out : tbi.outfixes) {
if (out.is_nonempty_mpv()) {
assert(!mpv);
mpv = &out;
assert(!mpv_outfix);
mpv_outfix = &out;
} else {
assert(!out.chained);
}
}
if (!mpv) {
if (!mpv_outfix) {
return;
}
assert(mpv->chained);
auto nfa = mpvCompile(mpv->mpv.puffettes, mpv->mpv.triggered_puffettes);
assert(mpv_outfix->chained);
auto *mpv = mpv_outfix->mpv();
auto nfa = mpvCompile(mpv->puffettes, mpv->triggered_puffettes);
assert(nfa);
if (!nfa) {
throw CompileError("Unable to generate bytecode.");
}
if (tbi.cc.grey.reverseAccelerate) {
buildReverseAcceleration(nfa.get(), mpv->rev_info, mpv->minWidth);
buildReverseAcceleration(nfa.get(), mpv_outfix->rev_info,
mpv_outfix->minWidth);
}
u32 qi = mpv->get_queue(tbi.qif);
u32 qi = mpv_outfix->get_queue(tbi.qif);
nfa->queueIndex = qi;
DEBUG_PRINTF("built mpv\n");
@ -1347,7 +1349,7 @@ void prepMpv(RoseBuildImpl &tbi, build_context &bc, size_t *historyRequired,
}
add_nfa_to_blob(bc, *nfa);
*mpv_as_outfix = !mpv->mpv.puffettes.empty();
*mpv_as_outfix = !mpv->puffettes.empty();
}
static
@ -1387,8 +1389,7 @@ bool prepOutfixes(RoseBuildImpl &tbi, build_context &bc,
if (out.chained) {
continue; /* already done */
}
DEBUG_PRINTF("building outfix %zd (holder %p rdfa %p)\n",
&out - &tbi.outfixes[0], out.holder.get(), out.rdfa.get());
DEBUG_PRINTF("building outfix %zd\n", &out - &tbi.outfixes[0]);
auto n = buildOutfix(tbi, out);
if (!n) {
assert(0);

View File

@ -1904,8 +1904,8 @@ bool extractSEPLiterals(const OutfixInfo &outfix, const ReportManager &rm,
// SEP cases should always become DFAs, so that's the only extract code we
// have implemented here.
if (outfix.rdfa) {
return extractSEPLiterals(*outfix.rdfa, lits_out);
if (outfix.rdfa()) {
return extractSEPLiterals(*outfix.rdfa(), lits_out);
}
DEBUG_PRINTF("cannot extract literals from outfix type\n");

View File

@ -48,6 +48,7 @@
#include <vector>
#include <boost/bimap.hpp>
#include <boost/functional/hash/hash.hpp>
#include <boost/variant.hpp>
struct RoseEngine;
@ -302,17 +303,11 @@ struct MpvProto {
std::vector<raw_puff> triggered_puffettes;
};
struct OutfixInfo { /* TODO: poly */
OutfixInfo() {}
explicit OutfixInfo(std::unique_ptr<raw_dfa> r) : rdfa(std::move(r)) {
assert(rdfa);
}
explicit OutfixInfo(std::unique_ptr<NGHolder> h) : holder(std::move(h)) {
assert(holder);
}
explicit OutfixInfo(std::unique_ptr<raw_som_dfa> r) : haig(std::move(r)) {
assert(haig);
}
struct OutfixInfo {
template<class T>
explicit OutfixInfo(std::unique_ptr<T> x) : proto(std::move(x)) {}
explicit OutfixInfo(MpvProto mpv) : proto(std::move(mpv)) {}
u32 get_queue(QueueIndexFactory &qif);
@ -322,25 +317,68 @@ struct OutfixInfo { /* TODO: poly */
}
bool is_nonempty_mpv() const {
return !mpv.empty();
auto *mpv = boost::get<MpvProto>(&proto);
return mpv && !mpv->empty();
}
bool is_dead() const {
return !holder && !rdfa && !haig && mpv.empty();
auto *mpv = boost::get<MpvProto>(&proto);
if (mpv) {
return mpv->empty();
}
return boost::get<boost::blank>(&proto) != nullptr;
}
void clear() {
holder.reset();
rdfa.reset();
haig.reset();
mpv.reset();
assert(is_dead());
proto = boost::blank();
}
std::unique_ptr<NGHolder> holder;
std::unique_ptr<raw_dfa> rdfa;
std::unique_ptr<raw_som_dfa> haig;
MpvProto mpv;
// Convenience accessor functions.
NGHolder *holder() {
auto *up = boost::get<std::unique_ptr<NGHolder>>(&proto);
return up ? up->get() : nullptr;
}
raw_dfa *rdfa() {
auto *up = boost::get<std::unique_ptr<raw_dfa>>(&proto);
return up ? up->get() : nullptr;
}
raw_som_dfa *haig() {
auto *up = boost::get<std::unique_ptr<raw_som_dfa>>(&proto);
return up ? up->get() : nullptr;
}
MpvProto *mpv() {
return boost::get<MpvProto>(&proto);
}
// Convenience const accessor functions.
const NGHolder *holder() const {
auto *up = boost::get<std::unique_ptr<NGHolder>>(&proto);
return up ? up->get() : nullptr;
}
const raw_dfa *rdfa() const {
auto *up = boost::get<std::unique_ptr<raw_dfa>>(&proto);
return up ? up->get() : nullptr;
}
const raw_som_dfa *haig() const {
auto *up = boost::get<std::unique_ptr<raw_som_dfa>>(&proto);
return up ? up->get() : nullptr;
}
const MpvProto *mpv() const {
return boost::get<MpvProto>(&proto);
}
/**
* \brief Variant wrapping the various engine types. If this is
* boost::blank, it means that this outfix is unused (dead).
*/
boost::variant<
boost::blank,
std::unique_ptr<NGHolder>,
std::unique_ptr<raw_dfa>,
std::unique_ptr<raw_som_dfa>,
MpvProto> proto = boost::blank();
RevAccInfo rev_info;
u32 maxBAWidth = 0; //!< max bi-anchored width

View File

@ -2451,8 +2451,9 @@ void mergeOutfixNfas(RoseBuildImpl &tbi, vector<NGHolder *> &nfas) {
map<NGHolder *, size_t> nfa_mapping;
for (size_t i = 0; i < outfixes.size(); i++) {
if (outfixes[i].holder) {
nfa_mapping[outfixes[i].holder.get()] = i;
auto *holder = outfixes[i].holder();
if (holder) {
nfa_mapping[holder] = i;
}
}
@ -2485,7 +2486,7 @@ struct MergeMcClellan {
}
static void transfer(OutfixInfo &outfix, unique_ptr<raw_dfa> d) {
outfix.rdfa = move(d);
outfix.proto = move(d);
}
private:
@ -2503,7 +2504,7 @@ struct MergeHaig {
}
static void transfer(OutfixInfo &outfix, unique_ptr<raw_som_dfa> d) {
outfix.haig = move(d);
outfix.proto = move(d);
}
private:
@ -2602,8 +2603,9 @@ void mergeOutfixDfas(RoseBuildImpl &tbi, vector<raw_dfa *> &dfas) {
* element addition. */
ue2::unordered_map<raw_dfa *, size_t> dfa_mapping;
for (size_t i = 0; i < outfixes.size(); i++) {
if (outfixes[i].rdfa) {
dfa_mapping[outfixes[i].rdfa.get()] = i;
auto *rdfa = outfixes[i].rdfa();
if (rdfa) {
dfa_mapping[rdfa] = i;
}
}
@ -2624,10 +2626,10 @@ void mergeOutfixCombo(RoseBuildImpl &tbi, const ReportManager &rm,
bool seen_dfa = false;
u32 nfa_count = 0;
for (const auto &outfix : tbi.outfixes) {
if (outfix.holder) {
if (outfix.holder()) {
DEBUG_PRINTF("nfa\n");
nfa_count++;
} else if (outfix.rdfa) {
} else if (outfix.rdfa()) {
DEBUG_PRINTF("dfa\n");
seen_dfa = true;
}
@ -2647,27 +2649,29 @@ void mergeOutfixCombo(RoseBuildImpl &tbi, const ReportManager &rm,
vector<raw_dfa *> dfas;
for (auto it = tbi.outfixes.begin(); it != tbi.outfixes.end(); ++it) {
assert(!it->is_dead());
assert(!it->chained);
if (it->rdfa) {
dfas.push_back(it->rdfa.get());
dfa_mapping[it->rdfa.get()] = it - tbi.outfixes.begin();
auto &outfix = *it;
assert(!outfix.is_dead());
assert(!outfix.chained);
if (outfix.rdfa()) {
auto *rdfa = outfix.rdfa();
dfas.push_back(rdfa);
dfa_mapping[rdfa] = it - tbi.outfixes.begin();
continue;
}
if (!it->holder) {
if (!outfix.holder()) {
continue;
}
NGHolder *h = it->holder.get();
NGHolder *h = outfix.holder();
assert(h->kind == NFA_OUTFIX);
auto rdfa = buildMcClellan(*h, &rm, grey);
if (rdfa) {
// Transform this outfix into a DFA and add it to the merge set.
dfa_mapping[rdfa.get()] = it - tbi.outfixes.begin();
dfas.push_back(rdfa.get());
it->clear();
it->rdfa = move(rdfa);
outfix.proto = move(rdfa);
new_dfas++;
}
}
@ -2695,8 +2699,9 @@ void mergeOutfixHaigs(RoseBuildImpl &tbi, vector<raw_som_dfa *> &dfas,
ue2::unordered_map<raw_som_dfa *, size_t> dfa_mapping;
for (size_t i = 0; i < outfixes.size(); i++) {
if (outfixes[i].haig) {
dfa_mapping[outfixes[i].haig.get()] = i;
auto *haig = outfixes[i].haig();
if (haig) {
dfa_mapping[haig] = i;
}
}
@ -2721,14 +2726,14 @@ void mergeOutfixes(RoseBuildImpl &tbi) {
vector<raw_dfa *> dfas;
vector<raw_som_dfa *> som_dfas;
for (const auto &outfix : tbi.outfixes) {
for (auto &outfix : tbi.outfixes) {
assert(!outfix.chained);
if (outfix.rdfa) {
dfas.push_back(outfix.rdfa.get());
} else if (outfix.holder) {
nfas.push_back(outfix.holder.get());
} else if (outfix.haig) {
som_dfas.push_back(outfix.haig.get());
if (outfix.rdfa()) {
dfas.push_back(outfix.rdfa());
} else if (outfix.holder()) {
nfas.push_back(outfix.holder());
} else if (outfix.haig()) {
som_dfas.push_back(outfix.haig());
}
}

View File

@ -631,10 +631,11 @@ RoseDedupeAuxImpl::RoseDedupeAuxImpl(const RoseBuildImpl &tbi_in)
}
if (tbi.mpv_outfix) {
for (const auto &puff : tbi.mpv_outfix->mpv.puffettes) {
auto *mpv = tbi.mpv_outfix->mpv();
for (const auto &puff : mpv->puffettes) {
puff_map[puff.report].insert(&puff);
}
for (const auto &puff : tbi.mpv_outfix->mpv.triggered_puffettes) {
for (const auto &puff : mpv->triggered_puffettes) {
puff_map[puff.report].insert(&puff);
}
}
@ -785,12 +786,13 @@ bool RoseDedupeAuxImpl::requiresDedupeSupport(
}
has_outfix = true;
if (out.haig) {
if (out.haig()) {
return true; /* haig may report matches with different SOM at the
same offset */
}
if (out.holder && requiresDedupe(*out.holder, reports, tbi.cc.grey)) {
if (out.holder() &&
requiresDedupe(*out.holder(), reports, tbi.cc.grey)) {
return true;
}
}
@ -874,25 +876,33 @@ u32 OutfixInfo::get_queue(QueueIndexFactory &qif) {
return queue;
}
namespace {
class OutfixAllReports : public boost::static_visitor<set<ReportID>> {
public:
set<ReportID> operator()(const boost::blank &) const {
return {};
}
template<class T>
set<ReportID> operator()(const unique_ptr<T> &x) const {
return all_reports(*x);
}
set<ReportID> operator()(const MpvProto &mpv) const {
set<ReportID> reports;
for (const auto &puff : mpv.puffettes) {
reports.insert(puff.report);
}
for (const auto &puff : mpv.triggered_puffettes) {
reports.insert(puff.report);
}
return reports;
}
};
}
set<ReportID> all_reports(const OutfixInfo &outfix) {
set<ReportID> reports;
if (outfix.holder) {
insert(&reports, all_reports(*outfix.holder));
}
if (outfix.rdfa) {
insert(&reports, all_reports(*outfix.rdfa));
}
if (outfix.haig) {
insert(&reports, all_reports(*outfix.haig));
}
for (const auto &puff : outfix.mpv.puffettes) {
reports.insert(puff.report);
}
for (const auto &puff : outfix.mpv.triggered_puffettes) {
reports.insert(puff.report);
}
auto reports = boost::apply_visitor(OutfixAllReports(), outfix.proto);
assert(!reports.empty());
return reports;
}