From 75195f5f2e76245ed150340736ff68785a2fbf62 Mon Sep 17 00:00:00 2001 From: Justin Viiret Date: Wed, 20 Apr 2016 17:11:25 +1000 Subject: [PATCH] ng_mcclellan: move logic into base class Move all of the Automaton logic into Automaton_Base, which is templated on its StateSet/StateMap types. --- src/nfagraph/ng_mcclellan.cpp | 174 ++++++++++++---------------------- 1 file changed, 59 insertions(+), 115 deletions(-) diff --git a/src/nfagraph/ng_mcclellan.cpp b/src/nfagraph/ng_mcclellan.cpp index 89716287..b1c6ff96 100644 --- a/src/nfagraph/ng_mcclellan.cpp +++ b/src/nfagraph/ng_mcclellan.cpp @@ -341,18 +341,24 @@ void markToppableStarts(const NGHolder &g, const flat_set &unused, namespace { -class Automaton_Big { +template +class Automaton_Base { public: - typedef dynamic_bitset<> StateSet; - typedef map StateMap; + using StateSet = typename Automaton_Traits::StateSet; + using StateMap = typename Automaton_Traits::StateMap; - Automaton_Big(const ReportManager *rm_in, const NGHolder &graph_in, - const flat_set &unused_in, bool single_trigger, - const vector> &triggers, bool prunable_in) + Automaton_Base(const ReportManager *rm_in, const NGHolder &graph_in, + const flat_set &unused_in, bool single_trigger, + const vector> &triggers, bool prunable_in) : rm(rm_in), graph(graph_in), numStates(num_vertices(graph)), - unused(unused_in), init(numStates), initDS(numStates), - squash(numStates), accept(numStates), acceptEod(numStates), - toppable(numStates), prunable(prunable_in), dead(numStates) { + unused(unused_in), init(Automaton_Traits::init_states(numStates)), + initDS(Automaton_Traits::init_states(numStates)), + squash(Automaton_Traits::init_states(numStates)), + accept(Automaton_Traits::init_states(numStates)), + acceptEod(Automaton_Traits::init_states(numStates)), + toppable(Automaton_Traits::init_states(numStates)), + dead(Automaton_Traits::init_states(numStates)), + prunable(prunable_in) { populateInit(graph, unused, &init, &initDS, &v_by_index); populateAccepts(graph, unused, &accept, &acceptEod); @@ -376,15 +382,17 @@ public: cr_by_index = populateCR(graph, v_by_index, alpha); if (is_triggered(graph)) { + dynamic_bitset<> temp(numStates); markToppableStarts(graph, unused, single_trigger, triggers, - &toppable); + &temp); + toppable = Automaton_Traits::copy_states(temp, numStates); } } private: // Convert an NFAStateSet (as used by the squash code) into a StateSet StateSet shrinkStateSet(const NFAStateSet &in) const { - StateSet out(dead.size()); + StateSet out = Automaton_Traits::init_states(numStates); for (size_t i = in.find_first(); i != in.npos && i < out.size(); i = in.find_next(i)) { out.set(i); @@ -398,7 +406,7 @@ public: } const vector initial() { - vector rv(1, init); + vector rv = {init}; if (start_floating != DEAD_STATE && start_floating != start_anchored) { rv.push_back(initDS); } @@ -446,9 +454,9 @@ public: StateSet acceptEod; StateSet toppable; /* states which are allowed to be on when a top arrives, * triggered dfas only */ + StateSet dead; map squash_mask; bool prunable; - StateSet dead; array alpha; array unalpha; u16 alphasize; @@ -457,119 +465,55 @@ public: u16 start_floating; }; -class Automaton_Graph { -public: - typedef bitfield StateSet; - typedef ue2::unordered_map StateMap; +struct Big_Traits { + using StateSet = dynamic_bitset<>; + using StateMap = map; - Automaton_Graph(const ReportManager *rm_in, const NGHolder &graph_in, - const flat_set &unused_in, bool single_trigger, - const vector> &triggers, bool prunable_in) - : rm(rm_in), graph(graph_in), unused(unused_in), prunable(prunable_in) { - populateInit(graph, unused, &init, &initDS, &v_by_index); - populateAccepts(graph, unused, &accept, &acceptEod); - - start_anchored = DEAD_STATE + 1; - if (initDS == init) { - start_floating = start_anchored; - } else if (initDS.any()) { - start_floating = start_anchored + 1; - } else { - start_floating = DEAD_STATE; - } - - calculateAlphabet(graph, alpha, unalpha, &alphasize); - assert(alphasize <= ALPHABET_SIZE); - - for (const auto &sq : findSquashers(graph)) { - NFAVertex v = sq.first; - u32 vert_id = graph[v].index; - squash.set(vert_id); - squash_mask[vert_id] = shrinkStateSet(sq.second); - } - - cr_by_index = populateCR(graph, v_by_index, alpha); - if (is_triggered(graph)) { - dynamic_bitset<> temp(NFA_STATE_LIMIT); - markToppableStarts(graph, unused, single_trigger, triggers, &temp); - toppable = bitfield(temp); - } + static StateSet init_states(u32 num) { + return StateSet(num); } -private: - // Convert an NFAStateSet (as used by the squash code) into a StateSet - StateSet shrinkStateSet(const NFAStateSet &in) const { - StateSet out; + static StateSet copy_states(const dynamic_bitset<> &in, UNUSED u32 num) { + assert(in.size() == num); + return in; + } +}; + +class Automaton_Big : public Automaton_Base { +public: + Automaton_Big(const ReportManager *rm_in, const NGHolder &graph_in, + const flat_set &unused_in, bool single_trigger, + const vector> &triggers, bool prunable_in) + : Automaton_Base(rm_in, graph_in, unused_in, single_trigger, triggers, + prunable_in) {} +}; + +struct Graph_Traits { + using StateSet = bitfield; + using StateMap = ue2::unordered_map; + + static StateSet init_states(UNUSED u32 num) { + assert(num <= NFA_STATE_LIMIT); + return StateSet(); + } + + static StateSet copy_states(const dynamic_bitset<> &in, u32 num) { + StateSet out = init_states(num); for (size_t i = in.find_first(); i != in.npos && i < out.size(); i = in.find_next(i)) { out.set(i); } return out; } +}; +class Automaton_Graph : public Automaton_Base { public: - void transition(const StateSet &in, StateSet *next) { - transition_graph(*this, v_by_index, in, next); - } - - const vector initial() { - vector rv(1, init); - if (start_floating != DEAD_STATE && start_floating != start_anchored) { - rv.push_back(initDS); - } - return rv; - } - -private: - void reports_i(const StateSet &in, bool eod, flat_set &rv) { - StateSet acc = in & (eod ? acceptEod : accept); - for (size_t i = acc.find_first(); i != StateSet::npos; - i = acc.find_next(i)) { - NFAVertex v = v_by_index[i]; - DEBUG_PRINTF("marking report\n"); - const auto &my_reports = graph[v].reports; - rv.insert(my_reports.begin(), my_reports.end()); - } - } - -public: - void reports(const StateSet &in, flat_set &rv) { - reports_i(in, false, rv); - } - void reportsEod(const StateSet &in, flat_set &rv) { - reports_i(in, true, rv); - } - - bool canPrune(const flat_set &test_reports) const { - if (!rm || !prunable || !canPruneEdgesFromAccept(*rm, graph)) { - return false; - } - return allExternalReports(*rm, test_reports); - } - -private: - const ReportManager *rm; -public: - const NGHolder &graph; - const flat_set &unused; - vector v_by_index; - vector cr_by_index; /* pre alpha'ed */ - StateSet init; - StateSet initDS; - StateSet squash; /* states which allow us to mask out other states */ - StateSet accept; - StateSet acceptEod; - StateSet toppable; /* states which are allowed to be on when a top arrives, - * triggered dfas only */ - map squash_mask; - bool prunable; - StateSet dead; - array alpha; - array unalpha; - u16 alphasize; - - u16 start_anchored; - u16 start_floating; + Automaton_Graph(const ReportManager *rm_in, const NGHolder &graph_in, + const flat_set &unused_in, bool single_trigger, + const vector> &triggers, bool prunable_in) + : Automaton_Base(rm_in, graph_in, unused_in, single_trigger, triggers, + prunable_in) {} }; } // namespace