diff --git a/src/nfagraph/ng_haig.cpp b/src/nfagraph/ng_haig.cpp index 4409924b..8fe4889d 100644 --- a/src/nfagraph/ng_haig.cpp +++ b/src/nfagraph/ng_haig.cpp @@ -111,19 +111,105 @@ void populateAccepts(const NGHolder &g, StateSet *accept, StateSet *acceptEod) { } } +template class Automaton_Base { +public: + using StateSet = typename Automaton_Traits::StateSet; + using StateMap = typename Automaton_Traits::StateMap; + protected: Automaton_Base(const NGHolder &graph_in, - const flat_set &unused_in) - : graph(graph_in), unused(unused_in) { + const flat_set &unused_in, som_type som, + const vector> &triggers, + bool unordered_som) + : graph(graph_in), numStates(num_vertices(graph)), 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)) { calculateAlphabet(graph, alpha, unalpha, &alphasize); assert(alphasize <= ALPHABET_SIZE); + + populateInit(graph, unused, &init, &initDS, &v_by_index); + populateAccepts(graph, &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; + } + + cr_by_index = populateCR(graph, v_by_index, alpha); + + if (!unordered_som) { + for (const auto &sq : findSquashers(graph, som)) { + NFAVertex v = sq.first; + u32 vert_id = graph[v].index; + squash.set(vert_id); + squash_mask[vert_id] = shrinkStateSet(sq.second); + } + } + + if (is_triggered(graph)) { + dynamic_bitset<> temp(numStates); + markToppableStarts(graph, unused, false, triggers, &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 = 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); + } + return out; + } + + 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 transition(const StateSet &in, StateSet *next) { + transition_graph(*this, v_by_index, in, next); + } + + const vector initial() { + vector rv = {init}; + if (start_floating != DEAD_STATE && start_floating != start_anchored) { + rv.push_back(initDS); + } + return rv; + } + + 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); + } + static bool canPrune(const flat_set &) { return false; } const NGHolder &graph; + const u32 numStates; const flat_set &unused; array alpha; @@ -135,201 +221,68 @@ public: u16 start_anchored; u16 start_floating; + + 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; + StateSet dead; }; -class Automaton_Big : public Automaton_Base { -public: - typedef dynamic_bitset<> StateSet; - typedef map StateMap; +struct Big_Traits { + using StateSet = dynamic_bitset<>; + using StateMap = map; + static StateSet init_states(u32 num) { + return StateSet(num); + } + + 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 NGHolder &graph_in, const flat_set &unused_in, som_type som, const vector> &triggers, bool unordered_som) - : Automaton_Base(graph_in, unused_in), numStates(num_vertices(graph)), - init(numStates), initDS(numStates), squash(numStates), - accept(numStates), acceptEod(numStates), toppable(numStates), - dead(numStates) { - populateInit(graph, unused, &init, &initDS, &v_by_index); - populateAccepts(graph, &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; - } - - if (!unordered_som) { - for (const auto &sq : findSquashers(graph, som)) { - 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)) { - markToppableStarts(graph, unused, false, triggers, &toppable); - } - } - -private: - // Convert an NFAStateSet (as used by the squash code) into a StateSet. - StateSet shrinkStateSet(const NFAStateSet &in) const { - StateSet out(dead.size()); - for (size_t i = in.find_first(); i != in.npos && i < out.size(); - i = in.find_next(i)) { - out.set(i); - } - return out; - } - -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); - } - -public: - u32 numStates; - 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; - StateSet dead; + : Automaton_Base(graph_in, unused_in, som, triggers, unordered_som) {} }; -class Automaton_Graph : public Automaton_Base { -public: - typedef bitfield StateSet; - typedef ue2::unordered_map StateMap; +struct Graph_Traits { + using StateSet = bitfield; + using StateMap = ue2::unordered_map; - Automaton_Graph(const NGHolder &graph_in, - const flat_set &unused_in, - som_type som, const vector> &triggers, - bool unordered_som) - : Automaton_Base(graph_in, unused_in) { - populateInit(graph, unused, &init, &initDS, &v_by_index); - populateAccepts(graph, &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; - } - - if (!unordered_som) { - for (const auto &sq : findSquashers(graph, som)) { - 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, false, triggers, &temp); - toppable = bitfield(temp); - } + static StateSet init_states(UNUSED u32 num) { + assert(num <= NFA_STATE_LIMIT); + return StateSet(); } -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, 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); - } - -public: - 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; - StateSet dead; + Automaton_Graph(const NGHolder &graph_in, + const flat_set &unused_in, som_type som, + const vector> &triggers, + bool unordered_som) + : Automaton_Base(graph_in, unused_in, som, triggers, unordered_som) {} }; class Automaton_Haig_Merge {