ng_calc_components: rework to move graphs

Rather than cloning graphs for output, rework calc components so that it
moves them.
This commit is contained in:
Justin Viiret 2017-03-21 10:27:14 +11:00 committed by Matthew Barr
parent 5dfae12a62
commit ba867ebaff
6 changed files with 51 additions and 52 deletions

View File

@ -276,13 +276,12 @@ void addExpression(NG &ng, unsigned index, const char *expression,
throw CompileError("Internal error."); throw CompileError("Internal error.");
} }
auto &g = *built_expr.g; if (!pe.expr.allow_vacuous && matches_everywhere(*built_expr.g)) {
if (!pe.expr.allow_vacuous && matches_everywhere(g)) {
throw CompileError("Pattern matches empty buffer; use " throw CompileError("Pattern matches empty buffer; use "
"HS_FLAG_ALLOWEMPTY to enable support."); "HS_FLAG_ALLOWEMPTY to enable support.");
} }
if (!ng.addGraph(built_expr.expr, g)) { if (!ng.addGraph(built_expr.expr, std::move(built_expr.g))) {
DEBUG_PRINTF("NFA addGraph failed on ID %u.\n", pe.expr.report); DEBUG_PRINTF("NFA addGraph failed on ID %u.\n", pe.expr.report);
throw CompileError("Error compiling expression."); throw CompileError("Error compiling expression.");
} }

View File

@ -315,7 +315,10 @@ bool processComponents(NG &ng, ExpressionInfo &expr,
return false; return false;
} }
bool NG::addGraph(ExpressionInfo &expr, NGHolder &g) { bool NG::addGraph(ExpressionInfo &expr, unique_ptr<NGHolder> g_ptr) {
assert(g_ptr);
NGHolder &g = *g_ptr;
// remove reports that aren't on vertices connected to accept. // remove reports that aren't on vertices connected to accept.
clearReports(g); clearReports(g);
@ -431,15 +434,16 @@ bool NG::addGraph(ExpressionInfo &expr, NGHolder &g) {
return true; return true;
} }
// Split the graph into a set of connected components. // Split the graph into a set of connected components and process those.
// Note: this invalidates g_ptr.
deque<unique_ptr<NGHolder>> g_comp = calcComponents(g); auto g_comp = calcComponents(std::move(g_ptr));
assert(!g_comp.empty()); assert(!g_comp.empty());
if (!som) { if (!som) {
for (u32 i = 0; i < g_comp.size(); i++) { for (auto &gc : g_comp) {
assert(g_comp[i]); assert(gc);
reformLeadingDots(*g_comp[i]); reformLeadingDots(*gc);
} }
recalcComponents(g_comp); recalcComponents(g_comp);
@ -453,12 +457,11 @@ bool NG::addGraph(ExpressionInfo &expr, NGHolder &g) {
// have another shot at accepting the graph. // have another shot at accepting the graph.
if (cc.grey.prefilterReductions && expr.prefilter) { if (cc.grey.prefilterReductions && expr.prefilter) {
for (u32 i = 0; i < g_comp.size(); i++) { for (auto &gc : g_comp) {
if (!g_comp[i]) { if (!gc) {
continue; continue;
} }
prefilterReductions(*gc, cc);
prefilterReductions(*g_comp[i], cc);
} }
if (processComponents(*this, expr, g_comp, som)) { if (processComponents(*this, expr, g_comp, som)) {

View File

@ -70,7 +70,7 @@ public:
/** \brief Consumes a pattern, returns false or throws a CompileError /** \brief Consumes a pattern, returns false or throws a CompileError
* exception if the graph cannot be consumed. */ * exception if the graph cannot be consumed. */
bool addGraph(ExpressionInfo &expr, NGHolder &h); bool addGraph(ExpressionInfo &expr, std::unique_ptr<NGHolder> g_ptr);
/** \brief Consumes a graph, cut-down version of addGraph for use by SOM /** \brief Consumes a graph, cut-down version of addGraph for use by SOM
* processing. */ * processing. */

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2015-2016, Intel Corporation * Copyright (c) 2015-2017, Intel Corporation
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
@ -245,31 +245,33 @@ void renumberVertices(NFAUndirectedGraph &ug) {
* one or more connected components, adding them to the comps deque. * one or more connected components, adding them to the comps deque.
*/ */
static static
void splitIntoComponents(const NGHolder &g, deque<unique_ptr<NGHolder>> &comps, void splitIntoComponents(unique_ptr<NGHolder> g,
deque<unique_ptr<NGHolder>> &comps,
const depth &max_head_depth, const depth &max_head_depth,
const depth &max_tail_depth, bool *shell_comp) { const depth &max_tail_depth, bool *shell_comp) {
DEBUG_PRINTF("graph has %zu vertices\n", num_vertices(g)); DEBUG_PRINTF("graph has %zu vertices\n", num_vertices(*g));
assert(shell_comp); assert(shell_comp);
*shell_comp = false; *shell_comp = false;
// Compute "shell" head and tail subgraphs. // Compute "shell" head and tail subgraphs.
vector<NFAVertexBidiDepth> depths; vector<NFAVertexBidiDepth> depths;
calcDepths(g, depths); calcDepths(*g, depths);
auto head_shell = findHeadShell(g, depths, max_head_depth); auto head_shell = findHeadShell(*g, depths, max_head_depth);
auto tail_shell = findTailShell(g, depths, max_tail_depth); auto tail_shell = findTailShell(*g, depths, max_tail_depth);
for (auto v : head_shell) { for (auto v : head_shell) {
tail_shell.erase(v); tail_shell.erase(v);
} }
if (head_shell.size() + tail_shell.size() + N_SPECIALS >= num_vertices(g)) { if (head_shell.size() + tail_shell.size() + N_SPECIALS >=
num_vertices(*g)) {
DEBUG_PRINTF("all in shell component\n"); DEBUG_PRINTF("all in shell component\n");
comps.push_back(cloneHolder(g)); comps.push_back(std::move(g));
*shell_comp = true; *shell_comp = true;
return; return;
} }
vector<NFAEdge> shell_edges = findShellEdges(g, head_shell, tail_shell); vector<NFAEdge> shell_edges = findShellEdges(*g, head_shell, tail_shell);
DEBUG_PRINTF("%zu vertices in head, %zu in tail, %zu shell edges\n", DEBUG_PRINTF("%zu vertices in head, %zu in tail, %zu shell edges\n",
head_shell.size(), tail_shell.size(), shell_edges.size()); head_shell.size(), tail_shell.size(), shell_edges.size());
@ -277,7 +279,7 @@ void splitIntoComponents(const NGHolder &g, deque<unique_ptr<NGHolder>> &comps,
NFAUndirectedGraph ug; NFAUndirectedGraph ug;
ue2::unordered_map<NFAVertex, NFAUndirectedVertex> old2new; ue2::unordered_map<NFAVertex, NFAUndirectedVertex> old2new;
createUnGraph(g, true, true, ug, old2new); createUnGraph(*g, true, true, ug, old2new);
// Construct reverse mapping. // Construct reverse mapping.
ue2::unordered_map<NFAUndirectedVertex, NFAVertex> new2old; ue2::unordered_map<NFAUndirectedVertex, NFAVertex> new2old;
@ -298,7 +300,7 @@ void splitIntoComponents(const NGHolder &g, deque<unique_ptr<NGHolder>> &comps,
assert(num > 0); assert(num > 0);
if (num == 1 && shell_edges.empty()) { if (num == 1 && shell_edges.empty()) {
DEBUG_PRINTF("single component\n"); DEBUG_PRINTF("single component\n");
comps.push_back(cloneHolder(g)); comps.push_back(std::move(g));
return; return;
} }
@ -313,7 +315,7 @@ void splitIntoComponents(const NGHolder &g, deque<unique_ptr<NGHolder>> &comps,
assert(contains(new2old, uv)); assert(contains(new2old, uv));
NFAVertex v = new2old.at(uv); NFAVertex v = new2old.at(uv);
verts[c].push_back(v); verts[c].push_back(v);
DEBUG_PRINTF("vertex %zu is in comp %u\n", g[v].index, c); DEBUG_PRINTF("vertex %zu is in comp %u\n", (*g)[v].index, c);
} }
ue2::unordered_map<NFAVertex, NFAVertex> v_map; // temp map for fillHolder ue2::unordered_map<NFAVertex, NFAVertex> v_map; // temp map for fillHolder
@ -328,12 +330,12 @@ void splitIntoComponents(const NGHolder &g, deque<unique_ptr<NGHolder>> &comps,
auto gc = ue2::make_unique<NGHolder>(); auto gc = ue2::make_unique<NGHolder>();
v_map.clear(); v_map.clear();
fillHolder(gc.get(), g, vv, &v_map); fillHolder(gc.get(), *g, vv, &v_map);
// Remove shell edges, which will get their own component. // Remove shell edges, which will get their own component.
for (const auto &e : shell_edges) { for (const auto &e : shell_edges) {
auto cu = v_map.at(source(e, g)); auto cu = v_map.at(source(e, *g));
auto cv = v_map.at(target(e, g)); auto cv = v_map.at(target(e, *g));
assert(edge(cu, cv, *gc).second); assert(edge(cu, cv, *gc).second);
remove_edge(cu, cv, *gc); remove_edge(cu, cv, *gc);
} }
@ -352,7 +354,7 @@ void splitIntoComponents(const NGHolder &g, deque<unique_ptr<NGHolder>> &comps,
auto gc = ue2::make_unique<NGHolder>(); auto gc = ue2::make_unique<NGHolder>();
v_map.clear(); v_map.clear();
fillHolder(gc.get(), g, vv, &v_map); fillHolder(gc.get(), *g, vv, &v_map);
pruneUseless(*gc); pruneUseless(*gc);
DEBUG_PRINTF("shell edge component %zu has %zu vertices\n", DEBUG_PRINTF("shell edge component %zu has %zu vertices\n",
@ -374,26 +376,26 @@ void splitIntoComponents(const NGHolder &g, deque<unique_ptr<NGHolder>> &comps,
})); }));
} }
deque<unique_ptr<NGHolder>> calcComponents(const NGHolder &g) { deque<unique_ptr<NGHolder>> calcComponents(unique_ptr<NGHolder> g) {
deque<unique_ptr<NGHolder>> comps; deque<unique_ptr<NGHolder>> comps;
// For trivial cases, we needn't bother running the full // For trivial cases, we needn't bother running the full
// connected_components algorithm. // connected_components algorithm.
if (isAlternationOfClasses(g)) { if (isAlternationOfClasses(*g)) {
comps.push_back(cloneHolder(g)); comps.push_back(std::move(g));
return comps; return comps;
} }
bool shell_comp = false; bool shell_comp = false;
splitIntoComponents(g, comps, MAX_HEAD_SHELL_DEPTH, MAX_TAIL_SHELL_DEPTH, splitIntoComponents(std::move(g), comps, MAX_HEAD_SHELL_DEPTH,
&shell_comp); MAX_TAIL_SHELL_DEPTH, &shell_comp);
if (shell_comp) { if (shell_comp) {
DEBUG_PRINTF("re-running on shell comp\n"); DEBUG_PRINTF("re-running on shell comp\n");
assert(!comps.empty()); assert(!comps.empty());
auto sc = move(comps.back()); auto sc = std::move(comps.back());
comps.pop_back(); comps.pop_back();
splitIntoComponents(*sc, comps, 0, 0, &shell_comp); splitIntoComponents(std::move(sc), comps, 0, 0, &shell_comp);
} }
DEBUG_PRINTF("finished; split into %zu components\n", comps.size()); DEBUG_PRINTF("finished; split into %zu components\n", comps.size());
@ -409,14 +411,13 @@ void recalcComponents(deque<unique_ptr<NGHolder>> &comps) {
} }
if (isAlternationOfClasses(*gc)) { if (isAlternationOfClasses(*gc)) {
out.push_back(move(gc)); out.push_back(std::move(gc));
continue; continue;
} }
auto gc_comps = calcComponents(*gc); auto gc_comps = calcComponents(std::move(gc));
for (auto &elem : gc_comps) { out.insert(end(out), std::make_move_iterator(begin(gc_comps)),
out.push_back(move(elem)); std::make_move_iterator(end(gc_comps)));
}
} }
// Replace comps with our recalculated list. // Replace comps with our recalculated list.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2015, Intel Corporation * Copyright (c) 2015-2017, Intel Corporation
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
@ -42,7 +42,8 @@ class NGHolder;
bool isAlternationOfClasses(const NGHolder &g); bool isAlternationOfClasses(const NGHolder &g);
std::deque<std::unique_ptr<NGHolder>> calcComponents(const NGHolder &g); std::deque<std::unique_ptr<NGHolder>>
calcComponents(std::unique_ptr<NGHolder> g);
void recalcComponents(std::deque<std::unique_ptr<NGHolder>> &comps); void recalcComponents(std::deque<std::unique_ptr<NGHolder>> &comps);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2015, Intel Corporation * Copyright (c) 2015-2017, Intel Corporation
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
@ -33,13 +33,8 @@
#include "config.h" #include "config.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "nfagraph_common.h" #include "nfagraph_common.h"
#include "grey.h"
#include "hs.h"
#include "compiler/compiler.h"
#include "nfagraph/ng.h" #include "nfagraph/ng.h"
#include "nfagraph/ng_builder.h"
#include "nfagraph/ng_calc_components.h" #include "nfagraph/ng_calc_components.h"
#include "util/target_info.h"
using namespace std; using namespace std;
using namespace ue2; using namespace ue2;
@ -48,7 +43,7 @@ TEST(NFAGraph, CalcComp1) {
auto graph = constructGraph("abc|def|ghi", 0); auto graph = constructGraph("abc|def|ghi", 0);
ASSERT_TRUE(graph != nullptr); ASSERT_TRUE(graph != nullptr);
deque<unique_ptr<NGHolder>> comps = calcComponents(*graph); auto comps = calcComponents(std::move(graph));
ASSERT_EQ(3, comps.size()); ASSERT_EQ(3, comps.size());
} }
@ -56,7 +51,7 @@ TEST(NFAGraph, CalcComp2) {
auto graph = constructGraph("a|b|c|d|e|f|g|h|i", 0); auto graph = constructGraph("a|b|c|d|e|f|g|h|i", 0);
ASSERT_TRUE(graph != nullptr); ASSERT_TRUE(graph != nullptr);
deque<unique_ptr<NGHolder>> comps = calcComponents(*graph); auto comps = calcComponents(std::move(graph));
// We should be identifying this as a trivial case and not splitting it. // We should be identifying this as a trivial case and not splitting it.
ASSERT_EQ(1, comps.size()); ASSERT_EQ(1, comps.size());