static void generateNFAForSubtree(NFA& nfa, unsigned nfaRootId, PrefixTreeVertex& root, size_t maxNFASize) { // This recurses the subtree of the prefix tree. // For each edge that has fixed length (no quantifiers like ?, *, or +) it generates the nfa graph, // recurses into children, and deletes any processed leaf nodes. struct ActiveSubtree { ActiveSubtree(PrefixTreeVertex& vertex, unsigned nfaNodeId, unsigned edgeIndex) : vertex(vertex) , nfaNodeId(nfaNodeId) , edgeIndex(edgeIndex) { } PrefixTreeVertex& vertex; unsigned nfaNodeId; unsigned edgeIndex; }; Vector<ActiveSubtree> stack; if (!root.edges.isEmpty()) stack.append(ActiveSubtree(root, nfaRootId, 0)); bool nfaTooBig = false; // Generate graphs for each subtree that does not contain any quantifiers. while (!stack.isEmpty()) { PrefixTreeVertex& vertex = stack.last().vertex; const unsigned edgeIndex = stack.last().edgeIndex; // Only stop generating an NFA at a leaf to ensure we have a correct NFA. We could go slightly over the maxNFASize. if (vertex.edges.isEmpty() && nfa.graphSize() > maxNFASize) nfaTooBig = true; if (edgeIndex < vertex.edges.size()) { auto& edge = vertex.edges[edgeIndex]; // Clean up any processed leaves and return early if we are past the maxNFASize. if (nfaTooBig) { stack.last().edgeIndex = stack.last().vertex.edges.size(); continue; } // Quantified edges in the subtree will be a part of another NFA. if (!edge.term.hasFixedLength()) { stack.last().edgeIndex++; continue; } unsigned subtreeRootId = edge.term.generateGraph(nfa, stack.last().nfaNodeId, edge.child->finalActions); ASSERT(edge.child.get()); stack.append(ActiveSubtree(*edge.child.get(), subtreeRootId, 0)); } else { ASSERT(edgeIndex == vertex.edges.size()); vertex.edges.removeAllMatching([](PrefixTreeEdge& edge) { return edge.term.isDeletedValue(); }); stack.removeLast(); if (!stack.isEmpty()) { auto& activeSubtree = stack.last(); auto& edge = activeSubtree.vertex.edges[stack.last().edgeIndex]; if (edge.child->edges.isEmpty()) edge.term = Term(Term::DeletedValue); // Mark this leaf for deleting. activeSubtree.edgeIndex++; } } } }