ng: ensure that only match states have reports

Ensure (and assert) that vertices without an edge to {accept, acceptEod}
do not have reports set.
This commit is contained in:
Justin Viiret 2016-07-18 12:41:31 +10:00 committed by Matthew Barr
parent 3d9a60d023
commit 4ce268af47
10 changed files with 70 additions and 20 deletions

View File

@ -105,6 +105,7 @@ bool addComponentSom(NG &ng, NGHolder &g, const NGWrapper &w,
DEBUG_PRINTF("doing som\n"); DEBUG_PRINTF("doing som\n");
dumpComponent(g, "03_presom", w.expressionIndex, comp_id, ng.cc.grey); dumpComponent(g, "03_presom", w.expressionIndex, comp_id, ng.cc.grey);
assert(hasCorrectlyNumberedVertices(g)); assert(hasCorrectlyNumberedVertices(g));
assert(allMatchStatesHaveReports(w));
// First, we try the "SOM chain" support in ng_som.cpp. // First, we try the "SOM chain" support in ng_som.cpp.
@ -208,6 +209,8 @@ bool addComponent(NG &ng, NGHolder &g, const NGWrapper &w, const som_type som,
dumpComponent(g, "01_begin", w.expressionIndex, comp_id, ng.cc.grey); dumpComponent(g, "01_begin", w.expressionIndex, comp_id, ng.cc.grey);
assert(allMatchStatesHaveReports(w));
reduceGraph(g, som, w.utf8, cc); reduceGraph(g, som, w.utf8, cc);
dumpComponent(g, "02_reduced", w.expressionIndex, comp_id, ng.cc.grey); dumpComponent(g, "02_reduced", w.expressionIndex, comp_id, ng.cc.grey);
@ -232,6 +235,8 @@ bool addComponent(NG &ng, NGHolder &g, const NGWrapper &w, const som_type som,
} }
} }
assert(allMatchStatesHaveReports(w));
if (splitOffAnchoredAcyclic(*ng.rose, g, cc)) { if (splitOffAnchoredAcyclic(*ng.rose, g, cc)) {
return true; return true;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2015, Intel Corporation * Copyright (c) 2015-2016, 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:
@ -553,6 +553,7 @@ void ensureCodePointStart(ReportManager &rm, NGWrapper &g) {
add_edge(g.startDs, v_4, g); add_edge(g.startDs, v_4, g);
remove_edge(orig, g); remove_edge(orig, g);
g.renumberEdges(); g.renumberEdges();
clearReports(g);
} }
} }

View File

@ -363,6 +363,12 @@ void splitIntoComponents(const NGHolder &g, deque<unique_ptr<NGHolder>> &comps,
*shell_comp = true; *shell_comp = true;
} }
// Ensure that only vertices with accept edges have reports.
for (auto &gc : comps) {
assert(gc);
clearReports(*gc);
}
// We should never produce empty component graphs. // We should never produce empty component graphs.
assert(all_of(begin(comps), end(comps), assert(all_of(begin(comps), end(comps),
[](const unique_ptr<NGHolder> &g_comp) { [](const unique_ptr<NGHolder> &g_comp) {

View File

@ -79,13 +79,17 @@ bool sanityCheckGraph(const NGHolder &g,
} }
} }
// Vertices with edges to accept or acceptEod must have reports. // Vertices with edges to accept or acceptEod must have reports and
// other vertices must not have them.
if (is_match_vertex(v, g) && v != g.accept) { if (is_match_vertex(v, g) && v != g.accept) {
if (g[v].reports.empty()) { if (g[v].reports.empty()) {
DEBUG_PRINTF("vertex %u has no reports\n", DEBUG_PRINTF("vertex %u has no reports\n", g[v].index);
g[v].index);
return false; return false;
} }
} else if (!g[v].reports.empty()) {
DEBUG_PRINTF("vertex %u has reports but no accept edge\n",
g[v].index);
return false;
} }
// Participant vertices should have distinct state indices. // Participant vertices should have distinct state indices.

View File

@ -872,6 +872,7 @@ u32 removeTrailingLiteralStates(NGHolder &g, const ue2_literal &lit,
} }
clear_in_edges(g.accept, g); clear_in_edges(g.accept, g);
clearReports(g);
vector<NFAVertex> verts(pred.begin(), pred.end()); vector<NFAVertex> verts(pred.begin(), pred.end());
sort(verts.begin(), verts.end(), VertexIndexOrdering<NGHolder>(g)); sort(verts.begin(), verts.end(), VertexIndexOrdering<NGHolder>(g));

View File

@ -631,16 +631,18 @@ unique_ptr<NGHolder> cloneHolder(const NGHolder &in) {
} }
#ifndef NDEBUG #ifndef NDEBUG
/** \brief Used in sanity-checking assertions: returns true if all vertices
* leading to accept or acceptEod have at least one report ID. */
bool allMatchStatesHaveReports(const NGHolder &g) { bool allMatchStatesHaveReports(const NGHolder &g) {
unordered_set<NFAVertex> reporters;
for (auto v : inv_adjacent_vertices_range(g.accept, g)) { for (auto v : inv_adjacent_vertices_range(g.accept, g)) {
if (g[v].reports.empty()) { if (g[v].reports.empty()) {
DEBUG_PRINTF("vertex %u has no reports!\n", DEBUG_PRINTF("vertex %u has no reports!\n",
g[v].index); g[v].index);
return false; return false;
} }
reporters.insert(v);
} }
for (auto v : inv_adjacent_vertices_range(g.acceptEod, g)) { for (auto v : inv_adjacent_vertices_range(g.acceptEod, g)) {
if (v == g.accept) { if (v == g.accept) {
continue; // stylised edge continue; // stylised edge
@ -650,12 +652,20 @@ bool allMatchStatesHaveReports(const NGHolder &g) {
g[v].index); g[v].index);
return false; return false;
} }
reporters.insert(v);
} }
for (auto v : vertices_range(g)) {
if (!contains(reporters, v) && !g[v].reports.empty()) {
DEBUG_PRINTF("vertex %u is not a match state, but has reports!\n",
g[v].index);
return false;
}
}
return true; return true;
} }
/** Assertion: returns true if the vertices in this graph are contiguously (and
* uniquely) numbered from zero. */
bool hasCorrectlyNumberedVertices(const NGHolder &g) { bool hasCorrectlyNumberedVertices(const NGHolder &g) {
size_t count = num_vertices(g); size_t count = num_vertices(g);
vector<bool> ids(count, false); vector<bool> ids(count, false);
@ -670,8 +680,6 @@ bool hasCorrectlyNumberedVertices(const NGHolder &g) {
&& num_vertices(g) == num_vertices(g.g); && num_vertices(g) == num_vertices(g.g);
} }
/** Assertion: returns true if the edges in this graph are contiguously (and
* uniquely) numbered from zero. */
bool hasCorrectlyNumberedEdges(const NGHolder &g) { bool hasCorrectlyNumberedEdges(const NGHolder &g) {
size_t count = num_edges(g); size_t count = num_edges(g);
vector<bool> ids(count, false); vector<bool> ids(count, false);

View File

@ -297,15 +297,29 @@ void clearReports(NGHolder &g);
void duplicateReport(NGHolder &g, ReportID r_old, ReportID r_new); void duplicateReport(NGHolder &g, ReportID r_old, ReportID r_new);
#ifndef NDEBUG #ifndef NDEBUG
// Assertions: only available in internal builds
/** \brief Used in sanity-checking assertions: returns true if all vertices // Assertions: only available in internal builds.
* leading to accept or acceptEod have at least one report ID. */
/**
* Used in sanity-checking assertions: returns true if all vertices
* with edges to accept or acceptEod have at least one report ID. Additionally,
* checks that ONLY vertices with edges to accept or acceptEod has reports.
*/
bool allMatchStatesHaveReports(const NGHolder &g); bool allMatchStatesHaveReports(const NGHolder &g);
/**
* Assertion: returns true if the vertices in this graph are contiguously (and
* uniquely) numbered from zero.
*/
bool hasCorrectlyNumberedVertices(const NGHolder &g); bool hasCorrectlyNumberedVertices(const NGHolder &g);
/**
* Assertion: returns true if the edges in this graph are contiguously (and
* uniquely) numbered from zero.
*/
bool hasCorrectlyNumberedEdges(const NGHolder &g); bool hasCorrectlyNumberedEdges(const NGHolder &g);
#endif
#endif // NDEBUG
} // namespace ue2 } // namespace ue2

View File

@ -36,6 +36,7 @@
#include "nfa/nfa_internal.h" #include "nfa/nfa_internal.h"
#include "nfa/nfa_api_util.h" #include "nfa/nfa_api_util.h"
#include "nfagraph/ng_lbr.h" #include "nfagraph/ng_lbr.h"
#include "nfagraph/ng_util.h"
#include "util/alloc.h" #include "util/alloc.h"
#include "util/compile_context.h" #include "util/compile_context.h"
#include "grey.h" #include "grey.h"
@ -97,6 +98,7 @@ protected:
ParsedExpression parsed(0, pattern.c_str(), flags, 0); ParsedExpression parsed(0, pattern.c_str(), flags, 0);
unique_ptr<NGWrapper> g = buildWrapper(rm, cc, parsed); unique_ptr<NGWrapper> g = buildWrapper(rm, cc, parsed);
ASSERT_TRUE(g != nullptr); ASSERT_TRUE(g != nullptr);
clearReports(*g);
ASSERT_TRUE(isLBR(*g, grey)); ASSERT_TRUE(isLBR(*g, grey));

View File

@ -31,14 +31,15 @@
#include "grey.h" #include "grey.h"
#include "compiler/compiler.h" #include "compiler/compiler.h"
#include "nfagraph/ng.h"
#include "nfagraph/ng_limex.h"
#include "nfagraph/ng_restructuring.h"
#include "nfa/limex_context.h" #include "nfa/limex_context.h"
#include "nfa/limex_internal.h" #include "nfa/limex_internal.h"
#include "nfa/nfa_api.h" #include "nfa/nfa_api.h"
#include "nfa/nfa_api_util.h" #include "nfa/nfa_api_util.h"
#include "nfa/nfa_internal.h" #include "nfa/nfa_internal.h"
#include "nfagraph/ng.h"
#include "nfagraph/ng_limex.h"
#include "nfagraph/ng_restructuring.h"
#include "nfagraph/ng_util.h"
#include "util/alloc.h" #include "util/alloc.h"
#include "util/target_info.h" #include "util/target_info.h"
@ -76,6 +77,7 @@ protected:
ParsedExpression parsed(0, expr.c_str(), flags, 0); ParsedExpression parsed(0, expr.c_str(), flags, 0);
unique_ptr<NGWrapper> g = buildWrapper(rm, cc, parsed); unique_ptr<NGWrapper> g = buildWrapper(rm, cc, parsed);
ASSERT_TRUE(g != nullptr); ASSERT_TRUE(g != nullptr);
clearReports(*g);
rm.setProgramOffset(0, MATCH_REPORT); rm.setProgramOffset(0, MATCH_REPORT);
@ -310,10 +312,12 @@ protected:
ParsedExpression parsed(0, expr.c_str(), flags, 0); ParsedExpression parsed(0, expr.c_str(), flags, 0);
unique_ptr<NGWrapper> g = buildWrapper(rm, cc, parsed); unique_ptr<NGWrapper> g = buildWrapper(rm, cc, parsed);
ASSERT_TRUE(g != nullptr); ASSERT_TRUE(g != nullptr);
clearReports(*g);
// Reverse the graph and add some reports on the accept vertices. // Reverse the graph and add some reports on the accept vertices.
NGHolder g_rev(NFA_REV_PREFIX); NGHolder g_rev(NFA_REV_PREFIX);
reverseHolder(*g, g_rev); reverseHolder(*g, g_rev);
clearReports(g_rev);
for (NFAVertex v : inv_adjacent_vertices_range(g_rev.accept, g_rev)) { for (NFAVertex v : inv_adjacent_vertices_range(g_rev.accept, g_rev)) {
g_rev[v].reports.insert(0); g_rev[v].reports.insert(0);
} }
@ -367,6 +371,7 @@ protected:
ReportManager rm(cc.grey); ReportManager rm(cc.grey);
unique_ptr<NGWrapper> g = buildWrapper(rm, cc, parsed); unique_ptr<NGWrapper> g = buildWrapper(rm, cc, parsed);
ASSERT_TRUE(g != nullptr); ASSERT_TRUE(g != nullptr);
clearReports(*g);
rm.setProgramOffset(0, MATCH_REPORT); rm.setProgramOffset(0, MATCH_REPORT);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2015, Intel Corporation * Copyright (c) 2015-2016, 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:
@ -32,6 +32,7 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "nfagraph/ng_repeat.h" #include "nfagraph/ng_repeat.h"
#include "nfagraph/ng_util.h"
#include "util/depth.h" #include "util/depth.h"
#include "hs_compile.h" #include "hs_compile.h"
@ -89,12 +90,15 @@ static const PureRepeatTest pureRepeatTests[] = {
{ "^..?..?..?..?..?", 5, 10 } { "^..?..?..?..?..?", 5, 10 }
}; };
INSTANTIATE_TEST_CASE_P(PureRepeat, NFAPureRepeatTest, ValuesIn(pureRepeatTests)); INSTANTIATE_TEST_CASE_P(PureRepeat, NFAPureRepeatTest,
ValuesIn(pureRepeatTests));
TEST_P(NFAPureRepeatTest, Check) { TEST_P(NFAPureRepeatTest, Check) {
const PureRepeatTest &t = GetParam(); const PureRepeatTest &t = GetParam();
SCOPED_TRACE(testing::Message() << "Pattern: " << t.pattern); SCOPED_TRACE(testing::Message() << "Pattern: " << t.pattern);
unique_ptr<NGWrapper> w(constructGraph(t.pattern, HS_FLAG_ALLOWEMPTY)); auto w = constructGraph(t.pattern, HS_FLAG_ALLOWEMPTY);
ASSERT_TRUE(w != nullptr);
clearReports(*w);
PureRepeat repeat; PureRepeat repeat;
bool result = isPureRepeat(*w, repeat); bool result = isPureRepeat(*w, repeat);