diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f506e9b..8def2baf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -711,7 +711,6 @@ SET (hs_SRCS src/nfagraph/ng_extparam.h src/nfagraph/ng_fixed_width.cpp src/nfagraph/ng_fixed_width.h - src/nfagraph/ng_graph.h src/nfagraph/ng_haig.cpp src/nfagraph/ng_haig.h src/nfagraph/ng_holder.cpp @@ -933,6 +932,7 @@ SET (hs_SRCS src/util/target_info.cpp src/util/target_info.h src/util/ue2_containers.h + src/util/ue2_graph.h src/util/ue2string.cpp src/util/ue2string.h src/util/unaligned.h diff --git a/src/compiler/asserts.cpp b/src/compiler/asserts.cpp index 0365e268..e67fd8bc 100644 --- a/src/compiler/asserts.cpp +++ b/src/compiler/asserts.cpp @@ -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 * modification, are permitted provided that the following conditions are met: @@ -117,11 +117,11 @@ typedef map, NFAEdge> edge_cache_t; static void replaceAssertVertex(NGWrapper &g, NFAVertex t, edge_cache_t &edge_cache, u32 &assert_edge_count) { - DEBUG_PRINTF("replacing assert vertex %u\n", g[t].index); + DEBUG_PRINTF("replacing assert vertex %zu\n", g[t].index); const u32 flags = g[t].assert_flags; - DEBUG_PRINTF("consider assert vertex %u with flags %u\n", - g[t].index, flags); + DEBUG_PRINTF("consider assert vertex %zu with flags %u\n", g[t].index, + flags); // Wire up all the predecessors to all the successors. @@ -142,7 +142,7 @@ void replaceAssertVertex(NGWrapper &g, NFAVertex t, edge_cache_t &edge_cache, for (const auto &outEdge : out_edges_range(t, g)) { NFAVertex v = target(outEdge, g); - DEBUG_PRINTF("consider path [%u,%u,%u]\n", g[u].index, + DEBUG_PRINTF("consider path [%zu,%zu,%zu]\n", g[u].index, g[t].index, g[v].index); if (v == t) { @@ -173,8 +173,7 @@ void replaceAssertVertex(NGWrapper &g, NFAVertex t, edge_cache_t &edge_cache, auto cache_key = make_pair(u, v); auto ecit = edge_cache.find(cache_key); if (ecit == edge_cache.end()) { - DEBUG_PRINTF("adding edge %u %u\n", g[u].index, - g[v].index); + DEBUG_PRINTF("adding edge %zu %zu\n", g[u].index, g[v].index); NFAEdge e = add_edge(u, v, g).first; edge_cache.emplace(cache_key, e); g[e].assert_flags = flags; @@ -184,7 +183,7 @@ void replaceAssertVertex(NGWrapper &g, NFAVertex t, edge_cache_t &edge_cache, } } else { NFAEdge e = ecit->second; - DEBUG_PRINTF("updating edge %u %u [a %u]\n", g[u].index, + DEBUG_PRINTF("updating edge %zu %zu [a %zu]\n", g[u].index, g[v].index, g[t].index); // Edge already exists. u32 &e_flags = g[e].assert_flags; @@ -211,8 +210,7 @@ void setReportId(ReportManager &rm, NGWrapper &g, NFAVertex v, s32 adj) { Report r = rm.getBasicInternalReport(g, adj); g[v].reports.insert(rm.getInternalId(r)); - DEBUG_PRINTF("set report id for vertex %u, adj %d\n", - g[v].index, adj); + DEBUG_PRINTF("set report id for vertex %zu, adj %d\n", g[v].index, adj); } static @@ -222,8 +220,7 @@ void checkForMultilineStart(ReportManager &rm, NGWrapper &g) { if (!(g[v].assert_flags & POS_FLAG_MULTILINE_START)) { continue; } - DEBUG_PRINTF("mls %u %08x\n", g[v].index, - g[v].assert_flags); + DEBUG_PRINTF("mls %zu %08x\n", g[v].index, g[v].assert_flags); /* we have found a multi-line start (maybe more than one) */ @@ -299,8 +296,8 @@ void removeAssertVertices(ReportManager &rm, NGWrapper &g) { DEBUG_PRINTF("resolved %zu assert vertices\n", num); pruneUseless(g); pruneEmptyVertices(g); - g.renumberVertices(); - g.renumberEdges(); + renumber_vertices(g); + renumber_edges(g); } DEBUG_PRINTF("after: graph has %zu vertices\n", num_vertices(g)); diff --git a/src/nfa/accel_dfa_build_strat.cpp b/src/nfa/accel_dfa_build_strat.cpp index ba21adc7..70d2d103 100644 --- a/src/nfa/accel_dfa_build_strat.cpp +++ b/src/nfa/accel_dfa_build_strat.cpp @@ -56,15 +56,6 @@ struct path { }; }; -static UNUSED -string describeClasses(const vector &v) { - std::ostringstream oss; - for (const auto &cr : v) { - describeClass(oss, cr); - } - return oss.str(); -} - static void dump_paths(const vector &paths) { for (UNUSED const auto &p : paths) { diff --git a/src/nfa/castlecompile.cpp b/src/nfa/castlecompile.cpp index b76078f9..fb685f21 100644 --- a/src/nfa/castlecompile.cpp +++ b/src/nfa/castlecompile.cpp @@ -58,6 +58,7 @@ #include #include +#include #include using namespace std; @@ -981,7 +982,7 @@ unique_ptr makeHolder(const CastleProto &proto, addToHolder(*g, m.first, m.second); } - //dumpGraph("castle_holder.dot", g->g); + //dumpGraph("castle_holder.dot", *g); // Sanity checks. assert(allMatchStatesHaveReports(*g)); diff --git a/src/nfa/limex_compile.cpp b/src/nfa/limex_compile.cpp index b7ea93d9..481113e3 100644 --- a/src/nfa/limex_compile.cpp +++ b/src/nfa/limex_compile.cpp @@ -494,7 +494,7 @@ void nfaFindAccelSchemes(const NGHolder &g, // We want to skip any vertices that don't lead to at least one other // (self-loops don't count) vertex. if (!has_proper_successor(v, g)) { - DEBUG_PRINTF("skipping vertex %u\n", g[v].index); + DEBUG_PRINTF("skipping vertex %zu\n", g[v].index); continue; } @@ -502,7 +502,7 @@ void nfaFindAccelSchemes(const NGHolder &g, AccelScheme as; if (nfaCheckAccel(g, v, refined_cr, br_cyclic, &as, allow_wide)) { - DEBUG_PRINTF("graph vertex %u is accelerable with offset %u.\n", + DEBUG_PRINTF("graph vertex %zu is accelerable with offset %u.\n", g[v].index, as.offset); (*out)[v] = as; } @@ -514,7 +514,7 @@ struct fas_visitor : public boost::default_bfs_visitor { ue2::unordered_map *out_in) : accel_map(am_in), out(out_in) {} - void discover_vertex(NFAVertex v, const NFAGraph &) { + void discover_vertex(NFAVertex v, const NGHolder &) { if (accel_map.find(v) != accel_map.end()) { (*out)[v] = accel_map.find(v)->second; } @@ -552,11 +552,10 @@ void filterAccelStates(NGHolder &g, const map> &tops, try { vector colour(num_vertices(g)); - breadth_first_search( - g.g, g.start, + boost::breadth_first_search(g, g.start, visitor(fas_visitor(*accel_map, &out)) - .color_map(make_iterator_property_map( - colour.begin(), get(&NFAGraphVertexProps::index, g.g)))); + .color_map(make_iterator_property_map(colour.begin(), + get(vertex_index, g)))); } catch (fas_visitor *) { ; /* found max accel_states */ } @@ -628,7 +627,7 @@ void fillAccelInfo(build_info &bi) { /* for each subset of the accel keys need to find an accel scheme */ assert(astates.size() < 32); - sort(astates.begin(), astates.end(), make_index_ordering(g)); + sort(astates.begin(), astates.end()); for (u32 i = 1, i_end = 1U << astates.size(); i < i_end; i++) { DEBUG_PRINTF("saving info for accel %u\n", i); @@ -2335,8 +2334,7 @@ bool isSane(const NGHolder &h, const map> &tops, for (auto v : vertices_range(h)) { if (!contains(state_ids, v)) { - DEBUG_PRINTF("no entry for vertex %u in state map\n", - h[v].index); + DEBUG_PRINTF("no entry for vertex %zu in state map\n", h[v].index); return false; } const u32 i = state_ids.at(v); @@ -2344,8 +2342,7 @@ bool isSane(const NGHolder &h, const map> &tops, continue; } - DEBUG_PRINTF("checking vertex %u (state %u)\n", h[v].index, - i); + DEBUG_PRINTF("checking vertex %zu (state %u)\n", h[v].index, i); if (i >= num_states || contains(seen, i)) { DEBUG_PRINTF("vertex %u/%u has invalid state\n", i, num_states); @@ -2355,7 +2352,7 @@ bool isSane(const NGHolder &h, const map> &tops, // All our states should be reachable and have a state assigned. if (h[v].char_reach.none()) { - DEBUG_PRINTF("vertex %u has empty reachability\n", h[v].index); + DEBUG_PRINTF("vertex %zu has empty reachability\n", h[v].index); return false; } @@ -2363,7 +2360,7 @@ bool isSane(const NGHolder &h, const map> &tops, // must have at least one predecessor that is not itself. if (v != h.start && v != h.startDs && !contains(top_starts, v) && !proper_in_degree(v, h)) { - DEBUG_PRINTF("vertex %u has no pred\n", h[v].index); + DEBUG_PRINTF("vertex %zu has no pred\n", h[v].index); return false; } } diff --git a/src/nfagraph/ng.cpp b/src/nfagraph/ng.cpp index 071e5c63..dff9c7e8 100644 --- a/src/nfagraph/ng.cpp +++ b/src/nfagraph/ng.cpp @@ -203,6 +203,7 @@ static bool addComponent(NG &ng, NGHolder &g, const NGWrapper &w, const som_type som, const u32 comp_id) { const CompileContext &cc = ng.cc; + assert(hasCorrectlyNumberedVertices(g)); DEBUG_PRINTF("expr=%u, comp=%u: %zu vertices, %zu edges\n", w.expressionIndex, comp_id, num_vertices(g), num_edges(g)); diff --git a/src/nfagraph/ng_anchored_dots.cpp b/src/nfagraph/ng_anchored_dots.cpp index ba352e60..ed9c7f48 100644 --- a/src/nfagraph/ng_anchored_dots.cpp +++ b/src/nfagraph/ng_anchored_dots.cpp @@ -202,7 +202,7 @@ void reformAnchoredRepeatsComponent(NGHolder &g, } if (!isStartNode(dotV, g.start, g, true)) { - DEBUG_PRINTF("fleeing: vertex %u has other preds\n", g[dotV].index); + DEBUG_PRINTF("fleeing: vertex %zu has other preds\n", g[dotV].index); return; } @@ -249,7 +249,7 @@ void reformAnchoredRepeatsComponent(NGHolder &g, remove_edge(g.start, v, g); } - DEBUG_PRINTF("removing vertex %u\n", g[dotV].index); + DEBUG_PRINTF("removing vertex %zu\n", g[dotV].index); clear_vertex(dotV, g); dead.insert(dotV); compAnchoredStarts.erase(dotV); @@ -313,14 +313,15 @@ void reformUnanchoredRepeatsComponent(NGHolder &g, } // A self-loop indicates that this is a '.+' or '.*' - DEBUG_PRINTF("self-loop detected on %u\n", g[dotV].index); + DEBUG_PRINTF("self-loop detected on %zu\n", g[dotV].index); *startEnd = depth::infinity(); remove_edge(dotV, dotV, g); return; } if (!isStartNode(dotV, g.startDs, g, true)) { - DEBUG_PRINTF("fleeing: vertex %u has other preds\n", g[dotV].index); + DEBUG_PRINTF("fleeing: vertex %zu has other preds\n", + g[dotV].index); return; } @@ -362,14 +363,14 @@ void reformUnanchoredRepeatsComponent(NGHolder &g, compUnanchoredStarts.clear(); for (auto t : adjacent_vertices_range(dotV, g)) { if (t != dotV) { - DEBUG_PRINTF("connecting sds -> %u\n", g[t].index); + DEBUG_PRINTF("connecting sds -> %zu\n", g[t].index); add_edge(g.startDs, t, g); add_edge(g.start, t, g); compUnanchoredStarts.insert(t); } } - DEBUG_PRINTF("removing vertex %u\n", g[dotV].index); + DEBUG_PRINTF("removing vertex %zu\n", g[dotV].index); dead.insert(dotV); clear_vertex(dotV, g); compUnanchoredStarts.erase(dotV); @@ -416,7 +417,7 @@ bool gatherParticipants(const NGHolder &g, if (isOptionalDot(t, v, g)) { // another dot; bail if we've seen it once already if (dots.find(t) != dots.end()) { - DEBUG_PRINTF("cycle detected at vertex %u\n", g[t].index); + DEBUG_PRINTF("cycle detected at vertex %zu\n", g[t].index); return false; } dots.insert(t); @@ -432,7 +433,7 @@ bool gatherParticipants(const NGHolder &g, for (auto w : adjacent_vertices_range(v, g)) { succ.insert(w); if (!edge(start, w, g).second) { - DEBUG_PRINTF("failing, vertex %u does not have edge from start\n", + DEBUG_PRINTF("failing, vertex %zu does not have edge from start\n", g[w].index); return false; } @@ -474,7 +475,7 @@ void collapseVariableDotRepeat(NGHolder &g, NFAVertex start, return; } initialDot = v; - DEBUG_PRINTF("initial dot vertex is %u\n", g[v].index); + DEBUG_PRINTF("initial dot vertex is %zu\n", g[v].index); } } @@ -507,12 +508,8 @@ void collapseVariableDotRepeat(NGHolder &g, NFAVertex start, } assert(startEnd->is_reachable()); - // For determinism, copy and sort our successor vertices. - deque s(succ.begin(), succ.end()); - sort(s.begin(), s.end(), make_index_ordering(g)); - // Connect our successor vertices to both start and startDs. - for (auto v : s) { + for (auto v : succ) { add_edge_if_not_present(g.start, v, g); add_edge_if_not_present(g.startDs, v, g); } @@ -637,8 +634,8 @@ void restoreLeadingDots(NGHolder &g, const depth &startBegin, } addDotsBetween(g, root, rhs, startBegin, startEnd); - g.renumberVertices(); - g.renumberEdges(); + renumber_vertices(g); + renumber_edges(g); } // Entry point. diff --git a/src/nfagraph/ng_asserts.cpp b/src/nfagraph/ng_asserts.cpp index e9e39345..e0d43e7b 100644 --- a/src/nfagraph/ng_asserts.cpp +++ b/src/nfagraph/ng_asserts.cpp @@ -101,7 +101,7 @@ vector getAsserts(const NGHolder &g) { static void addToSplit(const NGHolder &g, NFAVertex v, map *to_split) { - DEBUG_PRINTF("%u needs splitting\n", g[v].index); + DEBUG_PRINTF("%zu needs splitting\n", g[v].index); to_split->emplace(g[v].index, v); } @@ -194,7 +194,7 @@ void setReportId(ReportManager &rm, NGWrapper &g, NFAVertex v, s32 adj) { Report ir = rm.getBasicInternalReport(g, adj); g[v].reports.insert(rm.getInternalId(ir)); - DEBUG_PRINTF("set report id for vertex %u, adj %d\n", g[v].index, adj); + DEBUG_PRINTF("set report id for vertex %zu, adj %d\n", g[v].index, adj); } static @@ -224,7 +224,7 @@ void splitVertex(ReportManager &rm, NGWrapper &g, NFAVertex v, bool ucp) { assert(v != g.start); assert(v != g.accept); assert(v != g.acceptEod); - DEBUG_PRINTF("partitioning vertex %u ucp:%d\n", g[v].index, (int)ucp); + DEBUG_PRINTF("partitioning vertex %zu ucp:%d\n", g[v].index, (int)ucp); CharReach cr_word = ucp ? CHARREACH_WORD_UCP_PRE : CHARREACH_WORD; CharReach cr_nonword = ucp ? CHARREACH_NONWORD_UCP_PRE : CHARREACH_NONWORD; @@ -267,8 +267,8 @@ void resolveEdges(ReportManager &rm, NGWrapper &g, set *dead) { bool impassable = true; bool ucp = flags & UCP_ASSERT_FLAGS; - DEBUG_PRINTF("resolving edge %u->%u (flags=0x%x, ucp=%d)\n", g[u].index, - g[v].index, flags, (int)ucp); + DEBUG_PRINTF("resolving edge %zu->%zu (flags=0x%x, ucp=%d)\n", + g[u].index, g[v].index, flags, (int)ucp); while (flags && impassable) { u32 flag = 1U << findAndClearLSB_32(&flags); switch (flag) { @@ -482,12 +482,12 @@ void resolveAsserts(ReportManager &rm, NGWrapper &g) { resolveEdges(rm, g, &dead); remove_edges(dead, g); - g.renumberVertices(); + renumber_vertices(g); pruneUseless(g); pruneEmptyVertices(g); - g.renumberVertices(); - g.renumberEdges(); + renumber_vertices(g); + renumber_edges(g); clearReports(g); } @@ -552,7 +552,7 @@ void ensureCodePointStart(ReportManager &rm, NGWrapper &g) { add_edge(g.start, v_4, g); add_edge(g.startDs, v_4, g); remove_edge(orig, g); - g.renumberEdges(); + renumber_edges(g); clearReports(g); } } diff --git a/src/nfagraph/ng_builder.cpp b/src/nfagraph/ng_builder.cpp index 8a92b7ee..6e1ea71e 100644 --- a/src/nfagraph/ng_builder.cpp +++ b/src/nfagraph/ng_builder.cpp @@ -132,7 +132,7 @@ NFAVertex NFABuilderImpl::getVertex(Position pos) const { assert(id2vertex.size() >= pos); const NFAVertex v = id2vertex[pos]; assert(v != NGHolder::null_vertex()); - assert(graph->g[v].index == pos); + assert((*graph)[v].index == pos); return v; } @@ -147,7 +147,7 @@ void NFABuilderImpl::addVertex(Position pos) { id2vertex.resize(pos + 1); } id2vertex[pos] = v; - graph->g[v].index = pos; + (*graph)[v].index = pos; } unique_ptr NFABuilderImpl::getGraph() { @@ -177,22 +177,22 @@ void NFABuilderImpl::setNodeReportID(Position pos, int offsetAdjust) { void NFABuilderImpl::addCharReach(Position pos, const CharReach &cr) { NFAVertex v = getVertex(pos); - graph->g[v].char_reach |= cr; + (*graph)[v].char_reach |= cr; } void NFABuilderImpl::setAssertFlag(Position pos, u32 flag) { NFAVertex v = getVertex(pos); - graph->g[v].assert_flags |= flag; + (*graph)[v].assert_flags |= flag; } u32 NFABuilderImpl::getAssertFlag(Position pos) { NFAVertex v = getVertex(pos); - return graph->g[v].assert_flags; + return (*graph)[v].assert_flags; } pair NFABuilderImpl::addEdge(NFAVertex u, NFAVertex v) { // assert that the edge doesn't already exist - assert(edge(u, v, graph->g).second == false); + assert(edge(u, v, *graph).second == false); pair e = add_edge(u, v, *graph); assert(e.second); @@ -209,16 +209,16 @@ void NFABuilderImpl::addEdge(Position startPos, Position endPos) { if ((u == graph->start || u == graph->startDs) && v == graph->startDs) { /* standard special -> special edges already exist */ - assert(edge(u, v, graph->g).second == true); + assert(edge(u, v, *graph).second == true); return; } - assert(edge(u, v, graph->g).second == false); + assert(edge(u, v, *graph).second == false); addEdge(u, v); } bool NFABuilderImpl::hasEdge(Position startPos, Position endPos) const { - return edge(getVertex(startPos), getVertex(endPos), graph->g).second; + return edge(getVertex(startPos), getVertex(endPos), *graph).second; } Position NFABuilderImpl::getStart() const { @@ -252,7 +252,7 @@ Position NFABuilderImpl::makePositions(size_t nPositions) { } void NFABuilderImpl::cloneRegion(Position first, Position last, unsigned posOffset) { - NFAGraph &g = graph->g; + NGHolder &g = *graph; assert(posOffset > 0); // walk the nodes between first and last and copy their vertex properties diff --git a/src/nfagraph/ng_calc_components.cpp b/src/nfagraph/ng_calc_components.cpp index 658e7001..da6775e4 100644 --- a/src/nfagraph/ng_calc_components.cpp +++ b/src/nfagraph/ng_calc_components.cpp @@ -162,7 +162,7 @@ flat_set findHeadShell(const NGHolder &g, } for (UNUSED auto v : shell) { - DEBUG_PRINTF("shell: %u\n", g[v].index); + DEBUG_PRINTF("shell: %zu\n", g[v].index); } return shell; @@ -184,7 +184,7 @@ flat_set findTailShell(const NGHolder &g, } for (UNUSED auto v : shell) { - DEBUG_PRINTF("shell: %u\n", g[v].index); + DEBUG_PRINTF("shell: %zu\n", g[v].index); } return shell; @@ -209,7 +209,8 @@ vector findShellEdges(const NGHolder &g, if ((is_special(u, g) || contains(head_shell, u)) && (is_special(v, g) || contains(tail_shell, v))) { - DEBUG_PRINTF("edge (%u,%u) is a shell edge\n", g[u].index, g[v].index); + DEBUG_PRINTF("edge (%zu,%zu) is a shell edge\n", g[u].index, + g[v].index); shell_edges.push_back(e); } } @@ -275,9 +276,8 @@ void splitIntoComponents(const NGHolder &g, deque> &comps, NFAUndirectedGraph ug; ue2::unordered_map old2new; - ue2::unordered_map newIdx2old; - createUnGraph(g.g, true, true, ug, old2new, newIdx2old); + createUnGraph(g, true, true, ug, old2new); // Construct reverse mapping. ue2::unordered_map new2old; @@ -313,7 +313,7 @@ void splitIntoComponents(const NGHolder &g, deque> &comps, assert(contains(new2old, uv)); NFAVertex v = new2old.at(uv); verts[c].push_back(v); - DEBUG_PRINTF("vertex %u 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 v_map; // temp map for fillHolder @@ -322,8 +322,9 @@ void splitIntoComponents(const NGHolder &g, deque> &comps, vv.insert(vv.end(), begin(head_shell), end(head_shell)); vv.insert(vv.end(), begin(tail_shell), end(tail_shell)); - // Sort by vertex index for determinism. - sort(begin(vv), end(vv), VertexIndexOrdering(g)); + /* Sort for determinism. Still required as NFAUndirectedVertex have + * no deterministic ordering (split_components map). */ + sort(begin(vv), end(vv)); auto gc = ue2::make_unique(); v_map.clear(); @@ -349,9 +350,6 @@ void splitIntoComponents(const NGHolder &g, deque> &comps, vv.insert(vv.end(), begin(head_shell), end(head_shell)); vv.insert(vv.end(), begin(tail_shell), end(tail_shell)); - // Sort by vertex index for determinism. - sort(begin(vv), end(vv), VertexIndexOrdering(g)); - auto gc = ue2::make_unique(); v_map.clear(); fillHolder(gc.get(), g, vv, &v_map); diff --git a/src/nfagraph/ng_cyclic_redundancy.cpp b/src/nfagraph/ng_cyclic_redundancy.cpp index e2272264..9ae4458c 100644 --- a/src/nfagraph/ng_cyclic_redundancy.cpp +++ b/src/nfagraph/ng_cyclic_redundancy.cpp @@ -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 * modification, are permitted provided that the following conditions are met: @@ -99,7 +99,7 @@ class SearchVisitor : public boost::default_dfs_visitor { template void discover_vertex(const Vertex &v, const Graph &g) const { - DEBUG_PRINTF("vertex %u\n", g[v].index); + DEBUG_PRINTF("vertex %zu\n", g[v].index); if (is_special(v, g)) { DEBUG_PRINTF("start or accept\n"); throw SearchFailed(); @@ -141,24 +141,16 @@ bool searchForward(const Graph &g, const CharReach &reach, } static -NFAEdge to_raw(const NFAEdge &e, const NFAGraph &, const NGHolder &) { +NFAEdge to_raw(const NFAEdge &e, const NGHolder &) { return e; } static -NFAEdge to_raw(const reverse_graph::edge_descriptor &e, - const reverse_graph &g, - const NGHolder &raw) { - /* clang doesn't seem to like edge_underlying */ - NFAVertex t = source(e, g); - NFAVertex s = target(e, g); - - assert(edge(s, t, raw).second); - - return edge(s, t, raw).first; +NFAEdge to_raw(const reverse_graph::edge_descriptor &e, + const reverse_graph &g) { + return get(boost::edge_underlying, g, e); } - /* returns true if we did stuff */ template static @@ -185,7 +177,7 @@ bool removeCyclicPathRedundancy(Graph &g, typename Graph::vertex_descriptor v, continue; } - DEBUG_PRINTF("- checking u %u\n", g[u].index); + DEBUG_PRINTF("- checking u %zu\n", g[u].index); // let s be intersection(succ(u), succ(v)) s.clear(); @@ -206,17 +198,18 @@ bool removeCyclicPathRedundancy(Graph &g, typename Graph::vertex_descriptor v, continue; } - DEBUG_PRINTF(" - checking w %u\n", g[w].index); + DEBUG_PRINTF(" - checking w %zu\n", g[w].index); - if (searchForward(g, reach, s, w)) { - DEBUG_PRINTF("removing edge (%u,%u)\n", - g[u].index, g[w].index); - /* we are currently iterating over the in-edges of v, so it - would be unwise to remove edges to v. However, */ - assert(w != v); /* as v is in s */ - remove_edge(to_raw(e_u, g, raw), raw); - did_stuff = true; + if (!searchForward(g, reach, s, w)) { + continue; } + + DEBUG_PRINTF("removing edge (%zu,%zu)\n", g[u].index, g[w].index); + /* we are currently iterating over the in-edges of v, so it + would be unwise to remove edges to v. However, */ + assert(w != v); /* as v is in s */ + remove_edge(to_raw(e_u, g), raw); + did_stuff = true; } } @@ -233,7 +226,7 @@ bool cyclicPathRedundancyPass(Graph &g, NGHolder &raw) { continue; } - DEBUG_PRINTF("examining cyclic vertex %u\n", g[v].index); + DEBUG_PRINTF("examining cyclic vertex %zu\n", g[v].index); did_stuff |= removeCyclicPathRedundancy(g, v, raw); } @@ -242,7 +235,7 @@ bool cyclicPathRedundancyPass(Graph &g, NGHolder &raw) { bool removeCyclicPathRedundancy(NGHolder &g) { // Forward pass. - bool f_changed = cyclicPathRedundancyPass(g.g, g); + bool f_changed = cyclicPathRedundancyPass(g, g); if (f_changed) { DEBUG_PRINTF("edges removed by forward pass\n"); pruneUseless(g); @@ -250,8 +243,8 @@ bool removeCyclicPathRedundancy(NGHolder &g) { // Reverse pass. DEBUG_PRINTF("REVERSE PASS\n"); - typedef reverse_graph RevGraph; - RevGraph revg(g.g); + typedef reverse_graph RevGraph; + RevGraph revg(g); bool r_changed = cyclicPathRedundancyPass(revg, g); if (r_changed) { DEBUG_PRINTF("edges removed by reverse pass\n"); diff --git a/src/nfagraph/ng_depth.cpp b/src/nfagraph/ng_depth.cpp index 8afa644a..5111b752 100644 --- a/src/nfagraph/ng_depth.cpp +++ b/src/nfagraph/ng_depth.cpp @@ -44,11 +44,14 @@ #include #include #include +#include using namespace std; using boost::filtered_graph; +using boost::make_filtered_graph; using boost::make_constant_property; using boost::reverse_graph; +using boost::adaptors::reverse; namespace ue2 { @@ -122,25 +125,23 @@ private: template static -void findLoopReachable(const GraphT &g, const NFAVertex srcVertex, +void findLoopReachable(const GraphT &g, + const typename GraphT::vertex_descriptor srcVertex, vector &deadNodes) { typedef typename GraphT::edge_descriptor EdgeT; + typedef typename GraphT::vertex_descriptor VertexT; typedef set EdgeSet; EdgeSet deadEdges; BackEdges be(deadEdges); - auto index_map = get(&NFAGraphVertexProps::index, g); - - depth_first_search(g, visitor(be).root_vertex(srcVertex).vertex_index_map( - index_map)); + depth_first_search(g, visitor(be).root_vertex(srcVertex)); auto af = make_bad_edge_filter(&deadEdges); auto acyclic_g = make_filtered_graph(g, af); - vector topoOrder; /* actually reverse topological order */ + vector topoOrder; /* actually reverse topological order */ topoOrder.reserve(deadNodes.size()); - topological_sort(acyclic_g, back_inserter(topoOrder), - vertex_index_map(index_map)); + topological_sort(acyclic_g, back_inserter(topoOrder)); for (const auto &e : deadEdges) { u32 srcIdx = g[source(e, g)].index; @@ -149,8 +150,7 @@ void findLoopReachable(const GraphT &g, const NFAVertex srcVertex, } } - for (auto it = topoOrder.rbegin(); it != topoOrder.rend(); ++it) { - NFAVertex v = *it; + for (VertexT v : reverse(topoOrder)) { for (const auto &e : in_edges_range(v, g)) { if (deadNodes[g[source(e, g)].index]) { deadNodes[g[v].index] = true; @@ -194,22 +194,20 @@ void calcDepthFromSource(const NGHolder &graph, const GraphT &g, using boost::make_iterator_property_map; - auto min_index_map = get(&NFAGraphVertexProps::index, mindist_g); + auto min_index_map = get(vertex_index, mindist_g); breadth_first_search(mindist_g, srcVertex, - boost::vertex_index_map(min_index_map). visitor(make_bfs_visitor(record_distances( - make_iterator_property_map( - dMin.begin(), min_index_map), + make_iterator_property_map(dMin.begin(), + min_index_map), boost::on_tree_edge())))); - auto max_index_map = get(&NFAGraphVertexProps::index, maxdist_g); + auto max_index_map = get(vertex_index, maxdist_g); dag_shortest_paths(maxdist_g, srcVertex, - boost::vertex_index_map(max_index_map). - distance_map(make_iterator_property_map(dMax.begin(), - max_index_map)). - weight_map(make_constant_property(-1))); + distance_map(make_iterator_property_map(dMax.begin(), + max_index_map)) + .weight_map(make_constant_property(-1))); for (size_t i = 0; i < numVerts; i++) { if (dMin[i] > DIST_UNREACHABLE) { @@ -285,14 +283,14 @@ void calcDepths(const NGHolder &g, std::vector &depths) { * reachable from a loop need to be removed */ vector deadNodes(numVertices); - findLoopReachable(g.g, g.start, deadNodes); + findLoopReachable(g, g.start, deadNodes); DEBUG_PRINTF("doing start\n"); - calcAndStoreDepth(g, g.g, g.start, deadNodes, dMin, dMax, - depths, &NFAVertexDepth::fromStart); + calcAndStoreDepth(g, g, g.start, deadNodes, dMin, dMax, depths, + &NFAVertexDepth::fromStart); DEBUG_PRINTF("doing startds\n"); - calcAndStoreDepth(g, g.g, g.startDs, deadNodes, dMin, dMax, - depths, &NFAVertexDepth::fromStartDotStar); + calcAndStoreDepth(g, g, g.startDs, deadNodes, dMin, dMax, depths, + &NFAVertexDepth::fromStartDotStar); } void calcDepths(const NGHolder &g, std::vector &depths) { @@ -305,8 +303,8 @@ void calcDepths(const NGHolder &g, std::vector &depths) { vector dMax; /* reverse the graph before walking it */ - typedef reverse_graph RevNFAGraph; - const RevNFAGraph rg(g.g); + typedef reverse_graph RevNFAGraph; + const RevNFAGraph rg(g); /* * create a filtered graph for max depth calculations: all nodes/edges @@ -340,20 +338,20 @@ void calcDepths(const NGHolder &g, vector &depths) { * reachable from a loop need to be removed */ vector deadNodes(numVertices); - findLoopReachable(g.g, g.start, deadNodes); + findLoopReachable(g, g.start, deadNodes); DEBUG_PRINTF("doing start\n"); - calcAndStoreDepth( - g, g.g, g.start, deadNodes, dMin, dMax, depths, + calcAndStoreDepth( + g, g, g.start, deadNodes, dMin, dMax, depths, &NFAVertexBidiDepth::fromStart); DEBUG_PRINTF("doing startds\n"); - calcAndStoreDepth( - g, g.g, g.startDs, deadNodes, dMin, dMax, depths, + calcAndStoreDepth( + g, g, g.startDs, deadNodes, dMin, dMax, depths, &NFAVertexBidiDepth::fromStartDotStar); /* Now go backwards */ - typedef reverse_graph RevNFAGraph; - const RevNFAGraph rg(g.g); + typedef reverse_graph RevNFAGraph; + const RevNFAGraph rg(g); deadNodes.assign(numVertices, false); findLoopReachable(rg, g.acceptEod, deadNodes); @@ -374,10 +372,10 @@ void calcDepthsFrom(const NGHolder &g, const NFAVertex src, const size_t numVertices = num_vertices(g); vector deadNodes(numVertices); - findLoopReachable(g.g, g.start, deadNodes); + findLoopReachable(g, g.start, deadNodes); vector dMin, dMax; - calcDepthFromSource(g, g.g, src, deadNodes, dMin, dMax); + calcDepthFromSource(g, g, src, deadNodes, dMin, dMax); depths.clear(); depths.resize(numVertices); diff --git a/src/nfagraph/ng_dominators.cpp b/src/nfagraph/ng_dominators.cpp index 05650aaf..d01af994 100644 --- a/src/nfagraph/ng_dominators.cpp +++ b/src/nfagraph/ng_dominators.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-16, Intel Corporation + * Copyright (c) 2015-2016, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -48,37 +48,45 @@ using boost::make_iterator_property_map; namespace ue2 { template -ue2::unordered_map calcDominators(const Graph &g, - NFAVertex source) { +unordered_map calcDominators(const Graph &g, + typename Graph::vertex_descriptor source) { + using Vertex = typename Graph::vertex_descriptor; const size_t num_verts = num_vertices(g); auto index_map = get(&NFAGraphVertexProps::index, g); vector dfnum(num_verts, 0); - vector parents(num_verts, Graph::null_vertex()); + vector parents(num_verts, Graph::null_vertex()); auto dfnum_map = make_iterator_property_map(dfnum.begin(), index_map); auto parent_map = make_iterator_property_map(parents.begin(), index_map); - vector vertices_by_dfnum(num_verts, Graph::null_vertex()); + vector vertices_by_dfnum(num_verts, Graph::null_vertex()); // Output map. - unordered_map doms; + unordered_map doms; auto dom_map = make_assoc_property_map(doms); boost_ue2::lengauer_tarjan_dominator_tree(g, source, index_map, dfnum_map, parent_map, vertices_by_dfnum, dom_map); - return doms; + /* Translate back to an NFAVertex map */ + unordered_map doms2; + for (const auto &e : doms) { + NFAVertex f(e.first); + NFAVertex s(e.second); + doms2[f] = s; + } + return doms2; } -ue2::unordered_map findDominators(const NGHolder &g) { +unordered_map findDominators(const NGHolder &g) { assert(hasCorrectlyNumberedVertices(g)); - return calcDominators(g.g, g.start); + return calcDominators(g, g.start); } -ue2::unordered_map findPostDominators(const NGHolder &g) { +unordered_map findPostDominators(const NGHolder &g) { assert(hasCorrectlyNumberedVertices(g)); - return calcDominators(boost::reverse_graph(g.g), + return calcDominators(boost::reverse_graph(g), g.acceptEod); } diff --git a/src/nfagraph/ng_dump.cpp b/src/nfagraph/ng_dump.cpp index 7c1894a3..fc840f25 100644 --- a/src/nfagraph/ng_dump.cpp +++ b/src/nfagraph/ng_dump.cpp @@ -285,7 +285,7 @@ void dumpGraphImpl(const char *name, const GraphT &g, } // manual instantiation of templated dumpGraph above. -template void dumpGraphImpl(const char *, const NFAGraph &); +template void dumpGraphImpl(const char *, const NGHolder &); void dumpDotWrapperImpl(const NGWrapper &nw, const char *name, const Grey &grey) { @@ -293,7 +293,7 @@ void dumpDotWrapperImpl(const NGWrapper &nw, const char *name, stringstream ss; ss << grey.dumpPath << "Expr_" << nw.expressionIndex << "_" << name << ".dot"; DEBUG_PRINTF("dumping dot graph to '%s'\n", ss.str().c_str()); - dumpGraphImpl(ss.str().c_str(), nw.g); + dumpGraphImpl(ss.str().c_str(), nw); } } @@ -304,7 +304,7 @@ void dumpComponentImpl(const NGHolder &g, const char *name, u32 expr, ss << grey.dumpPath << "Comp_" << expr << "-" << comp << "_" << name << ".dot"; DEBUG_PRINTF("dumping dot graph to '%s'\n", ss.str().c_str()); - dumpGraphImpl(ss.str().c_str(), g.g); + dumpGraphImpl(ss.str().c_str(), g); } } @@ -315,7 +315,7 @@ void dumpSomSubComponentImpl(const NGHolder &g, const char *name, u32 expr, ss << grey.dumpPath << "Comp_" << expr << "-" << comp << "_" << name << "_" << plan << ".dot"; DEBUG_PRINTF("dumping dot graph to '%s'\n", ss.str().c_str()); - dumpGraphImpl(ss.str().c_str(), g.g); + dumpGraphImpl(ss.str().c_str(), g); } } @@ -325,7 +325,7 @@ void dumpHolderImpl(const NGHolder &h, unsigned int stageNumber, stringstream ss; ss << grey.dumpPath << "Holder_X_" << stageNumber << "-" << stageName << ".dot"; - dumpGraphImpl(ss.str().c_str(), h.g); + dumpGraphImpl(ss.str().c_str(), h); } } @@ -337,7 +337,7 @@ void dumpHolderImpl(const NGHolder &h, stringstream ss; ss << grey.dumpPath << "Holder_X_" << stageNumber << "-" << stageName << ".dot"; - dumpGraphImpl(ss.str().c_str(), h.g, region_map); + dumpGraphImpl(ss.str().c_str(), h, region_map); } } diff --git a/src/nfagraph/ng_edge_redundancy.cpp b/src/nfagraph/ng_edge_redundancy.cpp index 5944cfef..3ce62c41 100644 --- a/src/nfagraph/ng_edge_redundancy.cpp +++ b/src/nfagraph/ng_edge_redundancy.cpp @@ -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 * modification, are permitted provided that the following conditions are met: @@ -297,9 +297,8 @@ bool checkFwdCandidate(const NGHolder &g, NFAVertex fixed_src, return false; } - DEBUG_PRINTF("edge (%u, %u) killed by edge (%u, %u)\n", - g[w].index, g[v].index, - g[fixed_src].index, g[v].index); + DEBUG_PRINTF("edge (%zu, %zu) killed by edge (%zu, %zu)\n", + g[w].index, g[v].index, g[fixed_src].index, g[v].index); return true; } @@ -415,7 +414,7 @@ bool removeEdgeRedundancyFwd(NGHolder &g, bool ignore_starts) { pred(g, u, &parents_u); done.clear(); - if (hasGreaterOutDegree(1, u, g)) { + if (out_degree(u, g) > 1) { checkLargeOutU(g, u, parents_u, possible_w, done, &dead); } else { checkSmallOutU(g, u, parents_u, done, &dead); @@ -460,7 +459,7 @@ bool removeSiblingsOfStartDotStar(NGHolder &g) { vector dead; for (auto v : adjacent_vertices_range(g.startDs, g)) { - DEBUG_PRINTF("checking %u\n", g[v].index); + DEBUG_PRINTF("checking %zu\n", g[v].index); if (is_special(v, g)) { continue; } @@ -470,8 +469,7 @@ bool removeSiblingsOfStartDotStar(NGHolder &g) { if (is_special(u, g)) { continue; } - DEBUG_PRINTF("removing %u->%u\n", g[u].index, - g[v].index); + DEBUG_PRINTF("removing %zu->%zu\n", g[u].index, g[v].index); dead.push_back(e); } } diff --git a/src/nfagraph/ng_equivalence.cpp b/src/nfagraph/ng_equivalence.cpp index 6f8f6532..7e1f7c6f 100644 --- a/src/nfagraph/ng_equivalence.cpp +++ b/src/nfagraph/ng_equivalence.cpp @@ -77,7 +77,7 @@ public: flat_set pred; //!< predecessors of this vertex flat_set succ; //!< successors of this vertex NFAVertex v; - u32 vert_index; + size_t vert_index; CharReach cr; CharReach pred_cr; CharReach succ_cr; @@ -122,7 +122,7 @@ public: vertex_flags(vi.vertex_flags), edge_tops(vi.edge_tops), cr(vi.cr), adjacent_cr(eq == LEFT_EQUIVALENCE ? vi.pred_cr : vi.succ_cr), /* treat non-special vertices the same */ - node_type(min(g[vi.v].index, u32{N_SPECIALS})), depth(d_in) {} + node_type(min(g[vi.v].index, size_t{N_SPECIALS})), depth(d_in) {} bool operator==(const ClassInfo &b) const { return node_type == b.node_type && depth.d1 == b.depth.d1 && @@ -678,7 +678,7 @@ bool reduceGraphEquivalences(NGHolder &g, const CompileContext &cc) { DEBUG_PRINTF("equivalence processing disabled in grey box\n"); return false; } - g.renumberVertices(); + renumber_vertices(g); // Cheap check: if all the non-special vertices have in-degree one and // out-degree one, there's no redundancy in this here graph and we can diff --git a/src/nfagraph/ng_execute.cpp b/src/nfagraph/ng_execute.cpp index 4ffd89c0..9d904894 100644 --- a/src/nfagraph/ng_execute.cpp +++ b/src/nfagraph/ng_execute.cpp @@ -183,8 +183,6 @@ flat_set execute_graph(const NGHolder &g, return getVertices(work_states, info); } -typedef boost::reverse_graph RevNFAGraph; - namespace { class eg_visitor : public boost::default_dfs_visitor { public: @@ -195,13 +193,14 @@ public: info(info_in), input_g(input_g_in), states(states_in), succs(vertex_count) {} - void finish_vertex(NFAVertex input_v, const RevNFAGraph &) { + void finish_vertex(NFAVertex input_v, + const boost::reverse_graph &) { if (input_v == input_g.accept) { return; } assert(input_v != input_g.acceptEod); - DEBUG_PRINTF("finished p%u\n", input_g[input_v].index); + DEBUG_PRINTF("finished p%zu\n", input_g[input_v].index); /* finish vertex is called on vertex --> implies that all its parents * (in the forward graph) are also finished. Our parents will have @@ -236,7 +235,7 @@ public: /* we need to push into all our (forward) children their successors * from us. */ for (auto v : adjacent_vertices_range(input_v, input_g)) { - DEBUG_PRINTF("pushing our states to pstate %u\n", + DEBUG_PRINTF("pushing our states to pstate %zu\n", input_g[v].index); if (v == input_g.startDs) { /* no need for intra start edges */ @@ -289,7 +288,7 @@ flat_set execute_graph(const NGHolder &running_g, map colours; /* could just a topo order, but really it is time to pull a slightly bigger * gun: DFS */ - RevNFAGraph revg(input_dag.g); + boost::reverse_graph revg(input_dag); map > dfs_states; auto info = makeInfoTable(running_g); @@ -308,7 +307,7 @@ flat_set execute_graph(const NGHolder &running_g, #ifdef DEBUG DEBUG_PRINTF(" output rstates:"); for (const auto &v : states) { - printf(" %u", running_g[v].index); + printf(" %zu", running_g[v].index); } printf("\n"); #endif diff --git a/src/nfagraph/ng_expr_info.cpp b/src/nfagraph/ng_expr_info.cpp index cfd34ce6..b43c7fd1 100644 --- a/src/nfagraph/ng_expr_info.cpp +++ b/src/nfagraph/ng_expr_info.cpp @@ -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 * modification, are permitted provided that the following conditions are met: @@ -118,7 +118,7 @@ void checkVertex(const ReportManager &rm, const NGWrapper &w, NFAVertex v, rd.max = min(rd.max, max_offset); } - DEBUG_PRINTF("vertex %u report %u: %s\n", w[v].index, report_id, + DEBUG_PRINTF("vertex %zu report %u: %s\n", w[v].index, report_id, rd.str().c_str()); info = unionDepthMinMax(info, rd); diff --git a/src/nfagraph/ng_extparam.cpp b/src/nfagraph/ng_extparam.cpp index eeb15299..a504ac50 100644 --- a/src/nfagraph/ng_extparam.cpp +++ b/src/nfagraph/ng_extparam.cpp @@ -172,8 +172,7 @@ void updateReportBounds(ReportManager &rm, NGWrapper &g, NFAVertex accept, new_reports.insert(rm.getInternalId(ir)); } - DEBUG_PRINTF("swapping reports on vertex %u\n", - g[v].index); + DEBUG_PRINTF("swapping reports on vertex %zu\n", g[v].index); reports.swap(new_reports); } } @@ -286,8 +285,8 @@ bool anchorPatternWithBoundedRepeat(NGWrapper &g, const depth &minWidth, add_edge(u, v, g); } - g.renumberVertices(); - g.renumberEdges(); + renumber_vertices(g); + renumber_edges(g); return true; } @@ -309,7 +308,7 @@ NFAVertex findSingleCyclic(const NGHolder &g) { } if (v != NGHolder::null_vertex()) { - DEBUG_PRINTF("cyclic is %u\n", g[v].index); + DEBUG_PRINTF("cyclic is %zu\n", g[v].index); assert(!is_special(v, g)); } return v; @@ -380,7 +379,7 @@ bool transformMinLengthToRepeat(const ReportManager &rm, NGWrapper &g) { // Walk from the start vertex to the cyclic state and ensure we have a // chain of vertices. while (v != cyclic) { - DEBUG_PRINTF("vertex %u\n", g[v].index); + DEBUG_PRINTF("vertex %zu\n", g[v].index); width++; auto succ = succs(v, g); if (contains(succ, cyclic)) { @@ -418,7 +417,7 @@ bool transformMinLengthToRepeat(const ReportManager &rm, NGWrapper &g) { // Walk from the cyclic state to an accept and ensure we have a chain of // vertices. while (!is_any_accept(v, g)) { - DEBUG_PRINTF("vertex %u\n", g[v].index); + DEBUG_PRINTF("vertex %zu\n", g[v].index); width++; auto succ = succs(v, g); if (succ.size() != 1) { @@ -435,7 +434,7 @@ bool transformMinLengthToRepeat(const ReportManager &rm, NGWrapper &g) { DEBUG_PRINTF("adjusting width by %d\n", offsetAdjust); width += offsetAdjust; - DEBUG_PRINTF("width=%u, vertex %u is cyclic\n", width, + DEBUG_PRINTF("width=%u, vertex %zu is cyclic\n", width, g[cyclic].index); if (width >= g.min_length) { @@ -448,7 +447,7 @@ bool transformMinLengthToRepeat(const ReportManager &rm, NGWrapper &g) { vector preds; vector dead; for (auto u : inv_adjacent_vertices_range(cyclic, g)) { - DEBUG_PRINTF("pred %u\n", g[u].index); + DEBUG_PRINTF("pred %zu\n", g[u].index); if (u == cyclic) { continue; } @@ -484,8 +483,8 @@ bool transformMinLengthToRepeat(const ReportManager &rm, NGWrapper &g) { add_edge(u, cyclic, g); } - g.renumberVertices(); - g.renumberEdges(); + renumber_vertices(g); + renumber_edges(g); clearReports(g); g.min_length = 0; @@ -542,8 +541,7 @@ bool isEdgePrunable(const NGWrapper &g, const NFAVertex u = source(e, g); const NFAVertex v = target(e, g); - DEBUG_PRINTF("edge (%u,%u)\n", g[u].index, - g[v].index); + DEBUG_PRINTF("edge (%zu,%zu)\n", g[u].index, g[v].index); // Leave our special-to-special edges alone. if (is_special(u, g) && is_special(v, g)) { @@ -716,8 +714,7 @@ static bool isUnanchored(const NGHolder &g) { for (auto v : adjacent_vertices_range(g.start, g)) { if (!edge(g.startDs, v, g).second) { - DEBUG_PRINTF("fail, %u is anchored vertex\n", - g[v].index); + DEBUG_PRINTF("fail, %zu is anchored vertex\n", g[v].index); return false; } } @@ -862,7 +859,7 @@ void handleExtendedParams(ReportManager &rm, NGWrapper &g, } } } - //dumpGraph("final.dot", g.g); + //dumpGraph("final.dot", g); if (!hasExtParams(g)) { return; diff --git a/src/nfagraph/ng_fixed_width.cpp b/src/nfagraph/ng_fixed_width.cpp index 46d77913..978dad44 100644 --- a/src/nfagraph/ng_fixed_width.cpp +++ b/src/nfagraph/ng_fixed_width.cpp @@ -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 * modification, are permitted provided that the following conditions are met: @@ -77,7 +77,7 @@ bool findMask(const NGHolder &g, vector *mask, bool *anchored, NFAVertex v = *succs.begin(); while (true) { - DEBUG_PRINTF("validating vertex %u\n", g[v].index); + DEBUG_PRINTF("validating vertex %zu\n", g[v].index); assert(v != g.acceptEod); diff --git a/src/nfagraph/ng_graph.h b/src/nfagraph/ng_graph.h deleted file mode 100644 index 2d6fea13..00000000 --- a/src/nfagraph/ng_graph.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2015-2016, Intel Corporation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** \file - * \brief Definition of the NFAGraph type used for all NFA graph - * representations. - * - * Note that most of the time we don't work on a bare NFAGraph: instead - * we use an NGHolder, which wraps the graph and defines our special vertices, - * etc. - */ - -#ifndef NG_GRAPH_H -#define NG_GRAPH_H - -#include "util/charreach.h" -#include "util/ue2_containers.h" -#include "ue2common.h" - -#include -#include -#include - -namespace ue2 { - -/** \brief Properties associated with each vertex in an NFAGraph. */ -struct NFAGraphVertexProps { - /** \brief Set of characters on which this vertex is reachable. */ - CharReach char_reach; - - /** \brief Set of reports raised by this vertex. */ - ue2::flat_set reports; - - /** \brief Unique index for this vertex, used for BGL algorithms. */ - u32 index = 0; - - /** \brief Flags associated with assertions. */ - u32 assert_flags = 0; -}; - -/** \brief Properties associated with each edge in an NFAGraph. */ -struct NFAGraphEdgeProps { - /** \brief Unique index for this edge, used for BGL algorithms. */ - u32 index = 0; - - /** \brief For graphs that will be implemented as multi-top engines, this - * specifies the top events. Only used on edges from the start vertex. */ - ue2::flat_set tops; - - /** \brief Flags associated with assertions. */ - u32 assert_flags = 0; -}; - -// For flexibility: boost::listS, boost::listS for out-edge and vertex lists. -// boost::bidirectionalS for directed graph so that we can get at in-edges. -typedef boost::adjacency_list NFAGraph; - -typedef NFAGraph::vertex_descriptor NFAVertex; -typedef NFAGraph::edge_descriptor NFAEdge; - -/** \brief vertex_index values for special nodes in the NFAGraph. */ -enum SpecialNodes { - /** \brief Anchored start vertex. WARNING: this may be triggered at various - * locations (not just zero) for triggered graphs. */ - NODE_START, - - /** \brief Unanchored start-dotstar vertex. WARNING: this may not have a - * proper self-loop. */ - NODE_START_DOTSTAR, - - /** \brief Accept vertex. All vertices that can match at arbitrary offsets - * must have an edge to this vertex. */ - NODE_ACCEPT, - - /** \brief Accept-EOD vertex. Vertices that must raise a match at EOD only - * must have an edge to this vertex. */ - NODE_ACCEPT_EOD, - - /** \brief Sentinel, number of special vertices. */ - N_SPECIALS -}; - -} // namespace ue2 - -#endif diff --git a/src/nfagraph/ng_haig.cpp b/src/nfagraph/ng_haig.cpp index 143dca16..e4be14c3 100644 --- a/src/nfagraph/ng_haig.cpp +++ b/src/nfagraph/ng_haig.cpp @@ -37,10 +37,10 @@ #include "ng_mcclellan_internal.h" #include "ng_som_util.h" #include "ng_squash.h" -#include "ng_util.h" #include "util/bitfield.h" #include "util/container.h" #include "util/determinise.h" +#include "util/graph.h" #include "util/graph_range.h" #include "util/make_unique.h" #include "util/ue2_containers.h" @@ -449,7 +449,7 @@ void haig_do_preds(const NGHolder &g, const stateset &nfa_states, NFAVertex v = state_mapping[i]; s32 slot_id = g[v].index; - DEBUG_PRINTF("d vertex %u\n", g[v].index); + DEBUG_PRINTF("d vertex %zu\n", g[v].index); vector &out_map = preds[slot_id]; for (auto u : inv_adjacent_vertices_range(v, g)) { out_map.push_back(g[u].index); @@ -490,7 +490,7 @@ void haig_note_starts(const NGHolder &g, map *out) { for (auto v : vertices_range(g)) { if (is_any_start_inc_virtual(v, g)) { - DEBUG_PRINTF("%u creates new som value\n", g[v].index); + DEBUG_PRINTF("%zu creates new som value\n", g[v].index); out->emplace(g[v].index, 0U); continue; } @@ -501,7 +501,7 @@ void haig_note_starts(const NGHolder &g, map *out) { const DepthMinMax &d = depths[g[v].index]; if (d.min == d.max && d.min.is_finite()) { - DEBUG_PRINTF("%u is fixed at %u\n", g[v].index, (u32)d.min); + DEBUG_PRINTF("%zu is fixed at %u\n", g[v].index, (u32)d.min); out->emplace(g[v].index, d.min); } } diff --git a/src/nfagraph/ng_holder.cpp b/src/nfagraph/ng_holder.cpp index 5d83e626..a2fbb288 100644 --- a/src/nfagraph/ng_holder.cpp +++ b/src/nfagraph/ng_holder.cpp @@ -36,123 +36,33 @@ using namespace std; namespace ue2 { // internal use only -static NFAVertex addSpecialVertex(NFAGraph &g, SpecialNodes id) { - NFAVertex v = add_vertex(g); +static NFAVertex addSpecialVertex(NGHolder &g, SpecialNodes id) { + NFAVertex v(add_vertex(g)); g[v].index = id; return v; } -NGHolder::NGHolder(void) - : g(), - // add initial special nodes - start(addSpecialVertex(g, NODE_START)), - startDs(addSpecialVertex(g, NODE_START_DOTSTAR)), - accept(addSpecialVertex(g, NODE_ACCEPT)), - acceptEod(addSpecialVertex(g, NODE_ACCEPT_EOD)), - // misc data - numVertices(N_SPECIALS), - numEdges(0), - isValidNumEdges(true), - isValidNumVertices(true) { - - // wire up some fake edges for the stylized bits of the NFA - add_edge(start, startDs, *this); - add_edge(startDs, startDs, *this); - add_edge(accept, acceptEod, *this); - - g[start].char_reach.setall(); - g[startDs].char_reach.setall(); -} - NGHolder::NGHolder(nfa_kind k) - : kind (k), g(), + : kind (k), // add initial special nodes - start(addSpecialVertex(g, NODE_START)), - startDs(addSpecialVertex(g, NODE_START_DOTSTAR)), - accept(addSpecialVertex(g, NODE_ACCEPT)), - acceptEod(addSpecialVertex(g, NODE_ACCEPT_EOD)), - // misc data - numVertices(N_SPECIALS), - numEdges(0), - isValidNumEdges(true), - isValidNumVertices(true) { + start(addSpecialVertex(*this, NODE_START)), + startDs(addSpecialVertex(*this, NODE_START_DOTSTAR)), + accept(addSpecialVertex(*this, NODE_ACCEPT)), + acceptEod(addSpecialVertex(*this, NODE_ACCEPT_EOD)) { // wire up some fake edges for the stylized bits of the NFA add_edge(start, startDs, *this); add_edge(startDs, startDs, *this); add_edge(accept, acceptEod, *this); - g[start].char_reach.setall(); - g[startDs].char_reach.setall(); + (*this)[start].char_reach.setall(); + (*this)[startDs].char_reach.setall(); } NGHolder::~NGHolder(void) { DEBUG_PRINTF("destroying holder @ %p\n", this); } -size_t num_edges(NGHolder &h) { - if (!h.isValidNumEdges) { - h.numEdges = num_edges(h.g); - h.isValidNumEdges = true; - } - return h.numEdges; -} - -size_t num_edges(const NGHolder &h) { - if (!h.isValidNumEdges) { - return num_edges(h.g); - } - return h.numEdges; -} - -size_t num_vertices(NGHolder &h) { - if (!h.isValidNumVertices) { - h.numVertices = num_vertices(h.g); - h.isValidNumVertices = true; - } - return h.numVertices; -} - -size_t num_vertices(const NGHolder &h) { - if (!h.isValidNumVertices) { - return num_vertices(h.g); - } - return h.numVertices; -} - -void remove_edge(const NFAEdge &e, NGHolder &h) { - remove_edge(e, h.g); - assert(!h.isValidNumEdges || h.numEdges > 0); - h.numEdges--; -} - -void remove_edge(NFAVertex u, NFAVertex v, NGHolder &h) { - remove_edge(u, v, h.g); - assert(!h.isValidNumEdges || h.numEdges > 0); - h.numEdges--; -} - -void remove_vertex(NFAVertex v, NGHolder &h) { - remove_vertex(v, h.g); - assert(!h.isValidNumVertices || h.numVertices > 0); - h.numVertices--; -} - -void clear_vertex(NFAVertex v, NGHolder &h) { - h.isValidNumEdges = false; - clear_vertex_faster(v, h.g); -} - -void clear_in_edges(NFAVertex v, NGHolder &h) { - h.isValidNumEdges = false; - clear_in_edges(v, h.g); -} - -void clear_out_edges(NFAVertex v, NGHolder &h) { - h.isValidNumEdges = false; - clear_out_edges(v, h.g); -} - void clear_graph(NGHolder &h) { NGHolder::vertex_iterator vi, ve; for (tie(vi, ve) = vertices(h); vi != ve;) { @@ -166,6 +76,8 @@ void clear_graph(NGHolder &h) { } assert(num_vertices(h) == N_SPECIALS); + renumber_vertices(h); /* ensure that we reset our next allocated index */ + renumber_edges(h); // Recreate special stylised edges. add_edge(h.start, h.startDs, h); @@ -173,56 +85,13 @@ void clear_graph(NGHolder &h) { add_edge(h.accept, h.acceptEod, h); } -std::pair add_edge(NFAVertex u, NFAVertex v, NGHolder &h) { - assert(edge(u, v, h.g).second == false); - pair e = add_edge(u, v, h.g); - h.g[e.first].index = h.numEdges++; - assert(!h.isValidNumEdges || h.numEdges > 0); // no wrapping - return e; -} - -std::pair add_edge(NFAVertex u, NFAVertex v, - const NFAGraph::edge_property_type &ep, - NGHolder &h) { - assert(edge(u, v, h.g).second == false); - pair e = add_edge(u, v, ep, h.g); - h.g[e.first].index = h.numEdges++; - assert(!h.isValidNumEdges || h.numEdges > 0); // no wrapping - return e; -} - -NFAVertex add_vertex(NGHolder &h) { - NFAVertex v = add_vertex(h.g); - h[v].index = h.numVertices++; - assert(h.numVertices > 0); // no wrapping - return v; -} - -NFAVertex add_vertex(const NFAGraph::vertex_property_type &vp, NGHolder &h) { - NFAVertex v = add_vertex(h); - u32 i = h.g[v].index; /* preserve index */ - h.g[v] = vp; - h.g[v].index = i; - return v; -} - -void NGHolder::renumberEdges() { - numEdges = renumberGraphEdges(g); - isValidNumEdges = true; -} - -void NGHolder::renumberVertices() { - numVertices = renumberGraphVertices(g); - isValidNumVertices = true; -} - NFAVertex NGHolder::getSpecialVertex(u32 id) const { switch (id) { - case NODE_START: return start; - case NODE_START_DOTSTAR: return startDs; - case NODE_ACCEPT: return accept; - case NODE_ACCEPT_EOD: return acceptEod; - default: return nullptr; + case NODE_START: return start; + case NODE_START_DOTSTAR: return startDs; + case NODE_ACCEPT: return accept; + case NODE_ACCEPT_EOD: return acceptEod; + default: return null_vertex(); } } diff --git a/src/nfagraph/ng_holder.h b/src/nfagraph/ng_holder.h index 49050808..fbb6ac52 100644 --- a/src/nfagraph/ng_holder.h +++ b/src/nfagraph/ng_holder.h @@ -26,19 +26,75 @@ * POSSIBILITY OF SUCH DAMAGE. */ +/** \file + * \brief Definition of the NGHolder type used for to represent general nfa + * graphs as well as all associated types (vertex and edge properties, etc). + * + * The NGHolder also contains the special vertices used to represents starts and + * accepts. + */ + #ifndef NG_HOLDER_H #define NG_HOLDER_H -#include "ng_graph.h" #include "ue2common.h" #include "nfa/nfa_kind.h" - -#include -#include -#include +#include "util/charreach.h" +#include "util/ue2_containers.h" +#include "util/ue2_graph.h" namespace ue2 { +/** \brief Properties associated with each vertex in an NFAGraph. */ +struct NFAGraphVertexProps { + /** \brief Set of characters on which this vertex is reachable. */ + CharReach char_reach; + + /** \brief Set of reports raised by this vertex. */ + flat_set reports; + + /** \brief Unique index for this vertex, used for BGL algorithms. */ + size_t index = 0; + + /** \brief Flags associated with assertions. */ + u32 assert_flags = 0; +}; + +/** \brief Properties associated with each edge in an NFAGraph. */ +struct NFAGraphEdgeProps { + /** \brief Unique index for this edge, used for BGL algorithms. */ + size_t index = 0; + + /** \brief For graphs that will be implemented as multi-top engines, this + * specifies the top events. Only used on edges from the start vertex. */ + ue2::flat_set tops; + + /** \brief Flags associated with assertions. */ + u32 assert_flags = 0; +}; + +/** \brief vertex_index values for special nodes in the NFAGraph. */ +enum SpecialNodes { + /** \brief Anchored start vertex. WARNING: this may be triggered at various + * locations (not just zero) for triggered graphs. */ + NODE_START, + + /** \brief Unanchored start-dotstar vertex. WARNING: this may not have a + * proper self-loop. */ + NODE_START_DOTSTAR, + + /** \brief Accept vertex. All vertices that can match at arbitrary offsets + * must have an edge to this vertex. */ + NODE_ACCEPT, + + /** \brief Accept-EOD vertex. Vertices that must raise a match at EOD only + * must have an edge to this vertex. */ + NODE_ACCEPT_EOD, + + /** \brief Sentinel, number of special vertices. */ + N_SPECIALS +}; + /** \brief Encapsulates an NFAGraph, stores special vertices and other * metadata. * @@ -49,188 +105,34 @@ namespace ue2 { * - (startDs, startDs) (self-loop) * - (accept, acceptEod) */ -class NGHolder : boost::noncopyable { +class NGHolder : public ue2_graph { public: - NGHolder(void); explicit NGHolder(nfa_kind kind); + NGHolder(void) : NGHolder(NFA_OUTFIX) {}; virtual ~NGHolder(void); - // Pack edge and vertex indices. - // Note: maintaining edge index order can be expensive due to the frequency - // of edge removal/addition, so only renumberEdges() when required by - // operations on edge lists. - void renumberEdges(); - void renumberVertices(); + nfa_kind kind; /* Role that this plays in Rose */ - NFAVertex getSpecialVertex(u32 id) const; + static const size_t N_SPECIAL_VERTICES = N_SPECIALS; +public: + const vertex_descriptor start; //!< Anchored start vertex. + const vertex_descriptor startDs; //!< Unanchored start-dotstar vertex. + const vertex_descriptor accept; //!< Accept vertex. + const vertex_descriptor acceptEod; //!< Accept at EOD vertex. - nfa_kind kind = NFA_OUTFIX; /* Role that this plays in Rose */ - - /** \brief Underlying graph object */ - NFAGraph g; - - const NFAVertex start; //!< Anchored start vertex. - const NFAVertex startDs; //!< Unanchored start-dotstar vertex. - const NFAVertex accept; //!< Accept vertex. - const NFAVertex acceptEod; //!< Accept at EOD vertex. - - using directed_category = NFAGraph::directed_category; - using edge_parallel_category = NFAGraph::edge_parallel_category; - using traversal_category = NFAGraph::traversal_category; - - using vertex_descriptor = NFAGraph::vertex_descriptor; - using edge_descriptor = NFAGraph::edge_descriptor; - using adjacency_iterator = NFAGraph::adjacency_iterator; - using edge_iterator = NFAGraph::edge_iterator; - using in_edge_iterator = NFAGraph::in_edge_iterator; - using inv_adjacency_iterator = NFAGraph::inv_adjacency_iterator; - using out_edge_iterator = NFAGraph::out_edge_iterator; - using vertex_iterator = NFAGraph::vertex_iterator; - using edge_property_type = NFAGraph::edge_property_type; - using vertex_property_type = NFAGraph::vertex_property_type; - - // These free functions, which follow the BGL model, are the interface to - // the graph held by this class. - friend size_t num_vertices(NGHolder &h); - friend size_t num_vertices(const NGHolder &h); - friend size_t num_edges(NGHolder &h); - friend size_t num_edges(const NGHolder &h); - friend void remove_vertex(NFAVertex v, NGHolder &h); - friend void clear_vertex(NFAVertex v, NGHolder &h); - friend void clear_in_edges(NFAVertex v, NGHolder &h); - friend void clear_out_edges(NFAVertex v, NGHolder &h); - friend void remove_edge(const NFAEdge &e, NGHolder &h); - friend void remove_edge(NFAVertex u, NFAVertex v, NGHolder &h); - - template - friend void remove_out_edge_if(NFAVertex v, Predicate pred, NGHolder &h) { - boost::remove_out_edge_if(v, pred, h.g); - h.isValidNumEdges = false; - } - - template - friend void remove_in_edge_if(NFAVertex v, Predicate pred, NGHolder &h) { - boost::remove_in_edge_if(v, pred, h.g); - h.isValidNumEdges = false; - } - - template - friend void remove_edge_if(Predicate pred, NGHolder &h) { - boost::remove_edge_if(pred, h.g); - h.isValidNumEdges = false; - } - - friend std::pair add_edge(NFAVertex u, NFAVertex v, - NGHolder &h); - friend std::pair add_edge(NFAVertex u, NFAVertex v, - const edge_property_type &ep, - NGHolder &h); - friend NFAVertex add_vertex(NGHolder &h); - friend NFAVertex add_vertex(const vertex_property_type &vp, NGHolder &h); - - static NFAVertex null_vertex(void) { return NFAGraph::null_vertex(); } - - // Subscript operators for BGL bundled properties. - using graph_bundled = NFAGraph::graph_bundled; - using vertex_bundled = NFAGraph::vertex_bundled; - using edge_bundled = NFAGraph::edge_bundled; - - vertex_bundled &operator[](NFAVertex v) { - return get(boost::vertex_bundle, g)[v]; - } - const vertex_bundled &operator[](NFAVertex v) const { - return get(boost::vertex_bundle, g)[v]; - } - edge_bundled &operator[](const NFAEdge &e) { - return get(boost::edge_bundle, g)[e]; - } - const edge_bundled &operator[](const NFAEdge &e) const { - return get(boost::edge_bundle, g)[e]; - } - -protected: - - /* Since the NFAGraph vertex/edge list selectors are std::lists, computing - * num_vertices and num_edges is O(N). We use these members to store a - * cached copy of the size. - * - * In the future, with C++11's constant-time std::list::size, these may - * become obsolete. */ - - u32 numVertices; - u32 numEdges; - bool isValidNumEdges; - bool isValidNumVertices; + vertex_descriptor getSpecialVertex(u32 id) const; }; +typedef NGHolder::vertex_descriptor NFAVertex; +typedef NGHolder::edge_descriptor NFAEdge; + /** \brief True if the vertex \p v is one of our special vertices. */ template -static really_inline -bool is_special(const NFAVertex v, const GraphT &g) { +bool is_special(const typename GraphT::vertex_descriptor v, const GraphT &g) { return g[v].index < N_SPECIALS; } -static really_inline -std::pair -adjacent_vertices(NFAVertex v, const NGHolder &h) { - return adjacent_vertices(v, h.g); -} - -static really_inline -std::pair edge(NFAVertex u, NFAVertex v, const NGHolder &h) { - return boost::edge(u, v, h.g); -} - -static really_inline -std::pair -edges(const NGHolder &h) { - return edges(h.g); -} - -static really_inline -size_t in_degree(NFAVertex v, const NGHolder &h) { - return in_degree(v, h.g); -} - -static really_inline -std::pair -in_edges(NFAVertex v, const NGHolder &h) { - return in_edges(v, h.g); -} - -static really_inline -std::pair -inv_adjacent_vertices(NFAVertex v, const NGHolder &h) { - return inv_adjacent_vertices(v, h.g); -} - -static really_inline -size_t out_degree(NFAVertex v, const NGHolder &h) { - return out_degree(v, h.g); -} - -static really_inline -std::pair -out_edges(NFAVertex v, const NGHolder &h) { - return out_edges(v, h.g); -} - -static really_inline -NFAVertex source(const NFAEdge &e, const NGHolder &h) { - return source(e, h.g); -} - -static really_inline -NFAVertex target(const NFAEdge &e, const NGHolder &h) { - return target(e, h.g); -} - -static really_inline -std::pair -vertices(const NGHolder &h) { - return vertices(h.g); -} - /** * \brief Clears all non-special vertices and edges from the graph. * @@ -239,16 +141,6 @@ vertices(const NGHolder &h) { */ void clear_graph(NGHolder &h); -inline -void renumber_edges(NGHolder &h) { - h.renumberEdges(); -} - -inline -void renumber_vertices(NGHolder &h) { - h.renumberVertices(); -} - /* * \brief Clear and remove all of the vertices pointed to by the given iterator * range. @@ -275,8 +167,8 @@ void remove_vertices(Iter begin, Iter end, NGHolder &h, bool renumber = true) { } if (renumber) { - h.renumberEdges(); - h.renumberVertices(); + renumber_edges(h); + renumber_vertices(h); } } @@ -311,7 +203,7 @@ void remove_edges(Iter begin, Iter end, NGHolder &h, bool renumber = true) { } if (renumber) { - h.renumberEdges(); + renumber_edges(h); } } diff --git a/src/nfagraph/ng_is_equal.cpp b/src/nfagraph/ng_is_equal.cpp index 8e71c337..2df79f50 100644 --- a/src/nfagraph/ng_is_equal.cpp +++ b/src/nfagraph/ng_is_equal.cpp @@ -77,6 +77,26 @@ private: ReportID a_rep; ReportID b_rep; }; + +/** Comparison functor used to sort by vertex_index. */ +template +struct VertexIndexOrdering { + explicit VertexIndexOrdering(const Graph &g_in) : g(g_in) {} + bool operator()(typename Graph::vertex_descriptor a, + typename Graph::vertex_descriptor b) const { + assert(a == b || g[a].index != g[b].index); + return g[a].index < g[b].index; + } +private: + const Graph &g; +}; + +template +static +VertexIndexOrdering make_index_ordering(const Graph &g) { + return VertexIndexOrdering(g); +} + } static @@ -109,7 +129,7 @@ bool is_equal_i(const NGHolder &a, const NGHolder &b, for (size_t i = 0; i < vert_a.size(); i++) { NFAVertex va = vert_a[i]; NFAVertex vb = vert_b[i]; - DEBUG_PRINTF("vertex %u\n", a[va].index); + DEBUG_PRINTF("vertex %zu\n", a[va].index); // Vertex index must be the same. if (a[va].index != b[vb].index) { diff --git a/src/nfagraph/ng_limex.cpp b/src/nfagraph/ng_limex.cpp index 5e5a18d9..e92790b9 100644 --- a/src/nfagraph/ng_limex.cpp +++ b/src/nfagraph/ng_limex.cpp @@ -78,8 +78,7 @@ bool sanityCheckGraph(const NGHolder &g, // Non-specials should have non-empty reachability. if (!is_special(v, g)) { if (g[v].char_reach.none()) { - DEBUG_PRINTF("vertex %u has empty reach\n", - g[v].index); + DEBUG_PRINTF("vertex %zu has empty reach\n", g[v].index); return false; } } @@ -88,25 +87,23 @@ bool sanityCheckGraph(const NGHolder &g, // other vertices must not have them. if (is_match_vertex(v, g) && v != g.accept) { if (g[v].reports.empty()) { - DEBUG_PRINTF("vertex %u has no reports\n", g[v].index); + DEBUG_PRINTF("vertex %zu has no reports\n", g[v].index); return false; } } else if (!g[v].reports.empty()) { - DEBUG_PRINTF("vertex %u has reports but no accept edge\n", + DEBUG_PRINTF("vertex %zu has reports but no accept edge\n", g[v].index); return false; } // Participant vertices should have distinct state indices. if (!contains(state_ids, v)) { - DEBUG_PRINTF("vertex %u has no state index!\n", - g[v].index); + DEBUG_PRINTF("vertex %zu has no state index!\n", g[v].index); return false; } u32 s = state_ids.at(v); if (s != NO_STATE && !seen_states.insert(s).second) { - DEBUG_PRINTF("vertex %u has dupe state %u\n", - g[v].index, s); + DEBUG_PRINTF("vertex %zu has dupe state %u\n", g[v].index, s); return false; } } @@ -178,11 +175,7 @@ NFAVertex makeTopStartVertex(NGHolder &g, const flat_set &tops, CharReach top_cr = calcTopVertexReach(tops, top_reach); g[u].char_reach = top_cr; - // Add edges in vertex index order, for determinism. - vector ordered_succs(begin(succs), end(succs)); - sort(begin(ordered_succs), end(ordered_succs), make_index_ordering(g)); - - for (auto v : ordered_succs) { + for (auto v : succs) { if (v == g.accept || v == g.acceptEod) { reporter = true; } @@ -374,7 +367,7 @@ void attemptToUseAsStart(const NGHolder &g, NFAVertex u, return; } - DEBUG_PRINTF("reusing %u is a start vertex\n", g[u].index); + DEBUG_PRINTF("reusing %zu is a start vertex\n", g[u].index); markTopSuccAsHandled(u, top_inter, succs, tops_out, unhandled_top_succs, unhandled_succ_tops); } @@ -388,8 +381,7 @@ void reusePredsAsStarts(const NGHolder &g, const map &top_reach, map> &unhandled_top_succs, map> &unhandled_succ_tops, map> &tops_out) { - /* create list of candidates first, to avoid issues of iter invalidation - * and determinism */ + /* create list of candidates first, to avoid issues of iter invalidation */ DEBUG_PRINTF("attempting to reuse vertices for top starts\n"); vector cand_starts; for (NFAVertex u : unhandled_succ_tops | map_keys) { @@ -397,7 +389,6 @@ void reusePredsAsStarts(const NGHolder &g, const map &top_reach, cand_starts.push_back(u); } } - sort(cand_starts.begin(), cand_starts.end(), make_index_ordering(g)); for (NFAVertex u : cand_starts) { if (!contains(unhandled_succ_tops, u)) { @@ -625,7 +616,7 @@ void remapReportsToPrograms(NGHolder &h, const ReportManager &rm) { u32 program = rm.getProgramOffset(id); reports.insert(program); } - DEBUG_PRINTF("vertex %u: remapped reports {%s} to programs {%s}\n", + DEBUG_PRINTF("vertex %zu: remapped reports {%s} to programs {%s}\n", h[v].index, as_string_list(old_reports).c_str(), as_string_list(reports).c_str()); } diff --git a/src/nfagraph/ng_limex_accel.cpp b/src/nfagraph/ng_limex_accel.cpp index deaf2ffd..bfba7c71 100644 --- a/src/nfagraph/ng_limex_accel.cpp +++ b/src/nfagraph/ng_limex_accel.cpp @@ -69,7 +69,7 @@ void findAccelFriendGeneration(const NGHolder &g, const CharReach &cr, } const CharReach &acr = g[v].char_reach; - DEBUG_PRINTF("checking %u\n", g[v].index); + DEBUG_PRINTF("checking %zu\n", g[v].index); if (acr.count() < WIDE_FRIEND_MIN || !acr.isSubsetOf(cr)) { DEBUG_PRINTF("bad reach %zu\n", acr.count()); @@ -86,7 +86,7 @@ void findAccelFriendGeneration(const NGHolder &g, const CharReach &cr, next_preds->insert(v); insert(next_cands, adjacent_vertices(v, g)); - DEBUG_PRINTF("%u is a friend indeed\n", g[v].index); + DEBUG_PRINTF("%zu is a friend indeed\n", g[v].index); friends->insert(v); next_cand:; } @@ -675,7 +675,7 @@ NFAVertex get_sds_or_proxy(const NGHolder &g) { while (true) { if (hasSelfLoop(v, g)) { - DEBUG_PRINTF("woot %u\n", g[v].index); + DEBUG_PRINTF("woot %zu\n", g[v].index); return v; } if (out_degree(v, g) != 1) { @@ -837,7 +837,7 @@ bool nfaCheckAccel(const NGHolder &g, NFAVertex v, CharReach terminating = g[v].char_reach; terminating.flip(); - DEBUG_PRINTF("vertex %u is cyclic and has %zu stop chars%s\n", + DEBUG_PRINTF("vertex %zu is cyclic and has %zu stop chars%s\n", g[v].index, terminating.count(), allow_wide ? " (w)" : ""); diff --git a/src/nfagraph/ng_literal_analysis.cpp b/src/nfagraph/ng_literal_analysis.cpp index 9229457c..68c1bdd6 100644 --- a/src/nfagraph/ng_literal_analysis.cpp +++ b/src/nfagraph/ng_literal_analysis.cpp @@ -46,6 +46,7 @@ #include #include +#include #include using namespace std; @@ -335,7 +336,7 @@ void processWorkQueue(const NGHolder &g, const NFAEdge &e, // Our literal set should contain no literal that is a suffix of another. assert(!hasSuffixLiterals(s)); - DEBUG_PRINTF("edge %u (%u->%u) produced %zu literals\n", g[e].index, + DEBUG_PRINTF("edge %zu (%zu->%zu) produced %zu literals\n", g[e].index, g[source(e, g)].index, g[target(e, g)].index, s.size()); } @@ -791,7 +792,7 @@ bool splitOffLeadingLiteral_i(const NGHolder &g, bool anch, } while (true) { - DEBUG_PRINTF("validating vertex %u\n", g[v].index); + DEBUG_PRINTF("validating vertex %zu\n", g[v].index); assert(v != g.acceptEod && v != g.accept); diff --git a/src/nfagraph/ng_literal_component.cpp b/src/nfagraph/ng_literal_component.cpp index 871c8ac7..e3cfe867 100644 --- a/src/nfagraph/ng_literal_component.cpp +++ b/src/nfagraph/ng_literal_component.cpp @@ -95,7 +95,7 @@ void addToString(string &s, const NGHolder &g, NFAVertex v) { static bool splitOffLiteral(NG &ng, NGWrapper &g, NFAVertex v, const bool anchored, set &dead) { - DEBUG_PRINTF("examine vertex %u\n", g[v].index); + DEBUG_PRINTF("examine vertex %zu\n", g[v].index); bool nocase = false, casefixed = false; assert(!is_special(v, g)); @@ -109,7 +109,7 @@ bool splitOffLiteral(NG &ng, NGWrapper &g, NFAVertex v, const bool anchored, assert(edge(g.start, v, g).second); assert(edge(g.startDs, v, g).second); } - if (hasGreaterInDegree(reqInDegree, v, g)) { + if (in_degree(v, g) > reqInDegree) { DEBUG_PRINTF("extra in-edges\n"); return false; } @@ -134,7 +134,7 @@ bool splitOffLiteral(NG &ng, NGWrapper &g, NFAVertex v, const bool anchored, u = v; // previous vertex v = *(adjacent_vertices(v, g).first); - DEBUG_PRINTF("loop, v=%u\n", g[v].index); + DEBUG_PRINTF("loop, v=%zu\n", g[v].index); if (is_special(v, g)) { if (v == g.accept || v == g.acceptEod) { diff --git a/src/nfagraph/ng_literal_decorated.cpp b/src/nfagraph/ng_literal_decorated.cpp index 02b25a73..89c01a6c 100644 --- a/src/nfagraph/ng_literal_decorated.cpp +++ b/src/nfagraph/ng_literal_decorated.cpp @@ -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 * modification, are permitted provided that the following conditions are met: @@ -77,7 +77,7 @@ bool findPaths(const NGHolder &g, vector &paths) { read_count[g[v].index] = out_degree(v, g); - DEBUG_PRINTF("setting read_count to %zu for %u\n", + DEBUG_PRINTF("setting read_count to %zu for %zu\n", read_count[g[v].index], g[v].index); if (v == g.start || v == g.startDs) { @@ -117,7 +117,7 @@ bool findPaths(const NGHolder &g, vector &paths) { read_count[g[u].index]--; if (!read_count[g[u].index]) { - DEBUG_PRINTF("clearing %u as finished reading\n", g[u].index); + DEBUG_PRINTF("clearing %zu as finished reading\n", g[u].index); built[g[u].index].clear(); built[g[u].index].shrink_to_fit(); } @@ -138,9 +138,9 @@ bool hasLargeDegreeVertex(const NGHolder &g) { if (is_special(v, g)) { // specials can have large degree continue; } - if (has_greater_degree(MAX_VERTEX_DEGREE, v, g)) { - DEBUG_PRINTF("vertex %u has degree %zu\n", g[v].index, - boost::degree(v, g.g)); + if (degree(v, g) > MAX_VERTEX_DEGREE) { + DEBUG_PRINTF("vertex %zu has degree %zu\n", g[v].index, + degree(v, g)); return true; } } @@ -188,7 +188,8 @@ struct PathMask { } // Reports are attached to the second-to-last vertex. - reports = g[*next(path.rbegin())].reports; + NFAVertex u = *std::next(path.rbegin()); + reports = g[u].reports; assert(!reports.empty()); } diff --git a/src/nfagraph/ng_mcclellan.cpp b/src/nfagraph/ng_mcclellan.cpp index 71c9a05e..375086a4 100644 --- a/src/nfagraph/ng_mcclellan.cpp +++ b/src/nfagraph/ng_mcclellan.cpp @@ -328,7 +328,7 @@ void markToppableStarts(const NGHolder &g, const flat_set &unused, } for (const auto &trigger : triggers) { if (triggerAllowed(g, v, triggers, trigger)) { - DEBUG_PRINTF("idx %u is valid location for top\n", g[v].index); + DEBUG_PRINTF("idx %zu is valid location for top\n", g[v].index); out->set(g[v].index); break; } diff --git a/src/nfagraph/ng_misc_opt.cpp b/src/nfagraph/ng_misc_opt.cpp index 716802ba..29939fec 100644 --- a/src/nfagraph/ng_misc_opt.cpp +++ b/src/nfagraph/ng_misc_opt.cpp @@ -80,6 +80,7 @@ #include using namespace std; +using boost::make_filtered_graph; namespace ue2 { @@ -108,7 +109,7 @@ void findCandidates(NGHolder &g, const vector &ordering, goto next_cand; } } - DEBUG_PRINTF("vertex %u is a candidate\n", g[v].index); + DEBUG_PRINTF("vertex %zu is a candidate\n", g[v].index); cand->push_back(v); next_cand:; } @@ -139,7 +140,7 @@ void findCandidates_rev(NGHolder &g, const vector &ordering, goto next_cand; } } - DEBUG_PRINTF("vertex %u is a candidate\n", g[v].index); + DEBUG_PRINTF("vertex %zu is a candidate\n", g[v].index); cand->push_back(v); next_cand:; } @@ -242,7 +243,7 @@ set findSustainSet_rev(const NGHolder &g, NFAVertex p, static bool enlargeCyclicVertex(NGHolder &g, som_type som, NFAVertex v) { - DEBUG_PRINTF("considering vertex %u\n", g[v].index); + DEBUG_PRINTF("considering vertex %zu\n", g[v].index); const CharReach &v_cr = g[v].char_reach; CharReach add; @@ -261,7 +262,7 @@ bool enlargeCyclicVertex(NGHolder &g, som_type som, NFAVertex v) { if (p == v) { continue; } - DEBUG_PRINTF("looking at pred %u\n", g[p].index); + DEBUG_PRINTF("looking at pred %zu\n", g[p].index); bool ignore_sds = som; /* if we are tracking som, entries into a state from sds are significant. */ @@ -291,13 +292,13 @@ bool enlargeCyclicVertex(NGHolder &g, som_type som, NFAVertex v) { /* the cr can be increased */ g[v].char_reach = add; - DEBUG_PRINTF("vertex %u was widened\n", g[v].index); + DEBUG_PRINTF("vertex %zu was widened\n", g[v].index); return true; } static bool enlargeCyclicVertex_rev(NGHolder &g, NFAVertex v) { - DEBUG_PRINTF("considering vertex %u\n", g[v].index); + DEBUG_PRINTF("considering vertex %zu\n", g[v].index); const CharReach &v_cr = g[v].char_reach; CharReach add; @@ -316,7 +317,7 @@ bool enlargeCyclicVertex_rev(NGHolder &g, NFAVertex v) { if (p == v) { continue; } - DEBUG_PRINTF("looking at succ %u\n", g[p].index); + DEBUG_PRINTF("looking at succ %zu\n", g[p].index); set sustain = findSustainSet_rev(g, p, add); DEBUG_PRINTF("sustain set is %zu\n", sustain.size()); @@ -341,7 +342,7 @@ bool enlargeCyclicVertex_rev(NGHolder &g, NFAVertex v) { /* the cr can be increased */ g[v].char_reach = add; - DEBUG_PRINTF("vertex %u was widened\n", g[v].index); + DEBUG_PRINTF("vertex %zu was widened\n", g[v].index); return true; } @@ -390,7 +391,7 @@ bool improveGraph(NGHolder &g, som_type som) { * enlargeCyclicCR. */ CharReach reduced_cr(NFAVertex v, const NGHolder &g, const map &br_cyclic) { - DEBUG_PRINTF("find minimal cr for %u\n", g[v].index); + DEBUG_PRINTF("find minimal cr for %zu\n", g[v].index); CharReach v_cr = g[v].char_reach; if (proper_in_degree(v, g) != 1) { return v_cr; @@ -579,12 +580,11 @@ flat_set findDependentVertices(const NGHolder &g, NFAVertex v) { } } - auto filtered_g = make_filtered_graph(g.g, - make_bad_edge_filter(&no_explore)); + auto filtered_g = make_filtered_graph(g, make_bad_edge_filter(&no_explore)); vector color_raw(num_vertices(g)); auto color = make_iterator_property_map(color_raw.begin(), - get(&NFAGraphVertexProps::index, g.g)); + get(vertex_index, g)); flat_set bad; for (NFAVertex b : vertices_range(g)) { if (b != g.start && g[b].char_reach.isSubsetOf(g[v].char_reach)) { @@ -597,7 +597,7 @@ flat_set findDependentVertices(const NGHolder &g, NFAVertex v) { flat_set rv; for (NFAVertex u : vertices_range(g)) { if (!contains(bad, u)) { - DEBUG_PRINTF("%u is good\n", g[u].index); + DEBUG_PRINTF("%zu is good\n", g[u].index); rv.insert(u); } } @@ -623,7 +623,7 @@ bool pruneUsingSuccessors(NGHolder &g, NFAVertex u, som_type som) { } bool changed = false; - DEBUG_PRINTF("using cyclic %u as base\n", g[u].index); + DEBUG_PRINTF("using cyclic %zu as base\n", g[u].index); auto children = findDependentVertices(g, u); vector u_succs; for (NFAVertex v : adjacent_vertices_range(u, g)) { @@ -639,23 +639,23 @@ bool pruneUsingSuccessors(NGHolder &g, NFAVertex u, som_type som) { return g[a].char_reach.count() > g[b].char_reach.count(); }); for (NFAVertex v : u_succs) { - DEBUG_PRINTF(" using %u as killer\n", g[v].index); + DEBUG_PRINTF(" using %zu as killer\n", g[v].index); /* Need to distinguish between vertices that are switched on after the * cyclic vs vertices that are switched on concurrently with the cyclic * if (subject to a suitable reach) */ bool v_peer_of_cyclic = willBeEnabledConcurrently(u, v, g); set dead; for (NFAVertex s : adjacent_vertices_range(v, g)) { - DEBUG_PRINTF(" looking at preds of %u\n", g[s].index); + DEBUG_PRINTF(" looking at preds of %zu\n", g[s].index); for (NFAEdge e : in_edges_range(s, g)) { NFAVertex p = source(e, g); if (!contains(children, p) || p == v || p == u || p == g.accept) { - DEBUG_PRINTF("%u not a cand\n", g[p].index); + DEBUG_PRINTF("%zu not a cand\n", g[p].index); continue; } if (is_any_accept(s, g) && g[p].reports != g[v].reports) { - DEBUG_PRINTF("%u bad reports\n", g[p].index); + DEBUG_PRINTF("%zu bad reports\n", g[p].index); continue; } /* the out-edges of a vertex that may be enabled on the same @@ -664,7 +664,7 @@ bool pruneUsingSuccessors(NGHolder &g, NFAVertex u, som_type som) { * may not be switched on until another byte is processed). */ if (!v_peer_of_cyclic && sometimesEnabledConcurrently(u, p, g)) { - DEBUG_PRINTF("%u can only be squashed by a proper peer\n", + DEBUG_PRINTF("%zu can only be squashed by a proper peer\n", g[p].index); continue; } @@ -672,14 +672,14 @@ bool pruneUsingSuccessors(NGHolder &g, NFAVertex u, som_type som) { if (g[p].char_reach.isSubsetOf(g[v].char_reach)) { dead.insert(e); changed = true; - DEBUG_PRINTF("removing edge %u->%u\n", g[p].index, + DEBUG_PRINTF("removing edge %zu->%zu\n", g[p].index, g[s].index); } else if (is_subset_of(succs(p, g), succs(u, g))) { if (is_match_vertex(p, g) && !is_subset_of(g[p].reports, g[v].reports)) { continue; } - DEBUG_PRINTF("updating reach on %u\n", g[p].index); + DEBUG_PRINTF("updating reach on %zu\n", g[p].index); changed |= (g[p].char_reach & g[v].char_reach).any(); g[p].char_reach &= ~g[v].char_reach; } diff --git a/src/nfagraph/ng_netflow.cpp b/src/nfagraph/ng_netflow.cpp index 9004024f..4859d864 100644 --- a/src/nfagraph/ng_netflow.cpp +++ b/src/nfagraph/ng_netflow.cpp @@ -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 * modification, are permitted provided that the following conditions are met: @@ -111,6 +111,7 @@ static void removeEdgesFromIndex(NGHolder &g, vector &capacityMap, u32 idx) { remove_edge_if([&](const NFAEdge &e) { return g[e].index >= idx; }, g); capacityMap.resize(idx); + renumber_edges(g); } /** A wrapper around boykov_kolmogorov_max_flow, returns the max flow and @@ -142,11 +143,10 @@ u64a getMaxFlow(NGHolder &h, const vector &capacityMap_in, vector distances(numVertices); assert(colorMap.size() == numVertices); - const NFAGraph &g = h.g; - auto v_index_map = get(&NFAGraphVertexProps::index, g); - auto e_index_map = get(&NFAGraphEdgeProps::index, g); + auto v_index_map = get(vertex_index, h); + auto e_index_map = get(edge_index, h); - u64a flow = boykov_kolmogorov_max_flow(g, + u64a flow = boykov_kolmogorov_max_flow(h, make_iterator_property_map(capacityMap.begin(), e_index_map), make_iterator_property_map(edgeResiduals.begin(), e_index_map), make_iterator_property_map(reverseEdges.begin(), e_index_map), @@ -158,7 +158,7 @@ u64a getMaxFlow(NGHolder &h, const vector &capacityMap_in, // Remove reverse edges from graph. removeEdgesFromIndex(h, capacityMap, numRealEdges); - assert(num_edges(h.g) == numRealEdges); + assert(num_edges(h) == numRealEdges); DEBUG_PRINTF("flow = %llu\n", flow); return flow; @@ -190,14 +190,14 @@ vector findMinCut(NGHolder &h, const vector &scores) { if (fromColor != boost::white_color && toColor == boost::white_color) { assert(ec <= INVALID_EDGE_CAP); - DEBUG_PRINTF("found white cut edge %u->%u cap %llu\n", + DEBUG_PRINTF("found white cut edge %zu->%zu cap %llu\n", h[from].index, h[to].index, ec); observed_white_flow += ec; picked_white.push_back(e); } if (fromColor == boost::black_color && toColor != boost::black_color) { assert(ec <= INVALID_EDGE_CAP); - DEBUG_PRINTF("found black cut edge %u->%u cap %llu\n", + DEBUG_PRINTF("found black cut edge %zu->%zu cap %llu\n", h[from].index, h[to].index, ec); observed_black_flow += ec; picked_black.push_back(e); diff --git a/src/nfagraph/ng_prefilter.cpp b/src/nfagraph/ng_prefilter.cpp index 8abc45b3..012b4e8d 100644 --- a/src/nfagraph/ng_prefilter.cpp +++ b/src/nfagraph/ng_prefilter.cpp @@ -220,13 +220,7 @@ void copyInEdges(NGHolder &g, NFAVertex from, NFAVertex to, continue; } - // Check with edge_by_target to cope with predecessors with large - // fan-out. - if (edge_by_target(u, to, g).second) { - continue; - } - - add_edge(u, to, g[e], g); + add_edge_if_not_present(u, to, g[e], g); } } @@ -361,7 +355,7 @@ void reduceRegions(NGHolder &h) { // We may have vertices that have edges to both accept and acceptEod: in // this case, we can optimize for performance by removing the acceptEod // edges. - remove_in_edge_if(h.acceptEod, SourceHasEdgeToAccept(h), h.g); + remove_in_edge_if(h.acceptEod, SourceHasEdgeToAccept(h), h); } void prefilterReductions(NGHolder &h, const CompileContext &cc) { @@ -378,13 +372,13 @@ void prefilterReductions(NGHolder &h, const CompileContext &cc) { DEBUG_PRINTF("before: graph with %zu vertices, %zu edges\n", num_vertices(h), num_edges(h)); - h.renumberVertices(); - h.renumberEdges(); + renumber_vertices(h); + renumber_edges(h); reduceRegions(h); - h.renumberVertices(); - h.renumberEdges(); + renumber_vertices(h); + renumber_edges(h); DEBUG_PRINTF("after: graph with %zu vertices, %zu edges\n", num_vertices(h), num_edges(h)); diff --git a/src/nfagraph/ng_prune.cpp b/src/nfagraph/ng_prune.cpp index 473b9586..88f1880f 100644 --- a/src/nfagraph/ng_prune.cpp +++ b/src/nfagraph/ng_prune.cpp @@ -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 * modification, are permitted provided that the following conditions are met: @@ -57,9 +57,8 @@ namespace ue2 { void pruneUnreachable(NGHolder &g) { deque dead; - if (!hasGreaterInDegree(1, g.acceptEod, g) && - !hasGreaterInDegree(0, g.accept, g) && - edge(g.accept, g.acceptEod, g).second) { + if (in_degree(g.acceptEod, g) == 1 && !in_degree(g.accept, g) + && edge(g.accept, g.acceptEod, g).second) { // Trivial case: there are no in-edges to our accepts (other than // accept->acceptEod), so all non-specials are unreachable. for (auto v : vertices_range(g)) { @@ -70,10 +69,10 @@ void pruneUnreachable(NGHolder &g) { } else { // Walk a reverse graph from acceptEod with Boost's depth_first_visit // call. - typedef reverse_graph RevNFAGraph; - RevNFAGraph revg(g.g); + typedef reverse_graph RevNFAGraph; + RevNFAGraph revg(g); - map colours; + map colours; depth_first_visit(revg, g.acceptEod, make_dfs_visitor(boost::null_visitor()), @@ -104,7 +103,8 @@ void pruneUnreachable(NGHolder &g) { template static -bool pruneForwardUseless(NGHolder &h, const nfag_t &g, NFAVertex s, +bool pruneForwardUseless(NGHolder &h, const nfag_t &g, + typename nfag_t::vertex_descriptor s, vector &vertexColor) { // Begin with all vertices set to white, as DFV only marks visited // vertices. @@ -122,9 +122,9 @@ bool pruneForwardUseless(NGHolder &h, const nfag_t &g, NFAVertex s, for (auto v : vertices_range(g)) { u32 idx = g[v].index; if (!is_special(v, g) && vertexColor[idx] == boost::white_color) { - DEBUG_PRINTF("vertex %u is unreachable from %u\n", + DEBUG_PRINTF("vertex %zu is unreachable from %zu\n", g[v].index, g[s].index); - dead.push_back(v); + dead.push_back(NFAVertex(v)); } } @@ -145,17 +145,17 @@ void pruneUseless(NGHolder &g, bool renumber) { assert(hasCorrectlyNumberedVertices(g)); vector vertexColor(num_vertices(g)); - bool work_done = pruneForwardUseless(g, g.g, g.start, vertexColor); - work_done |= pruneForwardUseless( - g, reverse_graph(g.g), g.acceptEod, vertexColor); + bool work_done = pruneForwardUseless(g, g, g.start, vertexColor); + work_done |= pruneForwardUseless(g, reverse_graph(g), + g.acceptEod, vertexColor); if (!work_done) { return; } if (renumber) { - g.renumberEdges(); - g.renumberVertices(); + renumber_edges(g); + renumber_vertices(g); } } @@ -172,7 +172,7 @@ void pruneEmptyVertices(NGHolder &g) { const CharReach &cr = g[v].char_reach; if (cr.none()) { - DEBUG_PRINTF("empty: %u\n", g[v].index); + DEBUG_PRINTF("empty: %zu\n", g[v].index); dead.push_back(v); } } @@ -234,7 +234,7 @@ bool isDominatedByReporter(const NGHolder &g, // Note: reporters with edges only to acceptEod are not considered to // dominate. if (edge(u, g.accept, g).second && contains(g[u].reports, report_id)) { - DEBUG_PRINTF("%u is dominated by %u, and both report %u\n", + DEBUG_PRINTF("%zu is dominated by %zu, and both report %u\n", g[v].index, g[u].index, report_id); return true; } @@ -296,7 +296,7 @@ void pruneHighlanderDominated(NGHolder &g, const ReportManager &rm) { } - sort(begin(reporters), end(reporters), make_index_ordering(g)); + sort(begin(reporters), end(reporters)); reporters.erase(unique(begin(reporters), end(reporters)), end(reporters)); DEBUG_PRINTF("%zu vertices have simple exhaustible reports\n", @@ -315,14 +315,14 @@ void pruneHighlanderDominated(NGHolder &g, const ReportManager &rm) { continue; } if (isDominatedByReporter(g, dom, v, report_id)) { - DEBUG_PRINTF("removed dominated report %u from vertex %u\n", + DEBUG_PRINTF("removed dominated report %u from vertex %zu\n", report_id, g[v].index); g[v].reports.erase(report_id); } } if (g[v].reports.empty()) { - DEBUG_PRINTF("removed edges to accepts from %u, no reports left\n", + DEBUG_PRINTF("removed edges to accepts from %zu, no reports left\n", g[v].index); remove_edge(v, g.accept, g); remove_edge(v, g.acceptEod, g); @@ -337,7 +337,7 @@ void pruneHighlanderDominated(NGHolder &g, const ReportManager &rm) { if (hasOnlySelfLoopAndExhaustibleAccepts(g, rm, v)) { remove_edge(v, v, g); modified = true; - DEBUG_PRINTF("removed self-loop on %u\n", g[v].index); + DEBUG_PRINTF("removed self-loop on %zu\n", g[v].index); } } @@ -349,7 +349,7 @@ void pruneHighlanderDominated(NGHolder &g, const ReportManager &rm) { // We may have only removed self-loops, in which case pruneUseless wouldn't // renumber, so we do edge renumbering explicitly here. - g.renumberEdges(); + renumber_edges(g); } /** Removes the given Report ID from vertices connected to accept, and then @@ -388,8 +388,8 @@ void pruneReport(NGHolder &g, ReportID report) { remove_edges(dead, g); pruneUnreachable(g); - g.renumberVertices(); - g.renumberEdges(); + renumber_vertices(g); + renumber_edges(g); } /** Removes all Report IDs bar the given one from vertices connected to accept, @@ -431,8 +431,8 @@ void pruneAllOtherReports(NGHolder &g, ReportID report) { remove_edges(dead, g); pruneUnreachable(g); - g.renumberVertices(); - g.renumberEdges(); + renumber_vertices(g); + renumber_edges(g); } } // namespace ue2 diff --git a/src/nfagraph/ng_puff.cpp b/src/nfagraph/ng_puff.cpp index 00b2e8ac..7281471f 100644 --- a/src/nfagraph/ng_puff.cpp +++ b/src/nfagraph/ng_puff.cpp @@ -59,7 +59,7 @@ static size_t countChain(const NGHolder &g, NFAVertex v) { size_t count = 0; while (v) { - DEBUG_PRINTF("counting vertex %u\n", g[v].index); + DEBUG_PRINTF("counting vertex %zu\n", g[v].index); if (is_special(v, g)) { break; } @@ -79,7 +79,7 @@ void wireNewAccepts(NGHolder &g, NFAVertex head, continue; } - DEBUG_PRINTF("adding edge: %u -> accept\n", g[u].index); + DEBUG_PRINTF("adding edge: %zu -> accept\n", g[u].index); assert(!edge(u, g.accept, g).second); assert(!edge(u, g.acceptEod, g).second); add_edge(u, g.accept, g); @@ -136,13 +136,13 @@ bool singleStart(const NGHolder &g) { for (auto v : adjacent_vertices_range(g.start, g)) { if (!is_special(v, g)) { - DEBUG_PRINTF("saw %u\n", g[v].index); + DEBUG_PRINTF("saw %zu\n", g[v].index); seen.insert(v); } } for (auto v : adjacent_vertices_range(g.startDs, g)) { if (!is_special(v, g)) { - DEBUG_PRINTF("saw %u\n", g[v].index); + DEBUG_PRINTF("saw %zu\n", g[v].index); seen.insert(v); } } @@ -158,7 +158,7 @@ bool triggerResetsPuff(const NGHolder &g, NFAVertex head) { for (auto u : inv_adjacent_vertices_range(head, g)) { if (!g[u].char_reach.isSubsetOf(puff_escapes)) { - DEBUG_PRINTF("no reset on trigger %u %u\n", g[u].index, + DEBUG_PRINTF("no reset on trigger %zu %zu\n", g[u].index, g[head].index); return false; } @@ -172,7 +172,7 @@ bool triggerResetsPuff(const NGHolder &g, NFAVertex head) { * */ static bool triggerFloodsPuff(const NGHolder &g, NFAVertex head) { - DEBUG_PRINTF("head = %u\n", g[head].index); + DEBUG_PRINTF("head = %zu\n", g[head].index); const CharReach &puff_cr = g[head].char_reach; @@ -186,14 +186,14 @@ bool triggerFloodsPuff(const NGHolder &g, NFAVertex head) { if (proper_in_degree(head, g) == 1 && puff_cr == g[getSoleSourceVertex(g, head)].char_reach) { head = getSoleSourceVertex(g, head); - DEBUG_PRINTF("temp new head = %u\n", g[head].index); + DEBUG_PRINTF("temp new head = %zu\n", g[head].index); } for (auto s : inv_adjacent_vertices_range(head, g)) { - DEBUG_PRINTF("s = %u\n", g[s].index); + DEBUG_PRINTF("s = %zu\n", g[s].index); if (!puff_cr.isSubsetOf(g[s].char_reach)) { - DEBUG_PRINTF("no flood on trigger %u %u\n", - g[s].index, g[head].index); + DEBUG_PRINTF("no flood on trigger %zu %zu\n", g[s].index, + g[head].index); return false; } @@ -268,7 +268,7 @@ void constructPuff(NGHolder &g, const NFAVertex a, const NFAVertex puffv, RoseBuild &rose, ReportManager &rm, flat_set &chain_reports, bool prefilter) { DEBUG_PRINTF("constructing Puff for report %u\n", report); - DEBUG_PRINTF("a = %u\n", g[a].index); + DEBUG_PRINTF("a = %zu\n", g[a].index); const Report &puff_report = rm.getReport(report); const bool simple_exhaust = isSimpleExhaustible(puff_report); @@ -349,7 +349,7 @@ bool doComponent(RoseBuild &rose, ReportManager &rm, NGHolder &g, NFAVertex a, } nodes.push_back(a); - DEBUG_PRINTF("vertex %u has in_degree %zu\n", g[a].index, + DEBUG_PRINTF("vertex %zu has in_degree %zu\n", g[a].index, in_degree(a, g)); a = getSoleSourceVertex(g, a); @@ -387,10 +387,10 @@ bool doComponent(RoseBuild &rose, ReportManager &rm, NGHolder &g, NFAVertex a, bool auto_restart = false; - DEBUG_PRINTF("a = %u\n", g[a].index); + DEBUG_PRINTF("a = %zu\n", g[a].index); if (nodes.size() < MIN_PUFF_LENGTH || a == g.startDs) { - DEBUG_PRINTF("bad %zu %u\n", nodes.size(), g[a].index); + DEBUG_PRINTF("bad %zu %zu\n", nodes.size(), g[a].index); if (nodes.size() < MIN_PUFF_LENGTH) { return false; } else { diff --git a/src/nfagraph/ng_redundancy.cpp b/src/nfagraph/ng_redundancy.cpp index 8fc5d5f3..4ca695d8 100644 --- a/src/nfagraph/ng_redundancy.cpp +++ b/src/nfagraph/ng_redundancy.cpp @@ -309,14 +309,10 @@ static bool hasInEdgeTops(const NGHolder &g, NFAVertex v) { bool exists; NFAEdge e; - tie(e, exists) = edge_by_target(g.start, v, g); - if (exists && !g[e].tops.empty()) { - return true; - } - return false; + tie(e, exists) = edge(g.start, v, g); + return exists && !g[e].tops.empty(); } - /** Transform (1), removal of redundant vertices. */ static bool doUselessMergePass(NGHolder &g, som_type som, VertexInfoMap &infoMap, @@ -348,8 +344,7 @@ bool doUselessMergePass(NGHolder &g, som_type som, VertexInfoMap &infoMap, } if (info.pred.empty() || info.succ.empty()) { - DEBUG_PRINTF("vertex %u has empty pred/succ list\n", - g[v].index); + DEBUG_PRINTF("vertex %zu has empty pred/succ list\n", g[v].index); assert(0); // non-special states should always have succ/pred lists continue; } @@ -448,7 +443,7 @@ bool doUselessMergePass(NGHolder &g, som_type som, VertexInfoMap &infoMap, CharReach &otherReach = g[t].char_reach; if (currReach.isSubsetOf(otherReach)) { - DEBUG_PRINTF("removing redundant vertex %u (keeping %u)\n", + DEBUG_PRINTF("removing redundant vertex %zu (keeping %zu)\n", g[v].index, g[t].index); markForRemoval(v, infoMap, removable); changed = true; @@ -539,9 +534,6 @@ bool doDiamondMergePass(NGHolder &g, som_type som, VertexInfoMap &infoMap, continue; } - /* ensure that we look for candidates in the same order */ - sort(intersection.begin(), intersection.end(), make_index_ordering(g)); - const CharReach &currReach = g[v].char_reach; const auto &currReports = g[v].reports; for (auto t : intersection) { @@ -578,8 +570,8 @@ bool doDiamondMergePass(NGHolder &g, som_type som, VertexInfoMap &infoMap, CharReach &otherReach = g[t].char_reach; otherReach |= currReach; // v can be removed - DEBUG_PRINTF("removing redundant vertex %u and merging " - "reachability with vertex %u\n", + DEBUG_PRINTF("removing redundant vertex %zu and merging " + "reachability with vertex %zu\n", g[v].index, g[t].index); markForRemoval(v, infoMap, removable); changed = true; @@ -645,14 +637,14 @@ bool reversePathReachSubset(const NFAEdge &e, const NFAVertex &dom, } NFAVertex start = source(e, g); - using RevGraph = boost::reverse_graph; + using RevGraph = boost::reverse_graph; map vertexColor; // Walk the graph backwards from v, examining each node. We fail (return // false) if we encounter a node with reach NOT a subset of domReach, and // we stop searching at dom. try { - depth_first_visit(RevGraph(g.g), start, + depth_first_visit(RevGraph(g), start, ReachSubsetVisitor(domReach), make_assoc_property_map(vertexColor), VertexIs(dom)); @@ -674,16 +666,15 @@ bool forwardPathReachSubset(const NFAEdge &e, const NFAVertex &dom, } NFAVertex start = target(e, g); - map vertexColor; + map vertexColor; // Walk the graph forward from v, examining each node. We fail (return // false) if we encounter a node with reach NOT a subset of domReach, and // we stop searching at dom. try { - depth_first_visit(g.g, start, - ReachSubsetVisitor(domReach), + depth_first_visit(g, start, ReachSubsetVisitor(domReach), make_assoc_property_map(vertexColor), - VertexIs(dom)); + VertexIs(dom)); } catch(ReachMismatch&) { return false; } @@ -775,9 +766,8 @@ void findCyclicDom(NGHolder &g, vector &cyclic, continue; } - DEBUG_PRINTF("vertex %u is dominated by directly-connected cyclic " - "vertex %u\n", g[v].index, - g[dom].index); + DEBUG_PRINTF("vertex %zu is dominated by directly-connected cyclic " + "vertex %zu\n", g[v].index, g[dom].index); // iff all paths through in-edge e of v involve vertices whose // reachability is a subset of reach(dom), we can delete edge e. @@ -787,8 +777,8 @@ void findCyclicDom(NGHolder &g, vector &cyclic, } if (reversePathReachSubset(e, dom, g)) { - DEBUG_PRINTF("edge (%u, %u) can be removed: leading paths " - "share dom reach\n", + DEBUG_PRINTF("edge (%zu, %zu) can be removed: leading " + "paths share dom reach\n", g[source(e, g)].index, g[target(e, g)].index); dead.insert(e); if (source(e, g) == v) { @@ -814,11 +804,9 @@ void findCyclicPostDom(NGHolder &g, vector &cyclic, // Path out through a post-dominator (e.g. a?.+foobar') NFAVertex postdom = postdominators[v]; - if (postdom && cyclic[g[postdom].index] - && edge(v, postdom, g).second) { - DEBUG_PRINTF("vertex %u is postdominated by directly-connected " - "cyclic vertex %u\n", g[v].index, - g[postdom].index); + if (postdom && cyclic[g[postdom].index] && edge(v, postdom, g).second) { + DEBUG_PRINTF("vertex %zu is postdominated by directly-connected " + "cyclic vertex %zu\n", g[v].index, g[postdom].index); // iff all paths through in-edge e of v involve vertices whose // reachability is a subset of reach(dom), we can delete edge e. @@ -828,8 +816,8 @@ void findCyclicPostDom(NGHolder &g, vector &cyclic, } if (forwardPathReachSubset(e, postdom, g)) { - DEBUG_PRINTF("edge (%u, %u) can be removed: trailing paths " - "share postdom reach\n", + DEBUG_PRINTF("edge (%zu, %zu) can be removed: trailing " + "paths share postdom reach\n", g[source(e, g)].index, g[target(e, g)].index); if (target(e, g) == v) { cyclic[g[v].index] = false; @@ -844,7 +832,7 @@ void findCyclicPostDom(NGHolder &g, vector &cyclic, bool removeRedundancy(NGHolder &g, som_type som) { DEBUG_PRINTF("rr som = %d\n", (int)som); - g.renumberVertices(); + renumber_vertices(g); // Cheap check: if all the non-special vertices have in-degree one and // out-degree one, there's no redundancy in this here graph and we can diff --git a/src/nfagraph/ng_region.cpp b/src/nfagraph/ng_region.cpp index c7472e0d..0ecd7bd6 100644 --- a/src/nfagraph/ng_region.cpp +++ b/src/nfagraph/ng_region.cpp @@ -71,7 +71,7 @@ using namespace std; namespace ue2 { typedef ue2::unordered_set BackEdgeSet; -typedef boost::filtered_graph> +typedef boost::filtered_graph> AcyclicGraph; namespace { @@ -92,17 +92,17 @@ void checkAndAddExitCandidate(const AcyclicGraph &g, /* find the set of vertices reachable from v which are not in r */ for (auto w : adjacent_vertices_range(v, g)) { - if (!contains(r, w)) { + if (!contains(r, NFAVertex(w))) { if (!open) { - exits->push_back(exit_info(v)); + exits->push_back(exit_info(NFAVertex(v))); open = &exits->back().open; } - open->insert(w); + open->insert(NFAVertex(w)); } } if (open) { - DEBUG_PRINTF("exit %u\n", g[v].index); + DEBUG_PRINTF("exit %zu\n", g[v].index); } } @@ -141,7 +141,7 @@ bool exitValid(UNUSED const AcyclicGraph &g, const vector &exits, return true; } if (exits.size() == 1 && open_jumps.size() == 1) { - DEBUG_PRINTF("oj %u, e %u\n", g[*open_jumps.begin()].index, + DEBUG_PRINTF("oj %zu, e %zu\n", g[*open_jumps.begin()].index, g[exits[0].exit].index); if (*open_jumps.begin() == exits[0].exit) { return true; @@ -190,7 +190,7 @@ void buildInitialCandidate(const AcyclicGraph &g, if (exits->empty()) { DEBUG_PRINTF("odd\n"); candidate->clear(); - DEBUG_PRINTF("adding %u to initial\n", g[*it].index); + DEBUG_PRINTF("adding %zu to initial\n", g[*it].index); candidate->insert(*it); open_jumps->erase(*it); checkAndAddExitCandidate(g, *candidate, *it, exits); @@ -202,7 +202,7 @@ void buildInitialCandidate(const AcyclicGraph &g, candidate->clear(); for (; it != ite; ++it) { - DEBUG_PRINTF("adding %u to initial\n", g[*it].index); + DEBUG_PRINTF("adding %zu to initial\n", g[*it].index); candidate->insert(*it); if (contains(enters, *it)) { break; @@ -231,10 +231,10 @@ void findDagLeaders(const NGHolder &h, const AcyclicGraph &g, vector exits; ue2::unordered_set candidate; ue2::unordered_set open_jumps; - DEBUG_PRINTF("adding %u to current\n", g[*t_it].index); + DEBUG_PRINTF("adding %zu to current\n", g[*t_it].index); assert(t_it != topo.rend()); candidate.insert(*t_it++); - DEBUG_PRINTF("adding %u to current\n", g[*t_it].index); + DEBUG_PRINTF("adding %zu to current\n", g[*t_it].index); assert(t_it != topo.rend()); candidate.insert(*t_it++); findExits(g, candidate, &exits); @@ -257,7 +257,7 @@ void findDagLeaders(const NGHolder &h, const AcyclicGraph &g, &open_jumps); } else { NFAVertex curr = *t_it; - DEBUG_PRINTF("adding %u to current\n", g[curr].index); + DEBUG_PRINTF("adding %zu to current\n", g[curr].index); candidate.insert(curr); open_jumps.erase(curr); refineExits(g, candidate, *t_it, &exits); @@ -284,7 +284,7 @@ void mergeUnderBackEdges(const NGHolder &g, const vector &topo, continue; } - DEBUG_PRINTF("merging v = %u(%u), u = %u(%u)\n", g[v].index, rv, + DEBUG_PRINTF("merging v = %zu(%u), u = %zu(%u)\n", g[v].index, rv, g[u].index, ru); assert(rv < ru); @@ -350,8 +350,8 @@ void liftSinks(const AcyclicGraph &acyclic_g, vector &topoOrder) { } if (isLeafNode(v, acyclic_g)) { - DEBUG_PRINTF("sink found %u\n", acyclic_g[v].index); - sinks.insert(v); + DEBUG_PRINTF("sink found %zu\n", acyclic_g[v].index); + sinks.insert(NFAVertex(v)); } } @@ -365,18 +365,18 @@ void liftSinks(const AcyclicGraph &acyclic_g, vector &topoOrder) { DEBUG_PRINTF("look\n"); changed = false; for (auto v : vertices_range(acyclic_g)) { - if (is_special(v, acyclic_g) || contains(sinks, v)) { + if (is_special(v, acyclic_g) || contains(sinks, NFAVertex(v))) { continue; } for (auto w : adjacent_vertices_range(v, acyclic_g)) { - if (!contains(sinks, w)) { + if (!contains(sinks, NFAVertex(w))) { goto next; } } - DEBUG_PRINTF("sink found %u\n", acyclic_g[v].index); - sinks.insert(v); + DEBUG_PRINTF("sink found %zu\n", acyclic_g[v].index); + sinks.insert(NFAVertex(v)); changed = true; next:; } @@ -387,10 +387,10 @@ void liftSinks(const AcyclicGraph &acyclic_g, vector &topoOrder) { continue; } NFAVertex s = *ri; - DEBUG_PRINTF("handling sink %u\n", acyclic_g[s].index); + DEBUG_PRINTF("handling sink %zu\n", acyclic_g[s].index); ue2::unordered_set parents; for (const auto &e : in_edges_range(s, acyclic_g)) { - parents.insert(source(e, acyclic_g)); + parents.insert(NFAVertex(source(e, acyclic_g))); } /* vertex has no children not reachable on a back edge, bubble the @@ -417,10 +417,9 @@ vector buildTopoOrder(const NGHolder &w, vector &colours) { vector topoOrder; - topological_sort( - acyclic_g, back_inserter(topoOrder), - color_map(make_iterator_property_map( - colours.begin(), get(&NFAGraphVertexProps::index, acyclic_g)))); + topological_sort(acyclic_g, back_inserter(topoOrder), + color_map(make_iterator_property_map(colours.begin(), + get(vertex_index, acyclic_g)))); reorderSpecials(w, acyclic_g, topoOrder); @@ -432,7 +431,7 @@ vector buildTopoOrder(const NGHolder &w, DEBUG_PRINTF("TOPO ORDER\n"); for (auto ri = topoOrder.rbegin(); ri != topoOrder.rend(); ++ri) { - DEBUG_PRINTF("[%u]\n", acyclic_g[*ri].index); + DEBUG_PRINTF("[%zu]\n", acyclic_g[*ri].index); } DEBUG_PRINTF("----------\n"); @@ -448,14 +447,14 @@ ue2::unordered_map assignRegions(const NGHolder &g) { // Build an acyclic graph for this NGHolder. BackEdgeSet deadEdges; - depth_first_search( - g.g, visitor(BackEdges(deadEdges)) - .root_vertex(g.start) - .color_map(make_iterator_property_map( - colours.begin(), get(&NFAGraphVertexProps::index, g.g)))); + depth_first_search(g, + visitor(BackEdges(deadEdges)) + .root_vertex(g.start) + .color_map(make_iterator_property_map(colours.begin(), + get(vertex_index, g)))); auto af = make_bad_edge_filter(&deadEdges); - AcyclicGraph acyclic_g(g.g, af); + AcyclicGraph acyclic_g(g, af); // Build a (reverse) topological ordering. vector topoOrder = buildTopoOrder(g, acyclic_g, colours); diff --git a/src/nfagraph/ng_region.h b/src/nfagraph/ng_region.h index 464a6838..a56933dc 100644 --- a/src/nfagraph/ng_region.h +++ b/src/nfagraph/ng_region.h @@ -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 * modification, are permitted provided that the following conditions are met: @@ -181,7 +181,7 @@ bool isOptionalRegion(const Graph &g, NFAVertex v, const ue2::unordered_map ®ion_map) { assert(isRegionEntry(g, v, region_map)); - DEBUG_PRINTF("check if r%u is optional (inspecting v%u)\n", + DEBUG_PRINTF("check if r%u is optional (inspecting v%zu)\n", region_map.at(v), g[v].index); // Region zero is never optional. @@ -198,12 +198,12 @@ bool isOptionalRegion(const Graph &g, NFAVertex v, if (inSameRegion(g, v, u, region_map)) { continue; } - DEBUG_PRINTF(" searching from u=%u\n", g[u].index); + DEBUG_PRINTF(" searching from u=%zu\n", g[u].index); assert(inEarlierRegion(g, v, u, region_map)); for (auto w : adjacent_vertices_range(u, g)) { - DEBUG_PRINTF(" searching to w=%u\n", g[w].index); + DEBUG_PRINTF(" searching to w=%zu\n", g[w].index); if (inLaterRegion(g, v, w, region_map)) { return true; } diff --git a/src/nfagraph/ng_region_redundancy.cpp b/src/nfagraph/ng_region_redundancy.cpp index 5cd266dc..264e4312 100644 --- a/src/nfagraph/ng_region_redundancy.cpp +++ b/src/nfagraph/ng_region_redundancy.cpp @@ -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 * modification, are permitted provided that the following conditions are met: @@ -90,7 +90,7 @@ void processCyclicStateForward(NGHolder &h, NFAVertex cyc, CharReach cr = h[cyc].char_reach; auto reports = h[cyc].reports; - DEBUG_PRINTF("going forward from %u/%u\n", h[cyc].index, + DEBUG_PRINTF("going forward from %zu/%u\n", h[cyc].index, region); map::const_iterator it; @@ -98,7 +98,7 @@ void processCyclicStateForward(NGHolder &h, NFAVertex cyc, NFAVertex v = it->second.entry; const CharReach ®ion_cr = it->second.cr; assert(isRegionEntry(h, v, region_map) && !is_special(v, h)); - DEBUG_PRINTF("checking %u\n", h[v].index); + DEBUG_PRINTF("checking %zu\n", h[v].index); if (!region_cr.isSubsetOf(cr)) { DEBUG_PRINTF("doesn't cover the reach of region %u\n", region); @@ -107,8 +107,8 @@ void processCyclicStateForward(NGHolder &h, NFAVertex cyc, if (isOptionalRegion(h, v, region_map) && !regionHasUnexpectedAccept(h, region, reports, region_map)) { - DEBUG_PRINTF("cyclic state %u leads to optional region leader %u\n", - h[cyc].index, h[v].index); + DEBUG_PRINTF("cyclic state %zu leads to optional region leader" + " %zu\n", h[cyc].index, h[v].index); deadRegions.insert(region); } else if (isSingletonRegion(h, v, region_map)) { /* we can use this region as straw and suck in optional regions on @@ -136,14 +136,14 @@ void processCyclicStateReverse(NGHolder &h, NFAVertex cyc, CharReach cr = h[cyc].char_reach; auto reports = h[cyc].reports; - DEBUG_PRINTF("going back from %u/%u\n", h[cyc].index, region); + DEBUG_PRINTF("going back from %zu/%u\n", h[cyc].index, region); map::const_iterator it; while ((it = info.find(--region)) != info.end()) { NFAVertex v = it->second.entry; const CharReach ®ion_cr = it->second.cr; assert(isRegionEntry(h, v, region_map) && !is_special(v, h)); - DEBUG_PRINTF("checking %u\n", h[v].index); + DEBUG_PRINTF("checking %zu\n", h[v].index); if (!region_cr.isSubsetOf(cr)) { DEBUG_PRINTF("doesn't cover the reach of region %u\n", region); @@ -152,7 +152,7 @@ void processCyclicStateReverse(NGHolder &h, NFAVertex cyc, if (isOptionalRegion(h, v, region_map) && !regionHasUnexpectedAccept(h, region, reports, region_map)) { - DEBUG_PRINTF("cyclic state %u trails optional region leader %u\n", + DEBUG_PRINTF("cyclic state %zu trails optional region leader %zu\n", h[cyc].index, h[v].index); deadRegions.insert(region); } else if (isSingletonRegion(h, v, region_map)) { diff --git a/src/nfagraph/ng_repeat.cpp b/src/nfagraph/ng_repeat.cpp index 6eb2a9d7..0aa6dc4b 100644 --- a/src/nfagraph/ng_repeat.cpp +++ b/src/nfagraph/ng_repeat.cpp @@ -61,6 +61,8 @@ #include using namespace std; +using boost::depth_first_search; +using boost::depth_first_visit; namespace ue2 { @@ -99,7 +101,7 @@ struct ReachFilter { const Graph *g = nullptr; }; -typedef boost::filtered_graph > RepeatGraph; +typedef boost::filtered_graph> RepeatGraph; struct ReachSubgraph { vector vertices; @@ -126,9 +128,11 @@ void findInitDepths(const NGHolder &g, } } -template static -void buildTopoOrder(const Graph &g, vector &topoOrder) { +vector buildTopoOrder(const RepeatGraph &g) { + /* Note: RepeatGraph is a filtered version of NGHolder and still has + * NFAVertex as its vertex descriptor */ + typedef ue2::unordered_set EdgeSet; EdgeSet deadEdges; @@ -140,10 +144,13 @@ void buildTopoOrder(const Graph &g, vector &topoOrder) { color_map(make_assoc_property_map(colours))); auto acyclic_g = make_filtered_graph(g, make_bad_edge_filter(&deadEdges)); + vector topoOrder; topological_sort(acyclic_g, back_inserter(topoOrder), color_map(make_assoc_property_map(colours))); reverse(topoOrder.begin(), topoOrder.end()); + + return topoOrder; } static @@ -171,7 +178,7 @@ bool roguePredecessor(const NGHolder &g, NFAVertex v, continue; } if (!contains(pred, u)) { - DEBUG_PRINTF("%u is a rogue pred\n", g[u].index); + DEBUG_PRINTF("%zu is a rogue pred\n", g[u].index); return true; } @@ -197,7 +204,7 @@ bool rogueSuccessor(const NGHolder &g, NFAVertex v, } if (!contains(succ, w)) { - DEBUG_PRINTF("%u is a rogue succ\n", g[w].index); + DEBUG_PRINTF("%zu is a rogue succ\n", g[w].index); return true; } @@ -223,8 +230,8 @@ bool hasDifferentTops(const NGHolder &g, const vector &verts) { if (u != g.start && u != g.startDs) { continue; // Only edges from starts have valid top properties. } - DEBUG_PRINTF("edge (%u,%u) with %zu tops\n", g[u].index, g[v].index, - g[e].tops.size()); + DEBUG_PRINTF("edge (%zu,%zu) with %zu tops\n", g[u].index, + g[v].index, g[e].tops.size()); if (!tops) { tops = &g[e].tops; } else if (g[e].tops != *tops) { @@ -243,14 +250,14 @@ bool vertexIsBad(const NGHolder &g, NFAVertex v, const ue2::unordered_set &pred, const ue2::unordered_set &succ, const flat_set &reports) { - DEBUG_PRINTF("check vertex %u\n", g[v].index); + DEBUG_PRINTF("check vertex %zu\n", g[v].index); // We must drop any vertex that is the target of a back-edge within // our subgraph. The tail set contains all vertices that are after v in a // topo ordering. for (auto u : inv_adjacent_vertices_range(v, g)) { if (contains(tail, u)) { - DEBUG_PRINTF("back-edge (%u,%u) in subgraph found\n", + DEBUG_PRINTF("back-edge (%zu,%zu) in subgraph found\n", g[u].index, g[v].index); return true; } @@ -260,18 +267,18 @@ bool vertexIsBad(const NGHolder &g, NFAVertex v, // edges from *all* the vertices in pred and no other external entries. // Similarly for exits. if (roguePredecessor(g, v, involved, pred)) { - DEBUG_PRINTF("preds for %u not well-formed\n", g[v].index); + DEBUG_PRINTF("preds for %zu not well-formed\n", g[v].index); return true; } if (rogueSuccessor(g, v, involved, succ)) { - DEBUG_PRINTF("succs for %u not well-formed\n", g[v].index); + DEBUG_PRINTF("succs for %zu not well-formed\n", g[v].index); return true; } // All reporting vertices should have the same reports. if (is_match_vertex(v, g) && reports != g[v].reports) { - DEBUG_PRINTF("report mismatch to %u\n", g[v].index); + DEBUG_PRINTF("report mismatch to %zu\n", g[v].index); return true; } @@ -291,8 +298,7 @@ void splitSubgraph(const NGHolder &g, const deque &verts, NFAUndirectedGraph ug; ue2::unordered_map old2new; - ue2::unordered_map newIdx2old; - createUnGraph(verts_g.g, true, true, ug, old2new, newIdx2old); + createUnGraph(verts_g, true, true, ug, old2new); ue2::unordered_map repeatMap; @@ -517,7 +523,7 @@ bool processSubgraph(const NGHolder &g, ReachSubgraph &rsi, if (u == first) { continue; // no self-loops } - DEBUG_PRINTF("pred vertex %u\n", g[u].index); + DEBUG_PRINTF("pred vertex %zu\n", g[u].index); dist[u].insert(0); } @@ -619,7 +625,7 @@ void buildTugTrigger(NGHolder &g, NFAVertex cyclic, NFAVertex v, vector &tugs) { if (allPredsInSubgraph(v, g, involved)) { // We can transform this vertex into a tug trigger in-place. - DEBUG_PRINTF("all preds in subgraph, vertex %u becomes tug\n", + DEBUG_PRINTF("all preds in subgraph, vertex %zu becomes tug\n", g[v].index); add_edge(cyclic, v, g); tugs.push_back(v); @@ -631,7 +637,7 @@ void buildTugTrigger(NGHolder &g, NFAVertex cyclic, NFAVertex v, NFAVertex t = clone_vertex(g, v); depths[t] = depths[v]; - DEBUG_PRINTF("there are other paths, cloned tug %u from vertex %u\n", + DEBUG_PRINTF("there are other paths, cloned tug %zu from vertex %zu\n", g[t].index, g[v].index); tugs.push_back(t); @@ -648,7 +654,7 @@ NFAVertex createCyclic(NGHolder &g, ReachSubgraph &rsi) { NFAVertex cyclic = clone_vertex(g, last); add_edge(cyclic, cyclic, g); - DEBUG_PRINTF("created cyclic vertex %u\n", g[cyclic].index); + DEBUG_PRINTF("created cyclic vertex %zu\n", g[cyclic].index); return cyclic; } @@ -659,7 +665,7 @@ NFAVertex createPos(NGHolder &g, ReachSubgraph &rsi) { g[pos].char_reach = g[first].char_reach; - DEBUG_PRINTF("created pos vertex %u\n", g[pos].index); + DEBUG_PRINTF("created pos vertex %zu\n", g[pos].index); return pos; } @@ -705,7 +711,7 @@ void unpeelNearEnd(NGHolder &g, ReachSubgraph &rsi, NFAVertex d = clone_vertex(g, last); depths[d] = depths[last]; - DEBUG_PRINTF("created vertex %u\n", g[d].index); + DEBUG_PRINTF("created vertex %zu\n", g[d].index); for (auto v : *succs) { add_edge(d, v, g); @@ -946,7 +952,7 @@ bool peelSubgraph(const NGHolder &g, const Grey &grey, ReachSubgraph &rsi, zap = it; break; } else { - DEBUG_PRINTF("%u is involved in another repeat\n", g[*it].index); + DEBUG_PRINTF("%zu is involved in another repeat\n", g[*it].index); } } DEBUG_PRINTF("peeling %zu vertices from front\n", @@ -963,7 +969,7 @@ bool peelSubgraph(const NGHolder &g, const Grey &grey, ReachSubgraph &rsi, zap = it.base(); // Note: erases everything after it. break; } else { - DEBUG_PRINTF("%u is involved in another repeat\n", g[*it].index); + DEBUG_PRINTF("%zu is involved in another repeat\n", g[*it].index); } } DEBUG_PRINTF("peeling %zu vertices from back\n", @@ -974,7 +980,7 @@ bool peelSubgraph(const NGHolder &g, const Grey &grey, ReachSubgraph &rsi, // no-no. for (auto v : rsi.vertices) { if (contains(created, v)) { - DEBUG_PRINTF("vertex %u is in another repeat\n", g[v].index); + DEBUG_PRINTF("vertex %zu is in another repeat\n", g[v].index); return false; } } @@ -997,7 +1003,7 @@ void peelStartDotStar(const NGHolder &g, NFAVertex first = rsi.vertices.front(); if (depths.at(first).fromStartDotStar.min == depth(1)) { - DEBUG_PRINTF("peeling start front vertex %u\n", g[first].index); + DEBUG_PRINTF("peeling start front vertex %zu\n", g[first].index); rsi.vertices.erase(rsi.vertices.begin()); reprocessSubgraph(g, grey, rsi); } @@ -1006,8 +1012,8 @@ void peelStartDotStar(const NGHolder &g, static void buildReachSubgraphs(const NGHolder &g, vector &rs, const u32 minNumVertices) { - const ReachFilter fil(&g.g); - const RepeatGraph rg(g.g, fil); + const ReachFilter fil(&g); + const RepeatGraph rg(g, fil); if (!isCompBigEnough(rg, minNumVertices)) { DEBUG_PRINTF("component not big enough, bailing\n"); @@ -1015,19 +1021,17 @@ void buildReachSubgraphs(const NGHolder &g, vector &rs, } NFAUndirectedGraph ug; - ue2::unordered_map old2new; - ue2::unordered_map newIdx2old; - createUnGraph(rg, true, true, ug, old2new, newIdx2old); + unordered_map old2new; + createUnGraph(rg, true, true, ug, old2new); - ue2::unordered_map repeatMap; + unordered_map repeatMap; unsigned int num; num = connected_components(ug, make_assoc_property_map(repeatMap)); DEBUG_PRINTF("found %u connected repeat components\n", num); // Now, we build a set of topo-ordered ReachSubgraphs. - vector topoOrder; - buildTopoOrder(rg, topoOrder); + vector topoOrder = buildTopoOrder(rg); rs.resize(num); @@ -1078,7 +1082,7 @@ bool entered_at_fixed_offset(NFAVertex v, const NGHolder &g, if (is_triggered(g) && !contains(reached_by_fixed_tops, v)) { /* can't do this for infix/suffixes unless we know trigger literals * can only occur at one offset */ - DEBUG_PRINTF("bad top(s) for %u\n", g[v].index); + DEBUG_PRINTF("bad top(s) for %zu\n", g[v].index); return false; } @@ -1098,8 +1102,8 @@ bool entered_at_fixed_offset(NFAVertex v, const NGHolder &g, for (auto u : inv_adjacent_vertices_range(v, g)) { const depth &u_max_depth = depths.at(u).fromStart.max; - DEBUG_PRINTF("pred %u max depth %s from start\n", - g[u].index, u_max_depth.str().c_str()); + DEBUG_PRINTF("pred %zu max depth %s from start\n", g[u].index, + u_max_depth.str().c_str()); if (u_max_depth != first - depth(1)) { return false; } @@ -1122,7 +1126,7 @@ NFAVertex buildTriggerStates(NGHolder &g, const vector &trigger, u = v; } - DEBUG_PRINTF("trigger len=%zu has sink %u\n", trigger.size(), g[u].index); + DEBUG_PRINTF("trigger len=%zu has sink %zu\n", trigger.size(), g[u].index); return u; } @@ -1252,7 +1256,7 @@ void buildRepeatGraph(NGHolder &rg, if (is_triggered(rg)) { // Add vertices for all our triggers addTriggers(rg, triggers); - rg.renumberVertices(); + renumber_vertices(rg); // We don't know anything about how often this graph is triggered, so we // make the start vertex cyclic for the purposes of this analysis ONLY. @@ -1274,30 +1278,26 @@ void buildInputGraph(NGHolder &lhs, ue2::unordered_map &lhs_map, const NGHolder &g, const NFAVertex first, const map>> &triggers) { - DEBUG_PRINTF("building lhs with first=%u\n", g[first].index); + DEBUG_PRINTF("building lhs with first=%zu\n", g[first].index); cloneHolder(lhs, g, &lhs_map); assert(g.kind == lhs.kind); addTriggers(lhs, triggers); - lhs.renumberVertices(); + renumber_vertices(lhs); // Replace each back-edge (u,v) with an edge (startDs,v), which will // generate entries at at least the rate of the loop created by that // back-edge. set dead; BackEdges > backEdgeVisitor(dead); - depth_first_search( - lhs.g, visitor(backEdgeVisitor) - .root_vertex(lhs.start) - .vertex_index_map(get(&NFAGraphVertexProps::index, lhs.g))); + depth_first_search(lhs, visitor(backEdgeVisitor).root_vertex(lhs.start)); for (const auto &e : dead) { const NFAVertex u = source(e, lhs), v = target(e, lhs); if (u == v) { continue; // Self-loops are OK. } - DEBUG_PRINTF("replacing back-edge (%u,%u) with edge (startDs,%u)\n", - lhs[u].index, lhs[v].index, - lhs[v].index); + DEBUG_PRINTF("replacing back-edge (%zu,%zu) with edge (startDs,%zu)\n", + lhs[u].index, lhs[v].index, lhs[v].index); add_edge_if_not_present(lhs.startDs, v, lhs); remove_edge(e, lhs); @@ -1384,13 +1384,13 @@ bool hasSoleEntry(const NGHolder &g, const ReachSubgraph &rsi, for (const auto &v : rsi.vertices) { assert(!is_special(v, g)); // no specials in repeats assert(contains(rg_map, v)); - DEBUG_PRINTF("rg vertex %u in repeat\n", rg[rg_map.at(v)].index); + DEBUG_PRINTF("rg vertex %zu in repeat\n", rg[rg_map.at(v)].index); region_map.emplace(rg_map.at(v), repeat_region); } for (const auto &v : vertices_range(rg)) { if (!contains(region_map, v)) { - DEBUG_PRINTF("rg vertex %u in lhs (trigger)\n", rg[v].index); + DEBUG_PRINTF("rg vertex %zu in lhs (trigger)\n", rg[v].index); region_map.emplace(v, lhs_region); } } @@ -1432,7 +1432,7 @@ struct StrawWalker { if (next == v) { // Ignore self loop. ++ai; if (ai == ae) { - return NFAGraph::null_vertex(); + return NGHolder::null_vertex(); } next = *ai; } @@ -1447,7 +1447,7 @@ struct StrawWalker { succs.erase(v); for (tie(ai, ae) = adjacent_vertices(v, g); ai != ae; ++ai) { next = *ai; - DEBUG_PRINTF("checking %u\n", g[next].index); + DEBUG_PRINTF("checking %zu\n", g[next].index); if (next == v) { continue; } @@ -1468,32 +1468,31 @@ struct StrawWalker { return next; } DEBUG_PRINTF("bailing\n"); - return NFAGraph::null_vertex(); + return NGHolder::null_vertex(); } return next; } NFAVertex walk(NFAVertex v, vector &straw) const { - DEBUG_PRINTF("walk from %u\n", g[v].index); + DEBUG_PRINTF("walk from %zu\n", g[v].index); ue2::unordered_set visited; straw.clear(); while (!is_special(v, g)) { - DEBUG_PRINTF("checking %u\n", g[v].index); + DEBUG_PRINTF("checking %zu\n", g[v].index); NFAVertex next = step(v); - if (next == NFAGraph::null_vertex()) { + if (next == NGHolder::null_vertex()) { break; } if (!visited.insert(next).second) { - DEBUG_PRINTF("already visited %u, bailing\n", - g[next].index); + DEBUG_PRINTF("already visited %zu, bailing\n", g[next].index); break; /* don't want to get stuck in any complicated loops */ } const CharReach &reach_v = g[v].char_reach; const CharReach &reach_next = g[next].char_reach; if (!reach_v.isSubsetOf(reach_next)) { - DEBUG_PRINTF("%u's reach is not a superset of %u's\n", + DEBUG_PRINTF("%zu's reach is not a superset of %zu's\n", g[next].index, g[v].index); break; } @@ -1501,7 +1500,7 @@ struct StrawWalker { // If this is cyclic with the right reach, we're done. Note that // startDs fulfils this requirement. if (hasSelfLoop(next, g) && !isBoundedRepeatCyclic(next)) { - DEBUG_PRINTF("found cyclic %u\n", g[next].index); + DEBUG_PRINTF("found cyclic %zu\n", g[next].index); return next; } @@ -1510,7 +1509,7 @@ struct StrawWalker { } straw.clear(); - return NFAGraph::null_vertex(); + return NGHolder::null_vertex(); } private: @@ -1525,8 +1524,8 @@ static NFAVertex walkStrawToCyclicRev(const NGHolder &g, NFAVertex v, const vector &all_repeats, vector &straw) { - typedef boost::reverse_graph RevGraph; - const RevGraph revg(g.g); + typedef boost::reverse_graph RevGraph; + const RevGraph revg(g); auto cyclic = StrawWalker(g, revg, all_repeats).walk(v, straw); reverse(begin(straw), end(straw)); // path comes from cyclic @@ -1537,7 +1536,7 @@ static NFAVertex walkStrawToCyclicFwd(const NGHolder &g, NFAVertex v, const vector &all_repeats, vector &straw) { - return StrawWalker(g, g.g, all_repeats).walk(v, straw); + return StrawWalker(g, g, all_repeats).walk(v, straw); } /** True if entries to this subgraph must pass through a cyclic state with @@ -1553,7 +1552,7 @@ bool hasCyclicSupersetEntryPath(const NGHolder &g, const ReachSubgraph &rsi, // until we encounter our cyclic, all of which must have superset reach. vector straw; return walkStrawToCyclicRev(g, rsi.vertices.front(), all_repeats, straw) != - NFAGraph::null_vertex(); + NGHolder::null_vertex(); } static @@ -1561,7 +1560,7 @@ bool hasCyclicSupersetExitPath(const NGHolder &g, const ReachSubgraph &rsi, const vector &all_repeats) { vector straw; return walkStrawToCyclicFwd(g, rsi.vertices.back(), all_repeats, straw) != - NFAGraph::null_vertex(); + NGHolder::null_vertex(); } static @@ -1844,7 +1843,7 @@ void buildFeeder(NGHolder &g, const BoundedRepeatData &rd, add_edge(u, feeder, g); } - DEBUG_PRINTF("added feeder %u\n", g[feeder].index); + DEBUG_PRINTF("added feeder %zu\n", g[feeder].index); } else { // No neg trigger means feeder is empty, and unnecessary. assert(g[rd.pos_trigger].char_reach.all()); @@ -1892,13 +1891,13 @@ bool improveLeadingRepeat(NGHolder &g, BoundedRepeatData &rd, // This transformation is only safe if the straw path from startDs that // we've discovered can *only* lead to this repeat, since we're going to // remove the self-loop on startDs. - if (hasGreaterOutDegree(2, g.startDs, g)) { + if (proper_out_degree(g.startDs, g) > 1) { DEBUG_PRINTF("startDs has other successors\n"); return false; } for (const auto &v : straw) { if (proper_out_degree(v, g) != 1) { - DEBUG_PRINTF("branch between startDs and repeat, from vertex %u\n", + DEBUG_PRINTF("branch between startDs and repeat, from vertex %zu\n", g[v].index); return false; } @@ -2068,8 +2067,8 @@ public: const depth &our_depth_in) : top_depths(top_depths_in), our_depth(our_depth_in) {} - void discover_vertex(NFAVertex v, UNUSED const NFAGraph &g) { - DEBUG_PRINTF("discovered %u (depth %s)\n", g[v].index, + void discover_vertex(NFAVertex v, UNUSED const NGHolder &g) { + DEBUG_PRINTF("discovered %zu (depth %s)\n", g[v].index, our_depth.str().c_str()); auto it = top_depths.find(v); @@ -2120,22 +2119,21 @@ void populateFixedTopInfo(const map &fixed_depth_tops, } } - DEBUG_PRINTF("scanning from %u depth=%s\n", g[v].index, + DEBUG_PRINTF("scanning from %zu depth=%s\n", g[v].index, td.str().c_str()); /* for each vertex reachable from v update its map to reflect that it is * reachable from a top of depth td. */ - depth_first_visit( - g.g, v, pfti_visitor(top_depths, td), - make_iterator_property_map(colours.begin(), - get(&NFAGraphVertexProps::index, g.g))); + depth_first_visit(g, v, pfti_visitor(top_depths, td), + make_iterator_property_map(colours.begin(), + get(vertex_index, g))); } for (const auto &v_depth : top_depths) { const NFAVertex v = v_depth.first; const depth &d = v_depth.second; if (d.is_finite()) { - DEBUG_PRINTF("%u reached by fixed tops at depth %s\n", + DEBUG_PRINTF("%zu reached by fixed tops at depth %s\n", g[v].index, d.str().c_str()); reached_by_fixed_tops->insert(v); } @@ -2152,19 +2150,16 @@ bool hasOverlappingRepeats(UNUSED const NGHolder &g, for (const auto &br : repeats) { if (contains(involved, br.cyclic)) { - DEBUG_PRINTF("already seen cyclic %u\n", - g[br.cyclic].index); + DEBUG_PRINTF("already seen cyclic %zu\n", g[br.cyclic].index); return true; } if (contains(involved, br.pos_trigger)) { - DEBUG_PRINTF("already seen pos %u\n", - g[br.pos_trigger].index); + DEBUG_PRINTF("already seen pos %zu\n", g[br.pos_trigger].index); return true; } for (auto v : br.tug_triggers) { if (contains(involved, v)) { - DEBUG_PRINTF("already seen tug %u\n", - g[v].index); + DEBUG_PRINTF("already seen tug %zu\n", g[v].index); return true; } } @@ -2310,7 +2305,7 @@ void analyseRepeats(NGHolder &g, const ReportManager *rm, // Go to town on the remaining acceptable subgraphs. ue2::unordered_set created; for (auto &rsi : rs) { - DEBUG_PRINTF("subgraph (beginning vertex %u) is a {%s,%s} repeat\n", + DEBUG_PRINTF("subgraph (beginning vertex %zu) is a {%s,%s} repeat\n", g[rsi.vertices.front()].index, rsi.repeatMin.str().c_str(), rsi.repeatMax.str().c_str()); @@ -2343,7 +2338,7 @@ void analyseRepeats(NGHolder &g, const ReportManager *rm, // Some of our analyses require correctly numbered vertices, so we // renumber after changes. - g.renumberVertices(); + renumber_vertices(g); } bool modified_start_ds = false; @@ -2384,8 +2379,8 @@ void analyseRepeats(NGHolder &g, const ReportManager *rm, // We have modified the graph, so we need to ensure that our edges // and vertices are correctly numbered. - g.renumberVertices(); - g.renumberEdges(); + renumber_vertices(g); + renumber_edges(g); // Remove stray report IDs. clearReports(g); } @@ -2424,14 +2419,14 @@ bool isPureRepeat(const NGHolder &g, PureRepeat &repeat) { // Must be start anchored. assert(edge(g.startDs, g.startDs, g).second); - if (hasGreaterOutDegree(1, g.startDs, g)) { + if (out_degree(g.startDs, g) > 1) { DEBUG_PRINTF("Unanchored\n"); return false; } // Must not be EOD-anchored. assert(edge(g.accept, g.acceptEod, g).second); - if (hasGreaterInDegree(1, g.acceptEod, g)) { + if (in_degree(g.acceptEod, g) > 1) { DEBUG_PRINTF("EOD anchored\n"); return false; } diff --git a/src/nfagraph/ng_restructuring.cpp b/src/nfagraph/ng_restructuring.cpp index 3b30a689..7bb3e991 100644 --- a/src/nfagraph/ng_restructuring.cpp +++ b/src/nfagraph/ng_restructuring.cpp @@ -52,11 +52,7 @@ namespace ue2 { static void wireStartToTops(NGHolder &g, const flat_set &tops, vector &tempEdges) { - // Construct edges in vertex index order, for determinism. - vector ordered_tops(begin(tops), end(tops)); - sort(begin(ordered_tops), end(ordered_tops), make_index_ordering(g)); - - for (NFAVertex v : ordered_tops) { + for (NFAVertex v : tops) { assert(!isLeafNode(v, g)); const NFAEdge &e = add_edge(g.start, v, g).first; @@ -102,7 +98,7 @@ void getStateOrdering(NGHolder &g, const flat_set &tops, vector tempEdges; wireStartToTops(g, tops, tempEdges); - renumberGraphVertices(g); + renumber_vertices(g); vector temp = getTopoOrdering(g); @@ -144,7 +140,7 @@ getStateIndices(const NGHolder &h, const vector &ordering) { u32 stateNum = 0; for (auto v : ordering) { - DEBUG_PRINTF("assigning state num %u to vertex %u\n", stateNum, + DEBUG_PRINTF("assigning state num %u to vertex %zu\n", stateNum, h[v].index); states[v] = stateNum++; } @@ -187,7 +183,7 @@ void optimiseTightLoops(const NGHolder &g, vector &ordering) { continue; } - DEBUG_PRINTF("moving vertex %u next to %u\n", g[v].index, g[u].index); + DEBUG_PRINTF("moving vertex %zu next to %zu\n", g[v].index, g[u].index); ordering.erase(v_it); ordering.insert(++u_it, v); diff --git a/src/nfagraph/ng_rose.cpp b/src/nfagraph/ng_rose.cpp index 46f180a8..b3649ce0 100644 --- a/src/nfagraph/ng_rose.cpp +++ b/src/nfagraph/ng_rose.cpp @@ -538,7 +538,7 @@ void getRegionRoseLiterals(const NGHolder &g, DEBUG_PRINTF("inspecting region %u\n", region); set s; for (auto v : vv) { - DEBUG_PRINTF(" exit vertex: %u\n", g[v].index); + DEBUG_PRINTF(" exit vertex: %zu\n", g[v].index); /* Note: RHS can not be depended on to take all subsequent revisits * to this vertex */ set ss = getLiteralSet(g, v, false); @@ -573,8 +573,7 @@ void gatherBackEdges(const NGHolder &g, ue2::unordered_map> *out) { set backEdges; BackEdges> be(backEdges); - depth_first_search(g.g, visitor(be).root_vertex(g.start).vertex_index_map( - get(&NFAGraphVertexProps::index, g.g))); + depth_first_search(g, visitor(be).root_vertex(g.start)); for (const auto &e : backEdges) { (*out)[source(e, g)].push_back(target(e, g)); @@ -757,7 +756,7 @@ unique_ptr LitCollection::pickNext() { unique_ptr rv = move(lits.back()); lits.pop_back(); poisonCandidates(*rv); - DEBUG_PRINTF("best is '%s' %u a%d t%d\n", + DEBUG_PRINTF("best is '%s' %zu a%d t%d\n", dumpString(*(rv->lit.begin())).c_str(), g[rv->vv.front()].index, (int)createsAnchoredLHS(g, rv->vv, depths, grey), @@ -863,8 +862,6 @@ u32 removeTrailingLiteralStates(NGHolder &g, const ue2_literal &lit, assert(delay <= lit.length()); DEBUG_PRINTF("managed delay %u (of max %u)\n", delay, max_delay); - // For determinism, we make sure that we create these edges from vertices - // in index-sorted order. set pred; for (auto v : curr) { insert(&pred, inv_adjacent_vertices_range(v, g)); @@ -873,10 +870,7 @@ u32 removeTrailingLiteralStates(NGHolder &g, const ue2_literal &lit, clear_in_edges(g.accept, g); clearReports(g); - vector verts(pred.begin(), pred.end()); - sort(verts.begin(), verts.end(), VertexIndexOrdering(g)); - - for (auto v : verts) { + for (auto v : pred) { NFAEdge e = add_edge(v, g.accept, g).first; g[v].reports.insert(0); if (is_triggered(g) && v == g.start) { @@ -921,8 +915,8 @@ void restoreTrailingLiteralStates(NGHolder &g, const ue2_literal &lit, g[u].reports.insert(0); } - g.renumberVertices(); - g.renumberEdges(); + renumber_vertices(g); + renumber_edges(g); assert(allMatchStatesHaveReports(g)); assert(isCorrectlyTopped(g)); } @@ -1152,7 +1146,7 @@ void deanchorIfNeeded(NGHolder &g, bool *orig_anch) { succ_g.erase(g.startDs); for (auto v : adjacent_vertices_range(g.start, g)) { - DEBUG_PRINTF("inspecting cand %u || =%zu\n", g[v].index, + DEBUG_PRINTF("inspecting cand %zu || =%zu\n", g[v].index, g[v].char_reach.size()); if (v == g.startDs || !g[v].char_reach.all()) { @@ -1170,7 +1164,7 @@ void deanchorIfNeeded(NGHolder &g, bool *orig_anch) { } clear_vertex(v, g); remove_vertex(v, g); - g.renumberVertices(); + renumber_vertices(g); return; } @@ -1701,7 +1695,7 @@ void splitEdgesByCut(RoseInGraph &ig, const vector &to_cut, /* TODO need to update v_mapping (if we were doing more cuts) */ } - DEBUG_PRINTF("splitting on pivot %u\n", h[pivot].index); + DEBUG_PRINTF("splitting on pivot %zu\n", h[pivot].index); ue2::unordered_map temp_map; shared_ptr new_lhs = make_shared(); splitLHS(h, pivot, new_lhs.get(), &temp_map); @@ -1774,8 +1768,8 @@ bool doNetflowCut(RoseInGraph &ig, const vector &to_cut, return false; } - h.renumberVertices(); - h.renumberEdges(); + renumber_vertices(h); + renumber_edges(h); /* Step 1: Get scores for all edges */ vector scores = scoreEdges(h); /* scores by edge_index */ /* Step 2: poison scores for edges covered by successor literal */ @@ -2573,7 +2567,7 @@ bool followedByStar(const vector &vv, const NGHolder &g) { static bool isEodPrefixCandidate(const NGHolder &g) { - if (hasGreaterInDegree(0, g.accept, g)) { + if (in_degree(g.accept, g)) { DEBUG_PRINTF("graph isn't eod anchored\n"); return false; } @@ -2644,7 +2638,7 @@ void processEodPrefixes(RoseInGraph &g) { } // TODO: handle cases with multiple out-edges. - if (hasGreaterOutDegree(1, source(e, g), g)) { + if (out_degree(source(e, g), g) > 1) { continue; } @@ -2671,7 +2665,7 @@ void processEodPrefixes(RoseInGraph &g) { } for (auto v : accepts) { - if (!hasGreaterInDegree(0, v, g)) { + if (!in_degree(v, g)) { remove_vertex(v, g); } } @@ -2813,6 +2807,7 @@ unique_ptr buildRose(const NGHolder &h, bool desperation, dumpPreRoseGraph(ig, cc.grey); + renumber_vertices(ig); calcVertexOffsets(ig); return igp; } @@ -2829,6 +2824,7 @@ void desperationImprove(RoseInGraph &ig, const CompileContext &cc) { handleLongMixedSensitivityLiterals(ig); dedupe(ig); pruneUseless(ig); + renumber_vertices(ig); calcVertexOffsets(ig); } @@ -2839,8 +2835,7 @@ bool splitOffRose(RoseBuild &rose, const NGHolder &h, bool prefilter, } // We should have at least one edge into accept or acceptEod! - assert(hasGreaterInDegree(0, h.accept, h) || - hasGreaterInDegree(1, h.acceptEod, h)); + assert(in_degree(h.accept, h) || in_degree(h.acceptEod, h) > 1); unique_ptr igp = buildRose(h, false, cc); if (igp && rose.addRose(*igp, prefilter)) { @@ -2932,6 +2927,7 @@ bool finalChanceRose(RoseBuild &rose, const NGHolder &h, bool prefilter, add_edge(v, a, RoseInEdgeProps(rhs, 0U), ig); } + renumber_vertices(ig); calcVertexOffsets(ig); return rose.addRose(ig, prefilter, true /* final chance */); @@ -2944,8 +2940,7 @@ bool checkRose(const ReportManager &rm, const NGHolder &h, bool prefilter, } // We should have at least one edge into accept or acceptEod! - assert(hasGreaterInDegree(0, h.accept, h) || - hasGreaterInDegree(1, h.acceptEod, h)); + assert(in_degree(h.accept, h) || in_degree(h.acceptEod, h) > 1); unique_ptr igp; diff --git a/src/nfagraph/ng_small_literal_set.cpp b/src/nfagraph/ng_small_literal_set.cpp index b5867bb9..1d7be65b 100644 --- a/src/nfagraph/ng_small_literal_set.cpp +++ b/src/nfagraph/ng_small_literal_set.cpp @@ -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 * modification, are permitted provided that the following conditions are met: @@ -125,7 +125,7 @@ bool findLiterals(const NGHolder &g, set &out = built[g[v].index]; read_count[g[v].index] = out_degree(v, g); - DEBUG_PRINTF("setting read_count to %zu for %u\n", + DEBUG_PRINTF("setting read_count to %zu for %zu\n", read_count[g[v].index], g[v].index); assert(out.empty()); @@ -154,7 +154,7 @@ bool findLiterals(const NGHolder &g, } set &in = built[g[u].index]; - DEBUG_PRINTF("getting from %u (%zu reads to go)\n", + DEBUG_PRINTF("getting from %zu (%zu reads to go)\n", g[u].index, read_count[g[u].index]); assert(!in.empty()); assert(read_count[g[u].index]); @@ -188,7 +188,7 @@ bool findLiterals(const NGHolder &g, read_count[g[u].index]--; if (!read_count[g[u].index]) { - DEBUG_PRINTF("clearing %u as finished reading\n", g[u].index); + DEBUG_PRINTF("clearing %zu as finished reading\n", g[u].index); in.clear(); } } diff --git a/src/nfagraph/ng_som.cpp b/src/nfagraph/ng_som.cpp index 09687c4f..862f5b53 100644 --- a/src/nfagraph/ng_som.cpp +++ b/src/nfagraph/ng_som.cpp @@ -110,7 +110,7 @@ bool regionCanEstablishSom(const NGHolder &g, DEBUG_PRINTF("region %u\n", region); for (UNUSED auto v : r_exits) { - DEBUG_PRINTF(" exit %u\n", g[v].index); + DEBUG_PRINTF(" exit %zu\n", g[v].index); } /* simple if each region exit is at fixed distance from SOM. Note SOM does @@ -119,12 +119,12 @@ bool regionCanEstablishSom(const NGHolder &g, assert(regions.at(v) == region); const DepthMinMax &d = depths.at(g[v].index); if (d.min != d.max) { - DEBUG_PRINTF("failing %u as %s != %s\n", g[v].index, + DEBUG_PRINTF("failing %zu as %s != %s\n", g[v].index, d.min.str().c_str(), d.max.str().c_str()); return false; } } - DEBUG_PRINTF("region %u/%u is good\n", regions.at(r_exits[0]), + DEBUG_PRINTF("region %u/%zu is good\n", regions.at(r_exits[0]), g[r_exits[0]].index); return true; @@ -178,10 +178,7 @@ void buildRegionMapping(const NGHolder &g, set be; BackEdges > backEdgeVisitor(be); - depth_first_search( - g.g, visitor(backEdgeVisitor) - .root_vertex(g.start) - .vertex_index_map(get(&NFAGraphVertexProps::index, g.g))); + boost::depth_first_search(g, visitor(backEdgeVisitor).root_vertex(g.start)); for (const auto &e : be) { NFAVertex u = source(e, g); @@ -208,17 +205,17 @@ void buildRegionMapping(const NGHolder &g, r_i.optional ? " (optional)" : ""); DEBUG_PRINTF(" enters:"); for (u32 i = 0; i < r_i.enters.size(); i++) { - printf(" %u", g[r_i.enters[i]].index); + printf(" %zu", g[r_i.enters[i]].index); } printf("\n"); DEBUG_PRINTF(" exits:"); for (u32 i = 0; i < r_i.exits.size(); i++) { - printf(" %u", g[r_i.exits[i]].index); + printf(" %zu", g[r_i.exits[i]].index); } printf("\n"); DEBUG_PRINTF(" all:"); for (u32 i = 0; i < r_i.full.size(); i++) { - printf(" %u", g[r_i.full[i]].index); + printf(" %zu", g[r_i.full[i]].index); } printf("\n"); } @@ -235,8 +232,7 @@ bool validateXSL(const NGHolder &g, u32 v_region = regions.at(v); if (!is_special(v, g) && v_region > region && (escapes & g[v].char_reach).any()) { - DEBUG_PRINTF("problem with escapes for %u\n", - g[v].index); + DEBUG_PRINTF("problem with escapes for %zu\n", g[v].index); first_bad_region = MIN(first_bad_region, v_region); } } @@ -402,7 +398,7 @@ makePrefix(const NGHolder &g, const ue2::unordered_map ®ions, vector to_clear; assert(contains(lhs_map, curr_exits.front())); NFAVertex p_u = lhs_map[curr_exits.front()]; - DEBUG_PRINTF("p_u: %u\n", prefix[p_u].index); + DEBUG_PRINTF("p_u: %zu\n", prefix[p_u].index); for (auto p_v : adjacent_vertices_range(p_u, prefix)) { auto v = rev_map.at(p_v); if (p_v == prefix.accept || regions.at(v) < dead_region) { @@ -412,7 +408,7 @@ makePrefix(const NGHolder &g, const ue2::unordered_map ®ions, } for (auto v : to_clear) { - DEBUG_PRINTF("clearing in_edges on %u\n", prefix[v].index); + DEBUG_PRINTF("clearing in_edges on %zu\n", prefix[v].index); clear_in_edges(v, prefix); } @@ -575,7 +571,7 @@ void replaceExternalReportsWithSomRep(ReportManager &rm, NGHolder &g, ir.somDistance = param; ReportID rep = rm.getInternalId(ir); - DEBUG_PRINTF("vertex %u, replacing report %u with %u (type %u)\n", + DEBUG_PRINTF("vertex %zu, replacing report %u with %u (type %u)\n", g[v].index, report_id, rep, ir_type); r_new.insert(rep); } @@ -713,7 +709,7 @@ void fillHolderForLockCheck(NGHolder *out, const NGHolder &g, /* add all vertices in region, create mapping */ for (auto v : jt->second.full) { - DEBUG_PRINTF("adding v %u to midfix\n", g[v].index); + DEBUG_PRINTF("adding v %zu to midfix\n", g[v].index); if (contains(v_map, v)) { continue; } @@ -758,7 +754,7 @@ void fillHolderForLockCheck(NGHolder *out, const NGHolder &g, } assert(in_degree(midfix.accept, midfix)); - midfix.renumberVertices(); + renumber_vertices(midfix); } static @@ -785,7 +781,7 @@ void fillRoughMidfix(NGHolder *out, const NGHolder &g, /* add all vertices in region, create mapping */ for (auto v : jt->second.full) { - DEBUG_PRINTF("adding v %u to midfix\n", g[v].index); + DEBUG_PRINTF("adding v %zu to midfix\n", g[v].index); NFAVertex vnew = add_vertex(g[v], midfix); v_map[v] = vnew; } @@ -825,7 +821,7 @@ void fillRoughMidfix(NGHolder *out, const NGHolder &g, do { for (auto v : jt->second.exits) { - DEBUG_PRINTF("adding v %u to midfix\n", g[v].index); + DEBUG_PRINTF("adding v %zu to midfix\n", g[v].index); NFAVertex vnew = add_vertex(g[v], midfix); v_map[v] = vnew; @@ -1012,8 +1008,7 @@ bool addPlan(vector &plan, u32 parent) { // Fetches all preds of {accept, acceptEod} for this graph. static void addReporterVertices(const NGHolder &g, vector &reporters) { - // Order reporter vertices by index for determinism. - set > tmp(g); + set tmp; insert(&tmp, inv_adjacent_vertices(g.accept, g)); insert(&tmp, inv_adjacent_vertices(g.acceptEod, g)); tmp.erase(g.accept); @@ -1021,7 +1016,7 @@ void addReporterVertices(const NGHolder &g, vector &reporters) { #ifdef DEBUG DEBUG_PRINTF("add reporters:"); for (UNUSED auto v : tmp) { - printf(" %u", g[v].index); + printf(" %zu", g[v].index); } printf("\n"); #endif @@ -1035,7 +1030,7 @@ void addReporterVertices(const region_info &r, const NGHolder &g, vector &reporters) { for (auto v : r.exits) { if (edge(v, g.accept, g).second || edge(v, g.acceptEod, g).second) { - DEBUG_PRINTF("add reporter %u\n", g[v].index); + DEBUG_PRINTF("add reporter %zu\n", g[v].index); reporters.push_back(v); } } @@ -1048,7 +1043,7 @@ void addMappedReporterVertices(const region_info &r, const NGHolder &g, vector &reporters) { for (auto v : r.exits) { if (edge(v, g.accept, g).second || edge(v, g.acceptEod, g).second) { - DEBUG_PRINTF("adding v=%u\n", g[v].index); + DEBUG_PRINTF("adding v=%zu\n", g[v].index); ue2::unordered_map::const_iterator it = mapping.find(v); assert(it != mapping.end()); @@ -1105,7 +1100,7 @@ void expandGraph(NGHolder &g, ue2::unordered_map ®ions, } for (auto enter : enters) { - DEBUG_PRINTF("processing enter %u\n", g[enter].index); + DEBUG_PRINTF("processing enter %zu\n", g[enter].index); map orig_to_copy; // Make a copy of all of the tail vertices, storing region info along @@ -1155,7 +1150,7 @@ void expandGraph(NGHolder &g, ue2::unordered_map ®ions, [&](const NFAEdge &e) { NFAVertex u = source(e, g); return regions.at(u) < split_region; - }, g.g); + }, g); } new_enters.push_back(orig_to_copy[enter]); @@ -1327,7 +1322,7 @@ bool doTreePlanning(NGHolder &g, dumpHolder(g, g_regions, 14, "som_expandedtree", grey); for (auto v : enters) { - DEBUG_PRINTF("enter %u\n", g[v].index); + DEBUG_PRINTF("enter %zu\n", g[v].index); // For this entry vertex, construct a version of the graph without the // other entries in this region (g_path), and calculate its depths and @@ -1562,12 +1557,12 @@ void dumpSomPlan(UNUSED const NGHolder &g, UNUSED const som_plan &p, p.is_reset, p.parent); printf(" reporters:"); for (auto v : p.reporters) { - printf(" %u", g[v].index); + printf(" %zu", g[v].index); } printf("\n"); printf(" reporters_in:"); for (auto v : p.reporters_in) { - printf(" %u", g[v].index); + printf(" %zu", g[v].index); } printf("\n"); #endif @@ -1633,7 +1628,7 @@ void implementSomPlan(NG &ng, const NGWrapper &w, u32 comp_id, NGHolder &g, /* create prefix to set the som_loc */ if (!plan.front().no_implement) { - plan.front().prefix->renumberVertices(); + renumber_vertices(*plan.front().prefix); assert(plan.front().prefix->kind == NFA_OUTFIX); if (!ng.addHolder(*plan.front().prefix)) { throw CompileError(w.expressionIndex, "Pattern is too large."); @@ -1745,7 +1740,7 @@ aligned_unique_ptr makeBareSomRevNfa(const NGHolder &g, setZeroReports(g_rev); // Prep for actual construction. - g_rev.renumberVertices(); + renumber_vertices(g_rev); g_rev.kind = NFA_REV_PREFIX; reduceGraphEquivalences(g_rev, cc); removeRedundancy(g_rev, SOM_NONE); @@ -1785,7 +1780,7 @@ bool makeSomRevNfa(vector &som_nfas, const NGHolder &g, return true; } - g2.renumberVertices(); // for findMinWidth, findMaxWidth. + renumber_vertices(g2); // for findMinWidth, findMaxWidth. aligned_unique_ptr nfa = makeBareSomRevNfa(g2, cc); if (!nfa) { @@ -2220,7 +2215,7 @@ bool leadingLiterals(const NGHolder &g, set *lits, for (const auto &m : curr) { const NFAVertex u = m.first; const vector &base = m.second; - DEBUG_PRINTF("expanding from %u\n", g[u].index); + DEBUG_PRINTF("expanding from %zu\n", g[u].index); for (auto v : adjacent_vertices_range(u, g)) { if (v == g.startDs) { continue; @@ -2233,8 +2228,7 @@ bool leadingLiterals(const NGHolder &g, set *lits, DEBUG_PRINTF("match\n"); goto skip_to_next_terminal; } - if (g[v].char_reach.count() - > 2 * MAX_LEADING_LITERALS) { + if (g[v].char_reach.count() > 2 * MAX_LEADING_LITERALS) { DEBUG_PRINTF("wide\n"); goto skip_to_next_terminal; } @@ -2250,8 +2244,8 @@ bool leadingLiterals(const NGHolder &g, set *lits, CharReach cr = g[v].char_reach; vector &out = next[v]; - DEBUG_PRINTF("expanding to %u (|| = %zu)\n", - g[v].index, cr.count()); + DEBUG_PRINTF("expanding to %zu (|| = %zu)\n", g[v].index, + cr.count()); for (size_t c = cr.find_first(); c != CharReach::npos; c = cr.find_next(c)) { bool nocase = ourisalpha(c) && cr.test(mytoupper(c)) @@ -2327,7 +2321,7 @@ bool splitOffLeadingLiterals(const NGHolder &g, set *lit_out, set adj_term1; insert(&adj_term1, adjacent_vertices(*terms.begin(), g)); for (auto v : terms) { - DEBUG_PRINTF("term %u\n", g[v].index); + DEBUG_PRINTF("term %zu\n", g[v].index); set temp; insert(&temp, adjacent_vertices(v, g)); if (temp != adj_term1) { @@ -2354,7 +2348,7 @@ void findBestLiteral(const NGHolder &g, buildRegionMapping(g, regions, info, false); ue2_literal best; - NFAVertex best_v = nullptr; + NFAVertex best_v = NGHolder::null_vertex(); map::const_iterator lit = info.begin(); while (1) { @@ -2390,7 +2384,7 @@ bool splitOffBestLiteral(const NGHolder &g, const ue2::unordered_map ®ions, ue2_literal *lit_out, NGHolder *lhs, NGHolder *rhs, const CompileContext &cc) { - NFAVertex v = nullptr; + NFAVertex v = NGHolder::null_vertex(); findBestLiteral(g, regions, lit_out, &v, cc); if (lit_out->empty()) { @@ -2404,7 +2398,7 @@ bool splitOffBestLiteral(const NGHolder &g, splitGraph(g, v, lhs, &lhs_map, rhs, &rhs_map); - DEBUG_PRINTF("v = %u\n", g[v].index); + DEBUG_PRINTF("v = %zu\n", g[v].index); return true; } @@ -2624,7 +2618,7 @@ bool doHaigLitHaigSom(NG &ng, NGHolder &g, } } else { DEBUG_PRINTF("has start->accept edge\n"); - if (hasGreaterInDegree(1, g.acceptEod, g)) { + if (in_degree(g.acceptEod, g) > 1) { DEBUG_PRINTF("also has a path to EOD\n"); return false; } @@ -2825,7 +2819,7 @@ map::const_iterator tryForLaterRevNfaCut(const NGHolder &g, reverseHolder(*prefix, g_rev); anchorStarts(g_rev); - g_rev.renumberVertices(); + renumber_vertices(g_rev); g_rev.kind = NFA_REV_PREFIX; reduceGraphEquivalences(g_rev, cc); removeRedundancy(g_rev, SOM_NONE); @@ -2869,7 +2863,7 @@ unique_ptr makePrefixForChain(NGHolder &g, } depths->clear(); /* renumbering invalidates depths */ - prefix->renumberVertices(); + renumber_vertices(*prefix); DEBUG_PRINTF("done\n"); return prefix; @@ -2885,8 +2879,7 @@ sombe_rv doSom(NG &ng, NGHolder &g, const NGWrapper &w, u32 comp_id, // Special case: if g is completely anchored or begins with a dot-star, we // know that we have an absolute SOM of zero all the time. - assert(edge(g.startDs, g.startDs, g).second); - if (!hasGreaterOutDegree(1, g.startDs, g) || beginsWithDotStar(g)) { + if (!proper_out_degree(g.startDs, g) || beginsWithDotStar(g)) { makeSomAbsReports(rm, g, g.accept); makeSomAbsReports(rm, g, g.acceptEod); return SOMBE_HANDLED_INTERNAL; @@ -3003,7 +2996,7 @@ sombe_rv doSom(NG &ng, NGHolder &g, const NGWrapper &w, u32 comp_id, u32 rev_comp_id = doSomRevNfaPrefix(ng, w, *prefix, cc); updatePrefixReportsRevNFA(rm, *prefix, rev_comp_id); } - prefix->renumberVertices(); + renumber_vertices(*prefix); if (!ng.addHolder(*prefix)) { DEBUG_PRINTF("failed to add holder\n"); clear_graph(g); diff --git a/src/nfagraph/ng_som_add_redundancy.cpp b/src/nfagraph/ng_som_add_redundancy.cpp index 924cfad1..33544ec1 100644 --- a/src/nfagraph/ng_som_add_redundancy.cpp +++ b/src/nfagraph/ng_som_add_redundancy.cpp @@ -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 * modification, are permitted provided that the following conditions are met: @@ -155,13 +155,13 @@ bool addSomRedundancy(NGHolder &g, vector &depths) { if (is_special(v, g)) { continue; } - if (!hasGreaterInDegree(0, v, g)) { + if (!in_degree(v, g)) { continue; // unreachable, probably killed } const DepthMinMax &d = getDepth(v, g, depths); - DEBUG_PRINTF("vertex %u has depths %s\n", g[v].index, + DEBUG_PRINTF("vertex %zu has depths %s\n", g[v].index, d.str().c_str()); if (d.min == d.max) { diff --git a/src/nfagraph/ng_som_util.cpp b/src/nfagraph/ng_som_util.cpp index 676fb523..c4337341 100644 --- a/src/nfagraph/ng_som_util.cpp +++ b/src/nfagraph/ng_som_util.cpp @@ -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 * modification, are permitted provided that the following conditions are met: @@ -76,7 +76,7 @@ vector getDistancesFromSOM(const NGHolder &g_orig) { clear_in_edges(v, g); } - //dumpGraph("som_depth.dot", g.g); + //dumpGraph("som_depth.dot", g); vector temp_depths; // numbered by vertex index in g calcDepthsFrom(g, g.start, temp_depths); @@ -143,7 +143,7 @@ bool firstMatchIsFirst(const NGHolder &p) { for (auto v : vertices_range(p)) { assert(!is_virtual_start(v, p)); if (!is_special(v, p)) { - DEBUG_PRINTF("turning on %u\n", p[v].index); + DEBUG_PRINTF("turning on %zu\n", p[v].index); states.insert(v); } } @@ -154,9 +154,9 @@ bool firstMatchIsFirst(const NGHolder &p) { for (auto v : states) { /* need to check if this vertex may represent an infix match - ie * it does not have an edge to accept. */ - DEBUG_PRINTF("check %u\n", p[v].index); + DEBUG_PRINTF("check %zu\n", p[v].index); if (!edge(v, p.accept, p).second) { - DEBUG_PRINTF("fail %u\n", p[v].index); + DEBUG_PRINTF("fail %zu\n", p[v].index); return false; } } @@ -186,14 +186,11 @@ bool somMayGoBackwards(NFAVertex u, const NGHolder &g, return cache.smgb[u]; } - DEBUG_PRINTF("checking if som can go backwards on %u\n", g[u].index); + DEBUG_PRINTF("checking if som can go backwards on %zu\n", g[u].index); set be; BackEdges> backEdgeVisitor(be); - depth_first_search( - g.g, visitor(backEdgeVisitor) - .root_vertex(g.start) - .vertex_index_map(get(&NFAGraphVertexProps::index, g.g))); + boost::depth_first_search(g, visitor(backEdgeVisitor).root_vertex(g.start)); bool rv; if (0) { @@ -210,8 +207,7 @@ bool somMayGoBackwards(NFAVertex u, const NGHolder &g, NFAVertex s = source(e, g); NFAVertex t = target(e, g); /* only need to worry about big cycles including/before u */ - DEBUG_PRINTF("back edge %u %u\n", g[s].index, - g[t].index); + DEBUG_PRINTF("back edge %zu %zu\n", g[s].index, g[t].index); if (s != t && region_map.at(s) <= u_region) { DEBUG_PRINTF("eek big cycle\n"); rv = true; /* big cycle -> eek */ @@ -268,13 +264,13 @@ bool somMayGoBackwards(NFAVertex u, const NGHolder &g, pruneUseless(c_g); be.clear(); - depth_first_search(c_g.g, visitor(backEdgeVisitor).root_vertex(c_g.start). - vertex_index_map(get(&NFAGraphVertexProps::index, c_g.g))); + boost::depth_first_search(c_g, visitor(backEdgeVisitor) + .root_vertex(c_g.start)); for (const auto &e : be) { NFAVertex s = source(e, c_g); NFAVertex t = target(e, c_g); - DEBUG_PRINTF("back edge %u %u\n", c_g[s].index, c_g[t].index); + DEBUG_PRINTF("back edge %zu %zu\n", c_g[s].index, c_g[t].index); if (s != t) { assert(0); DEBUG_PRINTF("eek big cycle\n"); @@ -326,7 +322,7 @@ bool sentClearsTail(const NGHolder &g, } for (UNUSED auto v : states) { - DEBUG_PRINTF("start state: %u\n", g[v].index); + DEBUG_PRINTF("start state: %zu\n", g[v].index); } /* run the prefix the main graph */ @@ -338,7 +334,7 @@ bool sentClearsTail(const NGHolder &g, continue; /* not in tail */ } - DEBUG_PRINTF("v %u is still on\n", g[v].index); + DEBUG_PRINTF("v %zu is still on\n", g[v].index); assert(v != g.accept && v != g.acceptEod); /* no cr */ assert(contains(region_map, v)); diff --git a/src/nfagraph/ng_split.cpp b/src/nfagraph/ng_split.cpp index 4576a498..ce267d0f 100644 --- a/src/nfagraph/ng_split.cpp +++ b/src/nfagraph/ng_split.cpp @@ -87,7 +87,7 @@ void splitLHS(const NGHolder &base, const vector &pivots, clearAccepts(*lhs); for (auto pivot : pivots) { - DEBUG_PRINTF("pivot is %u lv %zu lm %zu\n", base[pivot].index, + DEBUG_PRINTF("pivot is %zu lv %zu lm %zu\n", base[pivot].index, num_vertices(*lhs), lhs_map->size()); assert(contains(*lhs_map, pivot)); @@ -191,8 +191,8 @@ void findCommonSuccessors(const NGHolder &g, const vector &pivots, vector &succ) { assert(!pivots.empty()); - // Note: for determinism, we must sort our successor sets by vertex_index. - set > adj(g), adj_temp(g); + set adj; + set adj_temp; insert(&adj, adjacent_vertices(pivots.at(0), g)); diff --git a/src/nfagraph/ng_squash.cpp b/src/nfagraph/ng_squash.cpp index 21703f8b..ebec3a4a 100644 --- a/src/nfagraph/ng_squash.cpp +++ b/src/nfagraph/ng_squash.cpp @@ -134,8 +134,7 @@ void buildPDomTree(const NGHolder &g, PostDomTree &tree) { } NFAVertex pdom = postdominators[v]; if (pdom) { - DEBUG_PRINTF("vertex %u -> %u\n", g[pdom].index, - g[v].index); + DEBUG_PRINTF("vertex %zu -> %zu\n", g[pdom].index, g[v].index); tree[pdom].insert(v); } } @@ -153,8 +152,7 @@ void buildSquashMask(NFAStateSet &mask, const NGHolder &g, NFAVertex v, som_type som, const vector &som_depths, const ue2::unordered_map ®ion_map, smgb_cache &cache) { - DEBUG_PRINTF("build base squash mask for vertex %u)\n", - g[v].index); + DEBUG_PRINTF("build base squash mask for vertex %zu)\n", g[v].index); vector q; @@ -301,7 +299,7 @@ void findDerivedSquashers(const NGHolder &g, const vector &vByIndex, } NFAStateSet u_squash(init.size()); - u32 u_index = g[u].index; + size_t u_index = g[u].index; buildSquashMask(u_squash, g, u, g[u].char_reach, init, vByIndex, pdom_tree, som, som_depths, region_map, cache); @@ -309,7 +307,7 @@ void findDerivedSquashers(const NGHolder &g, const vector &vByIndex, u_squash.set(u_index); /* never clear ourselves */ if ((~u_squash).any()) { // i.e. some bits unset in mask - DEBUG_PRINTF("%u is an upstream squasher of %u\n", u_index, + DEBUG_PRINTF("%zu is an upstream squasher of %zu\n", u_index, g[v].index); (*squash)[u] = u_squash; remaining.push_back(u); @@ -521,8 +519,7 @@ void filterSquashers(const NGHolder &g, if (!contains(squash, v)) { continue; } - DEBUG_PRINTF("looking at squash set for vertex %u\n", - g[v].index); + DEBUG_PRINTF("looking at squash set for vertex %zu\n", g[v].index); if (!hasSelfLoop(v, g)) { DEBUG_PRINTF("acyclic\n"); @@ -600,7 +597,7 @@ void removeEdgesToAccept(NGHolder &g, NFAVertex v) { NFAVertex u = source(e, g); const auto &r = g[u].reports; if (!r.empty() && is_subset_of(r, reports)) { - DEBUG_PRINTF("vertex %u\n", g[u].index); + DEBUG_PRINTF("vertex %zu\n", g[u].index); dead.insert(e); } } @@ -609,7 +606,7 @@ void removeEdgesToAccept(NGHolder &g, NFAVertex v) { NFAVertex u = source(e, g); const auto &r = g[u].reports; if (!r.empty() && is_subset_of(r, reports)) { - DEBUG_PRINTF("vertex %u\n", g[u].index); + DEBUG_PRINTF("vertex %zu\n", g[u].index); dead.insert(e); } } @@ -620,7 +617,7 @@ void removeEdgesToAccept(NGHolder &g, NFAVertex v) { static vector findUnreachable(const NGHolder &g) { - const boost::reverse_graph revg(g.g); + const boost::reverse_graph revg(g); ue2::unordered_map colours; colours.reserve(num_vertices(g)); @@ -633,7 +630,7 @@ vector findUnreachable(const NGHolder &g) { vector unreach; for (auto v : vertices_range(revg)) { if (!contains(colours, v)) { - unreach.push_back(v); + unreach.push_back(NFAVertex(v)); } } return unreach; @@ -656,7 +653,7 @@ findHighlanderSquashers(const NGHolder &g, const ReportManager &rm) { const u32 numStates = num_vertices(g); for (auto v : verts) { - DEBUG_PRINTF("vertex %u with %zu reports\n", g[v].index, + DEBUG_PRINTF("vertex %zu with %zu reports\n", g[v].index, g[v].reports.size()); // Find the set of vertices that lead to v or any other reporter with a @@ -683,7 +680,7 @@ findHighlanderSquashers(const NGHolder &g, const ReportManager &rm) { NFAStateSet &mask = squash[v]; for (auto uv : unreach) { - DEBUG_PRINTF("squashes index %u\n", h[uv].index); + DEBUG_PRINTF("squashes index %zu\n", h[uv].index); mask.reset(h[uv].index); } } diff --git a/src/nfagraph/ng_uncalc_components.cpp b/src/nfagraph/ng_uncalc_components.cpp index 3326d6f4..baab3b0f 100644 --- a/src/nfagraph/ng_uncalc_components.cpp +++ b/src/nfagraph/ng_uncalc_components.cpp @@ -259,7 +259,7 @@ void mergeNfaComponent(NGHolder &dest, const NGHolder &vic, size_t common_len) { vmap[vic.startDs] = dest.startDs; vmap[vic.accept] = dest.accept; vmap[vic.acceptEod] = dest.acceptEod; - vmap[nullptr] = nullptr; + vmap[NGHolder::null_vertex()] = NGHolder::null_vertex(); // For vertices in the common len, add to vmap and merge in the reports, if // any. @@ -312,7 +312,7 @@ void mergeNfaComponent(NGHolder &dest, const NGHolder &vic, size_t common_len) { in_common_region = true; } - DEBUG_PRINTF("adding idx=%u (state %u) -> idx=%u (state %u)%s\n", + DEBUG_PRINTF("adding idx=%zu (state %u) -> idx=%zu (state %u)%s\n", dest[u].index, dest_info.get(u), dest[v].index, dest_info.get(v), in_common_region ? " [common]" : ""); @@ -338,8 +338,8 @@ void mergeNfaComponent(NGHolder &dest, const NGHolder &vic, size_t common_len) { add_edge(u, v, vic[e], dest); } - dest.renumberEdges(); - dest.renumberVertices(); + renumber_edges(dest); + renumber_vertices(dest); } namespace { diff --git a/src/nfagraph/ng_uncalc_components.h b/src/nfagraph/ng_uncalc_components.h index ddab8825..d7883578 100644 --- a/src/nfagraph/ng_uncalc_components.h +++ b/src/nfagraph/ng_uncalc_components.h @@ -36,14 +36,13 @@ #include #include -#include "nfagraph/ng_graph.h" +#include "nfagraph/ng_holder.h" #include "util/ue2_containers.h" namespace ue2 { struct CompileContext; struct Grey; -class NGHolder; class ReportManager; /** diff --git a/src/nfagraph/ng_undirected.h b/src/nfagraph/ng_undirected.h index 12632e05..7df6c7dc 100644 --- a/src/nfagraph/ng_undirected.h +++ b/src/nfagraph/ng_undirected.h @@ -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 * modification, are permitted provided that the following conditions are met: @@ -39,6 +39,10 @@ #include "util/graph_range.h" #include "util/ue2_containers.h" +#include + +#include + namespace ue2 { /** @@ -51,7 +55,7 @@ namespace ue2 { typedef boost::adjacency_list > + boost::property > NFAUndirectedGraph; typedef NFAUndirectedGraph::vertex_descriptor NFAUndirectedVertex; @@ -60,16 +64,18 @@ typedef NFAUndirectedGraph::vertex_descriptor NFAUndirectedVertex; * Make a copy of an NFAGraph with undirected edges, optionally without start * vertices. Mappings from the original graph to the new one are provided. * - * Note that new vertex indices are assigned contiguously in \a vertices(g) order. + * Note that new vertex indices are assigned contiguously in \a vertices(g) + * order. */ template void createUnGraph(const GraphT &g, - bool excludeStarts, - bool excludeAccepts, - NFAUndirectedGraph &ug, - ue2::unordered_map &old2new, - ue2::unordered_map &newIdx2old) { - u32 idx = 0; + bool excludeStarts, + bool excludeAccepts, + NFAUndirectedGraph &ug, + ue2::unordered_map &old2new) { + size_t idx = 0; + typedef typename GraphT::vertex_descriptor VertexT; for (auto v : ue2::vertices_range(g)) { // skip all accept nodes @@ -84,13 +90,12 @@ void createUnGraph(const GraphT &g, NFAUndirectedVertex nuv = boost::add_vertex(ug); old2new[v] = nuv; - newIdx2old[idx] = v; boost::put(boost::vertex_index, ug, nuv, idx++); } for (const auto &e : ue2::edges_range(g)) { - NFAVertex src = source(e, g); - NFAVertex targ = target(e, g); + VertexT src = source(e, g); + VertexT targ = target(e, g); if ((excludeAccepts && is_any_accept(src, g)) || (excludeStarts && is_any_start(src, g))) { diff --git a/src/nfagraph/ng_utf8.cpp b/src/nfagraph/ng_utf8.cpp index 352359f2..383aa142 100644 --- a/src/nfagraph/ng_utf8.cpp +++ b/src/nfagraph/ng_utf8.cpp @@ -176,7 +176,7 @@ void findSeeds(const NGHolder &h, const bool som, vector *seeds) { continue; } - DEBUG_PRINTF("%u is a seed\n", h[v].index); + DEBUG_PRINTF("%zu is a seed\n", h[v].index); seeds->push_back(v); already_seeds.insert(v); } @@ -184,7 +184,7 @@ void findSeeds(const NGHolder &h, const bool som, vector *seeds) { static bool expandCyclic(NGHolder &h, NFAVertex v) { - DEBUG_PRINTF("inspecting %u\n", h[v].index); + DEBUG_PRINTF("inspecting %zu\n", h[v].index); bool changes = false; auto v_preds = preds(v, h); @@ -201,7 +201,7 @@ bool expandCyclic(NGHolder &h, NFAVertex v) { auto a_preds = preds(a, h); if (a_preds == v_preds && isutf8start(h[a].char_reach)) { - DEBUG_PRINTF("%u is a start v\n", h[a].index); + DEBUG_PRINTF("%zu is a start v\n", h[a].index); start_siblings.insert(a); } } @@ -212,7 +212,7 @@ bool expandCyclic(NGHolder &h, NFAVertex v) { auto a_succs = succs(a, h); if (a_succs == v_succs && h[a].char_reach == UTF_CONT_CR) { - DEBUG_PRINTF("%u is a full tail cont\n", h[a].index); + DEBUG_PRINTF("%zu is a full tail cont\n", h[a].index); end_siblings.insert(a); } } @@ -226,7 +226,7 @@ bool expandCyclic(NGHolder &h, NFAVertex v) { if (cr.isSubsetOf(UTF_TWO_START_CR)) { if (end_siblings.find(*adjacent_vertices(s, h).first) == end_siblings.end()) { - DEBUG_PRINTF("%u is odd\n", h[s].index); + DEBUG_PRINTF("%zu is odd\n", h[s].index); continue; } } else if (cr.isSubsetOf(UTF_THREE_START_CR)) { @@ -238,7 +238,7 @@ bool expandCyclic(NGHolder &h, NFAVertex v) { } if (end_siblings.find(*adjacent_vertices(m, h).first) == end_siblings.end()) { - DEBUG_PRINTF("%u is odd\n", h[s].index); + DEBUG_PRINTF("%zu is odd\n", h[s].index); continue; } } else if (cr.isSubsetOf(UTF_FOUR_START_CR)) { @@ -258,11 +258,11 @@ bool expandCyclic(NGHolder &h, NFAVertex v) { if (end_siblings.find(*adjacent_vertices(m2, h).first) == end_siblings.end()) { - DEBUG_PRINTF("%u is odd\n", h[s].index); + DEBUG_PRINTF("%zu is odd\n", h[s].index); continue; } } else { - DEBUG_PRINTF("%u is bad\n", h[s].index); + DEBUG_PRINTF("%zu is bad\n", h[s].index); continue; } diff --git a/src/nfagraph/ng_util.cpp b/src/nfagraph/ng_util.cpp index de4ca656..ad40debe 100644 --- a/src/nfagraph/ng_util.cpp +++ b/src/nfagraph/ng_util.cpp @@ -52,7 +52,7 @@ using namespace std; using boost::default_color_type; -using boost::filtered_graph; +using boost::make_filtered_graph; using boost::make_assoc_property_map; using boost::adaptors::map_values; @@ -172,15 +172,14 @@ namespace { struct CycleFound {}; struct DetectCycles : public boost::default_dfs_visitor { explicit DetectCycles(const NGHolder &g) : startDs(g.startDs) {} - void back_edge(const NFAEdge &e, const NFAGraph &g) const { + void back_edge(const NFAEdge &e, const NGHolder &g) const { NFAVertex u = source(e, g), v = target(e, g); // We ignore the startDs self-loop. if (u == startDs && v == startDs) { return; } // Any other back-edge indicates a cycle. - DEBUG_PRINTF("back edge %u->%u found\n", g[u].index, - g[v].index); + DEBUG_PRINTF("back edge %zu->%zu found\n", g[u].index, g[v].index); throw CycleFound(); } private: @@ -215,10 +214,8 @@ bool isFloating(const NGHolder &g) { bool isAcyclic(const NGHolder &g) { try { - depth_first_search( - g.g, visitor(DetectCycles(g)) - .root_vertex(g.start) - .vertex_index_map(get(&NFAGraphVertexProps::index, g.g))); + boost::depth_first_search(g, visitor(DetectCycles(g)) + .root_vertex(g.start)); } catch (const CycleFound &) { return false; } @@ -234,11 +231,11 @@ bool hasReachableCycle(const NGHolder &g, NFAVertex src) { try { // Use depth_first_visit, rather than depth_first_search, so that we // only search from src. - auto index_map = get(&NFAGraphVertexProps::index, g.g); - depth_first_visit( - g.g, src, DetectCycles(g), - make_iterator_property_map(colors.begin(), index_map)); - } catch (const CycleFound&) { + auto index_map = get(vertex_index, g); + boost::depth_first_visit(g, src, DetectCycles(g), + make_iterator_property_map(colors.begin(), + index_map)); + } catch (const CycleFound &) { return true; } @@ -249,10 +246,7 @@ bool hasBigCycles(const NGHolder &g) { assert(hasCorrectlyNumberedVertices(g)); set dead; BackEdges> backEdgeVisitor(dead); - depth_first_search( - g.g, visitor(backEdgeVisitor) - .root_vertex(g.start) - .vertex_index_map(get(&NFAGraphVertexProps::index, g.g))); + boost::depth_first_search(g, visitor(backEdgeVisitor).root_vertex(g.start)); for (const auto &e : dead) { if (source(e, g) != target(e, g)) { @@ -266,8 +260,7 @@ bool hasBigCycles(const NGHolder &g) { set findVerticesInCycles(const NGHolder &g) { map comp_map; - strong_components(g.g, make_assoc_property_map(comp_map), - vertex_index_map(get(&NFAGraphVertexProps::index, g.g))); + strong_components(g, make_assoc_property_map(comp_map)); map > comps; @@ -298,8 +291,7 @@ set findVerticesInCycles(const NGHolder &g) { bool can_never_match(const NGHolder &g) { assert(edge(g.accept, g.acceptEod, g).second); - if (!hasGreaterInDegree(0, g.accept, g) - && !hasGreaterInDegree(1, g.acceptEod, g)) { + if (in_degree(g.accept, g) == 0 && in_degree(g.acceptEod, g) == 1) { DEBUG_PRINTF("no paths into accept\n"); return true; } @@ -308,7 +300,7 @@ bool can_never_match(const NGHolder &g) { } bool can_match_at_eod(const NGHolder &h) { - if (hasGreaterInDegree(1, h.acceptEod, h)) { + if (in_degree(h.acceptEod, h) > 1) { DEBUG_PRINTF("more than one edge to acceptEod\n"); return true; } @@ -396,21 +388,17 @@ vector getTopoOrdering(const NGHolder &g) { EdgeSet backEdges; BackEdges be(backEdges); - auto index_map = get(&NFAGraphVertexProps::index, g.g); - depth_first_search(g.g, visitor(be) - .root_vertex(g.start) - .color_map(make_iterator_property_map( - colour.begin(), index_map)) - .vertex_index_map(index_map)); + auto index_map = get(vertex_index, g); + depth_first_search(g, visitor(be).root_vertex(g.start) + .color_map(make_iterator_property_map( + colour.begin(), index_map))); - auto acyclic_g = make_filtered_graph(g.g, make_bad_edge_filter(&backEdges)); + auto acyclic_g = make_filtered_graph(g, make_bad_edge_filter(&backEdges)); vector ordering; ordering.reserve(num_verts); - topological_sort( - acyclic_g, back_inserter(ordering), - color_map(make_iterator_property_map(colour.begin(), index_map)) - .vertex_index_map(index_map)); + topological_sort(acyclic_g, back_inserter(ordering), + color_map(make_iterator_property_map(colour.begin(), index_map))); reorderSpecials(g, ordering); @@ -434,12 +422,12 @@ void mustBeSetBefore_int(NFAVertex u, const NGHolder &g, } } - auto prefix = make_filtered_graph(g.g, make_bad_edge_filter(&dead)); + auto prefix = make_filtered_graph(g, make_bad_edge_filter(&dead)); depth_first_visit( prefix, g.start, make_dfs_visitor(boost::null_visitor()), make_iterator_property_map(vertexColor.begin(), - get(&NFAGraphVertexProps::index, g.g))); + get(vertex_index, g))); } bool mustBeSetBefore(NFAVertex u, NFAVertex v, const NGHolder &g, @@ -456,15 +444,14 @@ bool mustBeSetBefore(NFAVertex u, NFAVertex v, const NGHolder &g, mustBeSetBefore_int(u, g, vertexColor); for (auto vi : vertices_range(g)) { - auto key2 = make_pair(g[u].index, - g[vi].index); - DEBUG_PRINTF("adding %u %u\n", key2.first, key2.second); + auto key2 = make_pair(g[u].index, g[vi].index); + DEBUG_PRINTF("adding %zu %zu\n", key2.first, key2.second); assert(!contains(cache.cache, key2)); bool value = vertexColor[g[vi].index] == boost::white_color; cache.cache[key2] = value; assert(contains(cache.cache, key2)); } - DEBUG_PRINTF("cache miss %u %u (%zu)\n", key.first, key.second, + DEBUG_PRINTF("cache miss %zu %zu (%zu)\n", key.first, key.second, cache.cache.size()); return cache.cache[key]; } @@ -592,12 +579,13 @@ void fillHolder(NGHolder *outp, const NGHolder &in, const deque &vv, fillHolderOutEdges(out, in, v_map, u); } - out.renumberEdges(); - out.renumberVertices(); + renumber_edges(out); + renumber_vertices(out); } void cloneHolder(NGHolder &out, const NGHolder &in) { assert(hasCorrectlyNumberedVertices(in)); + assert(hasCorrectlyNumberedVertices(out)); out.kind = in.kind; // Note: depending on the state of the input graph, some stylized edges @@ -607,6 +595,7 @@ void cloneHolder(NGHolder &out, const NGHolder &in) { /* remove the existing special edges */ clear_vertex(out.startDs, out); clear_vertex(out.accept, out); + renumber_edges(out); vector out_mapping(num_vertices(in)); out_mapping[NODE_START] = out.start; @@ -642,8 +631,8 @@ void cloneHolder(NGHolder &out, const NGHolder &in) { } // Safety checks. - assert(num_vertices(in.g) == num_vertices(out.g)); - assert(num_edges(in.g) == num_edges(out.g)); + assert(num_vertices(in) == num_vertices(out)); + assert(num_edges(in) == num_edges(out)); assert(hasCorrectlyNumberedVertices(out)); } @@ -672,9 +661,8 @@ unique_ptr cloneHolder(const NGHolder &in) { void reverseHolder(const NGHolder &g_in, NGHolder &g) { // Make the BGL do the grunt work. ue2::unordered_map vertexMap; - boost::transpose_graph(g_in.g, g.g, - orig_to_copy(boost::make_assoc_property_map(vertexMap)). - vertex_index_map(get(&NFAGraphVertexProps::index, g_in.g))); + boost::transpose_graph(g_in, g, + orig_to_copy(boost::make_assoc_property_map(vertexMap))); // The transpose_graph operation will have created extra copies of our // specials. We have to rewire their neighbours to the 'real' specials and @@ -716,8 +704,8 @@ void reverseHolder(const NGHolder &g_in, NGHolder &g) { // Renumber so that g's properties (number of vertices, edges) are // accurate. - g.renumberVertices(); - g.renumberEdges(); + renumber_vertices(g); + renumber_edges(g); assert(num_vertices(g) == num_vertices(g_in)); assert(num_edges(g) == num_edges(g_in)); @@ -729,8 +717,7 @@ bool allMatchStatesHaveReports(const NGHolder &g) { unordered_set reporters; for (auto v : inv_adjacent_vertices_range(g.accept, g)) { if (g[v].reports.empty()) { - DEBUG_PRINTF("vertex %u has no reports!\n", - g[v].index); + DEBUG_PRINTF("vertex %zu has no reports!\n", g[v].index); return false; } reporters.insert(v); @@ -741,8 +728,7 @@ bool allMatchStatesHaveReports(const NGHolder &g) { continue; // stylised edge } if (g[v].reports.empty()) { - DEBUG_PRINTF("vertex %u has no reports!\n", - g[v].index); + DEBUG_PRINTF("vertex %zu has no reports!\n", g[v].index); return false; } reporters.insert(v); @@ -750,7 +736,7 @@ bool allMatchStatesHaveReports(const NGHolder &g) { 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", + DEBUG_PRINTF("vertex %zu is not a match state, but has reports!\n", g[v].index); return false; } @@ -759,34 +745,6 @@ bool allMatchStatesHaveReports(const NGHolder &g) { return true; } -bool hasCorrectlyNumberedVertices(const NGHolder &g) { - size_t count = num_vertices(g); - vector ids(count, false); - for (auto v : vertices_range(g)) { - u32 id = g[v].index; - if (id >= count || ids[id]) { - return false; // duplicate - } - ids[id] = true; - } - return find(ids.begin(), ids.end(), false) == ids.end() - && num_vertices(g) == num_vertices(g.g); -} - -bool hasCorrectlyNumberedEdges(const NGHolder &g) { - size_t count = num_edges(g); - vector ids(count, false); - for (const auto &e : edges_range(g)) { - u32 id = g[e].index; - if (id >= count || ids[id]) { - return false; // duplicate - } - ids[id] = true; - } - return find(ids.begin(), ids.end(), false) == ids.end() - && num_edges(g) == num_edges(g.g); -} - bool isCorrectlyTopped(const NGHolder &g) { if (is_triggered(g)) { for (const auto &e : out_edges_range(g.start, g)) { @@ -805,7 +763,6 @@ bool isCorrectlyTopped(const NGHolder &g) { return true; } - #endif // NDEBUG } // namespace ue2 diff --git a/src/nfagraph/ng_util.h b/src/nfagraph/ng_util.h index 6b5090ce..a0752533 100644 --- a/src/nfagraph/ng_util.h +++ b/src/nfagraph/ng_util.h @@ -65,9 +65,8 @@ bool is_dot(NFAVertex v, const GraphT &g) { template static really_inline void succ(const NGHolder &g, NFAVertex v, U *s) { - NGHolder::adjacency_iterator ai, ae; - tie(ai, ae) = adjacent_vertices(v, g); - s->insert(ai, ae); + auto rv = adjacent_vertices(v, g); + s->insert(rv.first, rv.second); } template> @@ -81,9 +80,8 @@ ContTemp succs(NFAVertex u, const NGHolder &g) { template static really_inline void pred(const NGHolder &g, NFAVertex v, U *p) { - NGHolder::inv_adjacency_iterator it, ite; - tie(it, ite) = inv_adjacent_vertices(v, g); - p->insert(it, ite); + auto rv = inv_adjacent_vertices(v, g); + p->insert(rv.first, rv.second); } template> @@ -138,42 +136,11 @@ public: BackEdgeSet &backEdges; }; -/** - * Generic code to renumber all the vertices in a graph. Assumes that we're - * using a vertex_index property of type u32, and that we always have - * N_SPECIALS special vertices already present (which we don't want to - * renumber). - */ -template -static really_inline -size_t renumberGraphVertices(GraphT &g) { - size_t num = N_SPECIALS; - for (const auto &v : vertices_range(g)) { - if (!is_special(v, g)) { - g[v].index = num++; - assert(num > 0); // no wrapping - } - } - return num; -} - -/** Renumber all the edges in a graph. */ -template -static really_inline -size_t renumberGraphEdges(GraphT &g) { - size_t num = 0; - for (const auto &e : edges_range(g)) { - g[e].index = num++; - assert(num > 0); // no wrapping - } - return num; -} - /** Returns true if the vertex is either of the real starts (NODE_START, * NODE_START_DOTSTAR). */ template static really_inline -bool is_any_start(const NFAVertex v, const GraphT &g) { +bool is_any_start(typename GraphT::vertex_descriptor v, const GraphT &g) { u32 i = g[v].index; return i == NODE_START || i == NODE_START_DOTSTAR; } @@ -181,16 +148,14 @@ bool is_any_start(const NFAVertex v, const GraphT &g) { bool is_virtual_start(NFAVertex v, const NGHolder &g); template -static really_inline -bool is_any_accept(const NFAVertex v, const GraphT &g) { +bool is_any_accept(typename GraphT::vertex_descriptor v, const GraphT &g) { u32 i = g[v].index; return i == NODE_ACCEPT || i == NODE_ACCEPT_EOD; } /** returns true iff v has an edge to accept or acceptEod */ template -static really_inline -bool is_match_vertex(NFAVertex v, const GraphT &g) { +bool is_match_vertex(typename GraphT::vertex_descriptor v, const GraphT &g) { return edge(v, g.accept, g).second || edge(v, g.acceptEod, g).second; } @@ -202,25 +167,6 @@ bool is_match_vertex(NFAVertex v, const GraphT &g) { */ std::vector getTopoOrdering(const NGHolder &g); -/** Comparison functor used to sort by vertex_index. */ -template -struct VertexIndexOrdering { - VertexIndexOrdering(const Graph &g_in) : g(&g_in) {} - bool operator()(typename Graph::vertex_descriptor a, - typename Graph::vertex_descriptor b) const { - assert(a == b || (*g)[a].index != (*g)[b].index); - return (*g)[a].index < (*g)[b].index; - } -private: - const Graph *g; -}; - -template -static -VertexIndexOrdering make_index_ordering(const Graph &g) { - return VertexIndexOrdering(g); -} - bool onlyOneTop(const NGHolder &g); /** Return the set of the tops on the given graph. */ @@ -340,18 +286,6 @@ void reverseHolder(const NGHolder &g, NGHolder &out); */ 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); - -/** - * Assertion: returns true if the edges in this graph are contiguously (and - * uniquely) numbered from zero. - */ -bool hasCorrectlyNumberedEdges(const NGHolder &g); - /** * Assertion: returns true if the graph is triggered and all edges out of start * have tops OR if the graph is not-triggered and all edges out of start have no diff --git a/src/nfagraph/ng_violet.cpp b/src/nfagraph/ng_violet.cpp index 9c99ba8a..9e50ea3d 100644 --- a/src/nfagraph/ng_violet.cpp +++ b/src/nfagraph/ng_violet.cpp @@ -464,7 +464,7 @@ void getRegionRoseLiterals(const NGHolder &g, bool seeking_anchored, DEBUG_PRINTF("inspecting region %u\n", region); set s; for (auto v : vv) { - DEBUG_PRINTF(" exit vertex: %u\n", g[v].index); + DEBUG_PRINTF(" exit vertex: %zu\n", g[v].index); /* Note: RHS can not be depended on to take all subsequent revisits * to this vertex */ set ss = getLiteralSet(g, v, false); @@ -669,7 +669,7 @@ unique_ptr findBestSplit(const NGHolder &g, lits.pop_back(); } - DEBUG_PRINTF("best is '%s' %u a%d t%d\n", + DEBUG_PRINTF("best is '%s' %zu a%d t%d\n", dumpString(*best->lit.begin()).c_str(), g[best->vv.front()].index, depths ? (int)createsAnchoredLHS(g, best->vv, *depths, cc.grey) : 0, @@ -777,7 +777,7 @@ set poisonVertices(const NGHolder &h, const RoseInGraph &vg, set bad_vertices; for (const NFAEdge &e : bad_edges) { bad_vertices.insert(target(e, h)); - DEBUG_PRINTF("bad: %u->%u\n", h[source(e, h)].index, + DEBUG_PRINTF("bad: %zu->%zu\n", h[source(e, h)].index, h[target(e, h)].index); } @@ -1144,7 +1144,7 @@ void splitEdgesByCut(NGHolder &h, RoseInGraph &vg, NFAVertex prev_v = source(e, h); NFAVertex pivot = target(e, h); - DEBUG_PRINTF("splitting on pivot %u\n", h[pivot].index); + DEBUG_PRINTF("splitting on pivot %zu\n", h[pivot].index); ue2::unordered_map temp_map; shared_ptr new_lhs = make_shared(); splitLHS(h, pivot, new_lhs.get(), &temp_map); @@ -1324,7 +1324,7 @@ bool deanchorIfNeeded(NGHolder &g) { succ_g.erase(g.startDs); for (auto v : adjacent_vertices_range(g.start, g)) { - DEBUG_PRINTF("inspecting cand %u || = %zu\n", g[v].index, + DEBUG_PRINTF("inspecting cand %zu || = %zu\n", g[v].index, g[v].char_reach.count()); if (v == g.startDs || !g[v].char_reach.all()) { @@ -2339,7 +2339,7 @@ bool leadingDotStartLiteral(const NGHolder &h, VertLitInfo *out) { make_nocase(&lit); } - DEBUG_PRINTF("%u found %s\n", h[v].index, dumpString(lit).c_str()); + DEBUG_PRINTF("%zu found %s\n", h[v].index, dumpString(lit).c_str()); out->vv = {v}; out->lit = {lit}; return true; @@ -2468,7 +2468,7 @@ bool trailingDotStarLiteral(const NGHolder &h, VertLitInfo *out) { } ue2_literal lit = reverse_literal(rv.second); - DEBUG_PRINTF("%u found %s\n", h[v].index, dumpString(lit).c_str()); + DEBUG_PRINTF("%zu found %s\n", h[v].index, dumpString(lit).c_str()); if (bad_mixed_sensitivity(lit)) { make_nocase(&lit); @@ -2672,6 +2672,7 @@ bool doViolet(RoseBuild &rose, const NGHolder &h, bool prefilter, pruneUseless(vg); dumpPreRoseGraph(vg, cc.grey); + renumber_vertices(vg); calcVertexOffsets(vg); bool rv = rose.addRose(vg, prefilter); DEBUG_PRINTF("violet: %s\n", rv ? "success" : "fail"); diff --git a/src/nfagraph/ng_width.cpp b/src/nfagraph/ng_width.cpp index 5fb58ee4..d596b7b5 100644 --- a/src/nfagraph/ng_width.cpp +++ b/src/nfagraph/ng_width.cpp @@ -58,18 +58,18 @@ namespace { struct SpecialEdgeFilter { SpecialEdgeFilter() {} explicit SpecialEdgeFilter(const NGHolder &h_in) : h(&h_in) {} - explicit SpecialEdgeFilter(const NGHolder &h_in, u32 top_in) + SpecialEdgeFilter(const NGHolder &h_in, u32 top_in) : h(&h_in), single_top(true), top(top_in) {} bool operator()(const NFAEdge &e) const { - const NFAGraph &g = h->g; - NFAVertex u = source(e, g), v = target(e, g); - if ((is_any_start(u, g) && is_any_start(v, g)) || - (is_any_accept(u, g) && is_any_accept(v, g))) { + NFAVertex u = source(e, *h); + NFAVertex v = target(e, *h); + if ((is_any_start(u, *h) && is_any_start(v, *h)) || + (is_any_accept(u, *h) && is_any_accept(v, *h))) { return false; } if (single_top) { - if (u == h->start && !contains(g[e].tops, top)) { + if (u == h->start && !contains((*h)[e].tops, top)) { return false; } if (u == h->startDs) { @@ -94,7 +94,7 @@ depth findMinWidth(const NGHolder &h, const SpecialEdgeFilter &filter, return depth::unreachable(); } - boost::filtered_graph g(h.g, filter); + boost::filtered_graph g(h, filter); assert(hasCorrectlyNumberedVertices(h)); const size_t num = num_vertices(h); @@ -106,11 +106,10 @@ depth findMinWidth(const NGHolder &h, const SpecialEdgeFilter &filter, // Since we are interested in the single-source shortest paths on a graph // with the same weight on every edge, using BFS will be faster than // Dijkstra here. - breadth_first_search( - g, src, + breadth_first_search(g, src, visitor(make_bfs_visitor(record_distances( make_iterator_property_map(distance.begin(), index_map), - boost::on_tree_edge()))).vertex_index_map(index_map)); + boost::on_tree_edge())))); DEBUG_PRINTF("d[accept]=%s, d[acceptEod]=%s\n", distance.at(NODE_ACCEPT).str().c_str(), @@ -130,7 +129,7 @@ depth findMinWidth(const NGHolder &h, const SpecialEdgeFilter &filter, static depth findMaxWidth(const NGHolder &h, const SpecialEdgeFilter &filter, NFAVertex src) { - if (isLeafNode(src, h.g)) { + if (isLeafNode(src, h)) { return depth::unreachable(); } @@ -139,7 +138,7 @@ depth findMaxWidth(const NGHolder &h, const SpecialEdgeFilter &filter, return depth::infinity(); } - boost::filtered_graph g(h.g, filter); + boost::filtered_graph g(h, filter); assert(hasCorrectlyNumberedVertices(h)); const size_t num = num_vertices(h); @@ -149,11 +148,9 @@ depth findMaxWidth(const NGHolder &h, const SpecialEdgeFilter &filter, auto index_map = get(&NFAGraphVertexProps::index, g); // DAG shortest paths with negative edge weights. - dag_shortest_paths( - g, src, + dag_shortest_paths(g, src, distance_map(make_iterator_property_map(distance.begin(), index_map)) .weight_map(boost::make_constant_property(-1)) - .vertex_index_map(index_map) .color_map(make_iterator_property_map(colors.begin(), index_map))); depth acceptDepth, acceptEodDepth; diff --git a/src/rose/rose_build_add.cpp b/src/rose/rose_build_add.cpp index 72a791ba..e185bb37 100644 --- a/src/rose/rose_build_add.cpp +++ b/src/rose/rose_build_add.cpp @@ -112,11 +112,10 @@ RoseVertex createVertex(RoseBuildImpl *build, u32 literalId, u32 min_offset, RoseGraph &g = build->g; // add to tree RoseVertex v = add_vertex(g); - g[v].idx = build->vertexIndex++; g[v].min_offset = min_offset; g[v].max_offset = max_offset; - DEBUG_PRINTF("insert vertex %zu into literal %u's vertex set\n", g[v].idx, + DEBUG_PRINTF("insert vertex %zu into literal %u's vertex set\n", g[v].index, literalId); g[v].literals.insert(literalId); build->literal_info[literalId].vertices.insert(v); @@ -167,7 +166,7 @@ RoseVertex createAnchoredVertex(RoseBuildImpl *build, u32 literalId, RoseGraph &g = build->g; RoseVertex v = createVertex(build, literalId, min_offset, max_offset); - DEBUG_PRINTF("created anchored vertex %zu with lit id %u\n", g[v].idx, + DEBUG_PRINTF("created anchored vertex %zu with lit id %u\n", g[v].index, literalId); RoseEdge e = add_edge(build->anchored_root, v, g).first; @@ -181,8 +180,7 @@ static RoseVertex duplicate(RoseBuildImpl *build, RoseVertex v) { RoseGraph &g = build->g; RoseVertex w = add_vertex(g[v], g); - g[w].idx = build->vertexIndex++; - DEBUG_PRINTF("added vertex %zu\n", g[w].idx); + DEBUG_PRINTF("added vertex %zu\n", g[w].index); for (auto lit_id : g[w].literals) { build->literal_info[lit_id].vertices.insert(w); @@ -191,7 +189,7 @@ RoseVertex duplicate(RoseBuildImpl *build, RoseVertex v) { for (const auto &e : in_edges_range(v, g)) { RoseVertex s = source(e, g); add_edge(s, w, g[e], g); - DEBUG_PRINTF("added edge (%zu,%zu)\n", g[s].idx, g[w].idx); + DEBUG_PRINTF("added edge (%zu,%zu)\n", g[s].index, g[w].index); } return w; @@ -227,7 +225,7 @@ RoseRoleHistory selectHistory(const RoseBuildImpl &tbi, const RoseBuildData &bd, const bool has_bounds = g[e].minBound || (g[e].maxBound != ROSE_BOUND_INF); DEBUG_PRINTF("edge %zu->%zu, bounds=[%u,%u], fixed_u=%d, prefix=%d\n", - g[u].idx, g[v].idx, g[e].minBound, g[e].maxBound, + g[u].index, g[v].index, g[e].minBound, g[e].maxBound, (int)g[u].fixedOffset(), (int)g[v].left); if (g[v].left) { @@ -309,7 +307,7 @@ void createVertices(RoseBuildImpl *tbi, DEBUG_PRINTF("set som_adjust to %u\n", g[w].som_adjust); } - DEBUG_PRINTF(" adding new vertex idx=%zu\n", tbi->g[w].idx); + DEBUG_PRINTF(" adding new vertex index=%zu\n", tbi->g[w].index); vertex_map[iv].push_back(w); } else { w = created[key]; @@ -383,7 +381,7 @@ void removeFalsePaths(NGHolder &g, const ue2_literal &lit) { for (auto it = lit.rbegin(), ite = lit.rend(); it != ite; ++it) { next.clear(); for (auto curr_v : curr) { - DEBUG_PRINTF("handling %u\n", g[curr_v].index); + DEBUG_PRINTF("handling %zu\n", g[curr_v].index); vector next_cand; insert(&next_cand, next_cand.end(), inv_adjacent_vertices(curr_v, g)); @@ -401,7 +399,7 @@ void removeFalsePaths(NGHolder &g, const ue2_literal &lit) { const CharReach &cr = g[v].char_reach; if (!overlaps(*it, cr)) { - DEBUG_PRINTF("false edge %u\n", g[v].index); + DEBUG_PRINTF("false edge %zu\n", g[v].index); continue; } @@ -409,7 +407,7 @@ void removeFalsePaths(NGHolder &g, const ue2_literal &lit) { clone_in_edges(g, v, v2); add_edge(v2, curr_v, g); g[v2].char_reach &= *it; - DEBUG_PRINTF("next <- %u\n", g[v2].index); + DEBUG_PRINTF("next <- %zu\n", g[v2].index); next.insert(v2); } } @@ -557,7 +555,7 @@ void findRoseLiteralMask(const NGHolder &h, const u32 lag, vector &msk, next.clear(); CharReach cr; for (auto v : curr) { - DEBUG_PRINTF("vertex %u, reach %s\n", h[v].index, + DEBUG_PRINTF("vertex %zu, reach %s\n", h[v].index, describeClass(h[v].char_reach).c_str()); cr |= h[v].char_reach; insert(&next, inv_adjacent_vertices(v, h)); @@ -705,7 +703,6 @@ void makeEodEventLeftfix(RoseBuildImpl &build, RoseVertex u, for (const auto &report_mapping : report_remap) { RoseVertex v = add_vertex(g); - g[v].idx = build.vertexIndex++; g[v].literals.insert(eod_event); build.literal_info[eod_event].vertices.insert(v); @@ -728,7 +725,6 @@ void makeEodEventLeftfix(RoseBuildImpl &build, RoseVertex u, g[e1].history = ROSE_ROLE_HISTORY_NONE; // handled by prefix RoseVertex w = add_vertex(g); - g[w].idx = build.vertexIndex++; g[w].eod_accept = true; g[w].reports = report_mapping.first; g[w].min_offset = g[v].min_offset; @@ -737,7 +733,7 @@ void makeEodEventLeftfix(RoseBuildImpl &build, RoseVertex u, g[e].minBound = 0; g[e].maxBound = 0; g[e].history = ROSE_ROLE_HISTORY_LAST_BYTE; - DEBUG_PRINTF("accept eod vertex (idx=%zu)\n", g[w].idx); + DEBUG_PRINTF("accept eod vertex (index=%zu)\n", g[w].index); } } @@ -769,7 +765,7 @@ void doRoseAcceptVertex(RoseBuildImpl *tbi, || (ig[iv].type == RIV_ACCEPT_EOD && out_degree(u, g) && !edge_props.graph) || (!isLeafNode(u, g) && !tbi->isAnyStart(u))) { - DEBUG_PRINTF("duplicating for parent %zu\n", g[u].idx); + DEBUG_PRINTF("duplicating for parent %zu\n", g[u].index); assert(!tbi->isAnyStart(u)); u = duplicate(tbi, u); g[u].suffix.reset(); @@ -780,20 +776,20 @@ void doRoseAcceptVertex(RoseBuildImpl *tbi, if (ig[iv].type == RIV_ACCEPT) { assert(!tbi->isAnyStart(u)); if (contains(bd.early_dfas, edge_props.graph.get())) { - DEBUG_PRINTF("adding early dfa suffix to i%zu\n", g[u].idx); + DEBUG_PRINTF("adding early dfa suffix to i%zu\n", g[u].index); g[u].suffix.rdfa = bd.early_dfas.at(edge_props.graph.get()); g[u].suffix.dfa_min_width = findMinWidth(*edge_props.graph); g[u].suffix.dfa_max_width = findMaxWidth(*edge_props.graph); } else if (edge_props.graph) { - DEBUG_PRINTF("adding suffix to i%zu\n", g[u].idx); + DEBUG_PRINTF("adding suffix to i%zu\n", g[u].index); g[u].suffix.graph = edge_props.graph; assert(g[u].suffix.graph->kind == NFA_SUFFIX); /* TODO: set dfa_(min|max)_width */ } else if (edge_props.haig) { - DEBUG_PRINTF("adding suffaig to i%zu\n", g[u].idx); + DEBUG_PRINTF("adding suffaig to i%zu\n", g[u].index); g[u].suffix.haig = edge_props.haig; } else { - DEBUG_PRINTF("adding boring accept to i%zu\n", g[u].idx); + DEBUG_PRINTF("adding boring accept to i%zu\n", g[u].index); assert(!g[u].eod_accept); g[u].reports = ig[iv].reports; } @@ -803,7 +799,6 @@ void doRoseAcceptVertex(RoseBuildImpl *tbi, if (!edge_props.graph) { RoseVertex w = add_vertex(g); - g[w].idx = tbi->vertexIndex++; g[w].eod_accept = true; g[w].reports = ig[iv].reports; g[w].min_offset = g[u].min_offset; @@ -812,7 +807,7 @@ void doRoseAcceptVertex(RoseBuildImpl *tbi, g[e].minBound = 0; g[e].maxBound = 0; g[e].history = ROSE_ROLE_HISTORY_LAST_BYTE; - DEBUG_PRINTF("accept eod vertex (idx=%zu)\n", g[w].idx); + DEBUG_PRINTF("accept eod vertex (index=%zu)\n", g[w].index); continue; } @@ -824,7 +819,7 @@ void doRoseAcceptVertex(RoseBuildImpl *tbi, assert(h.kind == NFA_SUFFIX); assert(!tbi->isAnyStart(u)); /* etable can't/shouldn't use eod event */ - DEBUG_PRINTF("adding suffix to i%zu\n", g[u].idx); + DEBUG_PRINTF("adding suffix to i%zu\n", g[u].index); g[u].suffix.graph = edge_props.graph; continue; } @@ -976,7 +971,7 @@ void populateRoseGraph(RoseBuildImpl *tbi, RoseBuildData &bd) { || ig[v_order.front()].type == RIV_ANCHORED_START); for (RoseInVertex iv : v_order) { - DEBUG_PRINTF("vertex %p\n", iv); + DEBUG_PRINTF("vertex %zu\n", ig[iv].index); if (ig[iv].type == RIV_START) { DEBUG_PRINTF("is root\n"); @@ -1588,6 +1583,7 @@ bool RoseBuildImpl::addRose(const RoseInGraph &ig, bool prefilter, bool finalChance) { DEBUG_PRINTF("trying to rose\n"); assert(validateKinds(ig)); + assert(hasCorrectlyNumberedVertices(ig)); if (::ue2::empty(ig)) { assert(0); @@ -1603,7 +1599,8 @@ bool RoseBuildImpl::addRose(const RoseInGraph &ig, bool prefilter, transformAnchoredLiteralOverlap(in, bd, cc); transformSuffixDelay(in, cc); - assert(validateKinds(ig)); + renumber_vertices(in); + assert(validateKinds(in)); map > graphs; vector ordered_graphs; // Stored in first-encounter order. @@ -1762,8 +1759,7 @@ static u32 findMaxBAWidth(const NGHolder &h) { // Must be bi-anchored: no out-edges from startDs (other than its // self-loop), no in-edges to accept. - if (hasGreaterOutDegree(1, h.startDs, h) || - hasGreaterInDegree(0, h.accept, h)) { + if (out_degree(h.startDs, h) > 1 || in_degree(h.accept, h)) { return ROSE_BOUND_INF; } depth d = findMaxWidth(h); @@ -1889,9 +1885,9 @@ bool prepAcceptForAddAnchoredNFA(RoseBuildImpl &tbi, const NGHolder &w, map &allocated_reports, flat_set &added_lit_ids) { const depth max_anchored_depth(tbi.cc.grey.maxAnchoredRegion); - const u32 idx = w[u].index; - assert(idx < vertexDepths.size()); - const DepthMinMax &d = vertexDepths.at(idx); + const size_t index = w[u].index; + assert(index < vertexDepths.size()); + const DepthMinMax &d = vertexDepths.at(index); for (const auto &int_report : w[u].reports) { assert(int_report != MO_INVALID_IDX); @@ -2008,7 +2004,6 @@ bool RoseBuildImpl::addAnchoredAcyclic(const NGHolder &h) { RoseVertex v = createAnchoredVertex(this, lit_id, minBound, maxBound); RoseVertex eod = add_vertex(g); - g[eod].idx = vertexIndex++; g[eod].eod_accept = true; g[eod].reports.insert(report); g[eod].min_offset = g[v].min_offset; diff --git a/src/rose/rose_build_add_mask.cpp b/src/rose/rose_build_add_mask.cpp index ef83cae1..f46e1004 100644 --- a/src/rose/rose_build_add_mask.cpp +++ b/src/rose/rose_build_add_mask.cpp @@ -532,7 +532,7 @@ void addTransientMask(RoseBuildImpl &build, const vector &mask, g[v].left.leftfix_report = mask_report; } else { // Make sure our edge bounds are correct. - auto e = edge_by_target(parent, v, g).first; + auto e = edge(parent, v, g).first; g[e].minBound = 0; g[e].maxBound = anchored ? 0 : ROSE_BOUND_INF; g[e].history = anchored ? ROSE_ROLE_HISTORY_ANCH diff --git a/src/rose/rose_build_anchored.cpp b/src/rose/rose_build_anchored.cpp index 60732ff9..3d0affc6 100644 --- a/src/rose/rose_build_anchored.cpp +++ b/src/rose/rose_build_anchored.cpp @@ -549,7 +549,7 @@ bool isSimple(const NGHolder &h, u32 *min_bound, u32 *max_bound, /* lit should only be connected to dot vertices */ for (auto u : inv_adjacent_vertices_range(lit_head, h)) { - DEBUG_PRINTF("checking %u\n", h[u].index); + DEBUG_PRINTF("checking %zu\n", h[u].index); if (!h[u].char_reach.all()) { return false; } diff --git a/src/rose/rose_build_bytecode.cpp b/src/rose/rose_build_bytecode.cpp index 80e6450d..43df7962 100644 --- a/src/rose/rose_build_bytecode.cpp +++ b/src/rose/rose_build_bytecode.cpp @@ -314,7 +314,7 @@ bool needsCatchup(const RoseBuildImpl &build, continue; } if (g[v].suffix) { - DEBUG_PRINTF("vertex %zu has suffix\n", g[v].idx); + DEBUG_PRINTF("vertex %zu has suffix\n", g[v].index); return true; } @@ -947,7 +947,7 @@ void appendTailToHolder(NGHolder &h, const vector &tail) { appendTailToHolder(h, e.first, e.second, tail); } - h.renumberEdges(); + renumber_edges(h); } static @@ -1232,11 +1232,11 @@ void updateTops(const RoseGraph &g, const TamaInfo &tamaInfo, for (const auto &n : tamaInfo.subengines) { for (const auto &v : subengines[i].vertices) { if (is_suffix) { - tamaProto.add(n, g[v].idx, g[v].suffix.top, + tamaProto.add(n, g[v].index, g[v].suffix.top, out_top_remap); } else { for (const auto &e : in_edges_range(v, g)) { - tamaProto.add(n, g[v].idx, g[e].rose_top, + tamaProto.add(n, g[v].index, g[e].rose_top, out_top_remap); } } @@ -1280,7 +1280,7 @@ void buildInfixContainer(RoseGraph &g, build_context &bc, for (const auto &sub : subengines) { const auto &verts = sub.vertices; for (const auto &v : verts) { - DEBUG_PRINTF("vert id:%zu\n", g[v].idx); + DEBUG_PRINTF("vert id:%zu\n", g[v].index); g[v].left.tamarama = tamaProto; } } @@ -1299,7 +1299,7 @@ void buildSuffixContainer(RoseGraph &g, build_context &bc, for (const auto &sub : subengines) { const auto &verts = sub.vertices; for (const auto &v : verts) { - DEBUG_PRINTF("vert id:%zu\n", g[v].idx); + DEBUG_PRINTF("vert id:%zu\n", g[v].index); g[v].suffix.tamarama = tamaProto; } const auto &v = verts[0]; @@ -1790,7 +1790,7 @@ void assignSuffixQueues(RoseBuildImpl &build, build_context &bc) { const suffix_id s(g[v].suffix); - DEBUG_PRINTF("vertex %zu triggers suffix %p\n", g[v].idx, s.graph()); + DEBUG_PRINTF("vertex %zu triggers suffix %p\n", g[v].index, s.graph()); // We may have already built this NFA. if (contains(bc.suffixes, s)) { @@ -1887,7 +1887,7 @@ void findExclusiveSuffixes(RoseBuildImpl &tbi, build_context &bc, const suffix_id s(g[v].suffix); - DEBUG_PRINTF("vertex %zu triggers suffix %p\n", g[v].idx, s.graph()); + DEBUG_PRINTF("vertex %zu triggers suffix %p\n", g[v].index, s.graph()); // We may have already built this NFA. if (contains(suffixes, s)) { @@ -1977,24 +1977,13 @@ bool buildSuffixes(const RoseBuildImpl &tbi, build_context &bc, } static -void buildCountingMiracles(RoseBuildImpl &build, build_context &bc) { +void buildCountingMiracles(build_context &bc) { map, u32> pre_built; - // To ensure compile determinism, we need to iterate over our leftfixes in - // a stronger order than directly over bc.leftfix_info. - vector cm_vertices; - for (const auto &m : bc.leftfix_info) { - if (m.second.countingMiracleCount) { - cm_vertices.push_back(m.first); + for (left_build_info &lbi : bc.leftfix_info | map_values) { + if (!lbi.countingMiracleCount) { + continue; } - } - sort(begin(cm_vertices), end(cm_vertices), VertexIndexComp(build.g)); - - DEBUG_PRINTF("%zu vertices with counting miracles\n", cm_vertices.size()); - - for (const auto &v : cm_vertices) { - auto &lbi = bc.leftfix_info.at(v); - assert(lbi.countingMiracleCount); const CharReach &cr = lbi.countingMiracleReach; assert(!cr.all() && !cr.none()); @@ -2255,12 +2244,12 @@ u32 findMinFloatingLiteralMatch(const RoseBuildImpl &build, u32 minWidth = ROSE_BOUND_INF; for (auto v : vertices_range(g)) { if (build.isAnchored(v) || build.isVirtualVertex(v)) { - DEBUG_PRINTF("skipping %zu anchored or root\n", g[v].idx); + DEBUG_PRINTF("skipping %zu anchored or root\n", g[v].index); continue; } u32 w = g[v].min_offset; - DEBUG_PRINTF("%zu m_o = %u\n", g[v].idx, w); + DEBUG_PRINTF("%zu m_o = %u\n", g[v].index, w); if (w < minWidth) { minWidth = w; @@ -3540,7 +3529,7 @@ void makeRoleSuffix(RoseBuildImpl &build, build_context &bc, RoseVertex v, auto tamaProto = g[v].suffix.tamarama.get(); assert(tamaProto); u32 top = (u32)MQE_TOP_FIRST + - tamaProto->top_remap.at(make_pair(g[v].idx, + tamaProto->top_remap.at(make_pair(g[v].index, g[v].suffix.top)); assert(top < MQE_INVALID); suffixEvent = top; @@ -3622,7 +3611,7 @@ void makeRoleInfixTriggers(RoseBuildImpl &build, build_context &bc, auto tamaProto = g[v].left.tamarama.get(); assert(tamaProto); top = MQE_TOP_FIRST + tamaProto->top_remap.at( - make_pair(g[v].idx, g[e].rose_top)); + make_pair(g[v].index, g[e].rose_top)); assert(top < MQE_INVALID); } else if (!isMultiTopType(nfa->type)) { assert(num_tops(g[v].left) == 1); @@ -3782,7 +3771,7 @@ RoseProgram makeProgram(RoseBuildImpl &build, build_context &bc, // This program may be triggered by different predecessors, with different // offset bounds. We must ensure we put this check/set operation after the // bounds check to deal with this case. - if (hasGreaterInDegree(1, v, g)) { + if (in_degree(v, g) > 1) { makeRoleCheckNotHandled(bc, v, program); } @@ -4438,8 +4427,8 @@ RoseProgram buildLiteralProgram(RoseBuildImpl &build, build_context &bc, if (build.isAnyStart(u)) { continue; // Root roles are not handled with sparse iterator. } - DEBUG_PRINTF("sparse iter edge (%zu,%zu)\n", g[u].idx, - g[target(e, g)].idx); + DEBUG_PRINTF("sparse iter edge (%zu,%zu)\n", g[u].index, + g[target(e, g)].index); assert(contains(bc.roleStateIndices, u)); u32 pred_state = bc.roleStateIndices.at(u); pred_blocks[pred_state].add_block(makeProgram(build, bc, e)); @@ -4455,7 +4444,8 @@ RoseProgram buildLiteralProgram(RoseBuildImpl &build, build_context &bc, if (!build.isAnyStart(u)) { continue; } - DEBUG_PRINTF("root edge (%zu,%zu)\n", g[u].idx, g[target(e, g)].idx); + DEBUG_PRINTF("root edge (%zu,%zu)\n", g[u].index, + g[target(e, g)].index); program.add_block(makeProgram(build, bc, e)); } @@ -4531,8 +4521,8 @@ map> findEdgesByLiteral(const RoseBuildImpl &build) { auto edge_list = vector(begin(m.second), end(m.second)); sort(begin(edge_list), end(edge_list), [&g](const RoseEdge &a, const RoseEdge &b) { - return tie(g[source(a, g)].idx, g[target(a, g)].idx) < - tie(g[source(b, g)].idx, g[target(b, g)].idx); + return tie(g[source(a, g)].index, g[target(a, g)].index) < + tie(g[source(b, g)].index, g[target(b, g)].index); }); lit_edge_map.emplace(m.first, edge_list); } @@ -4658,7 +4648,7 @@ bool hasEodAnchoredSuffix(const RoseBuildImpl &build) { for (auto v : vertices_range(g)) { if (g[v].suffix && build.isInETable(v)) { DEBUG_PRINTF("vertex %zu is in eod table and has a suffix\n", - g[v].idx); + g[v].index); return true; } } @@ -4670,7 +4660,7 @@ bool hasEodMatcher(const RoseBuildImpl &build) { const RoseGraph &g = build.g; for (auto v : vertices_range(g)) { if (build.isInETable(v)) { - DEBUG_PRINTF("vertex %zu is in eod table\n", g[v].idx); + DEBUG_PRINTF("vertex %zu is in eod table\n", g[v].index); return true; } } @@ -4690,19 +4680,19 @@ void addEodAnchorProgram(RoseBuildImpl &build, build_context &bc, continue; } - DEBUG_PRINTF("vertex %zu (with %zu preds) fires on EOD\n", g[v].idx, + DEBUG_PRINTF("vertex %zu (with %zu preds) fires on EOD\n", g[v].index, in_degree(v, g)); vector edge_list; for (const auto &e : in_edges_range(v, g)) { RoseVertex u = source(e, g); if (build.isInETable(u) != in_etable) { - DEBUG_PRINTF("pred %zu %s in etable\n", g[u].idx, + DEBUG_PRINTF("pred %zu %s in etable\n", g[u].index, in_etable ? "is not" : "is"); continue; } if (canEagerlyReportAtEod(build, e)) { - DEBUG_PRINTF("already done report for vertex %zu\n", g[u].idx); + DEBUG_PRINTF("already done report for vertex %zu\n", g[u].index); continue; } edge_list.push_back(e); @@ -4745,8 +4735,8 @@ void addEodEventProgram(RoseBuildImpl &build, build_context &bc, // Sort edge list for determinism, prettiness. sort(begin(edge_list), end(edge_list), [&g](const RoseEdge &a, const RoseEdge &b) { - return tie(g[source(a, g)].idx, g[target(a, g)].idx) < - tie(g[source(b, g)].idx, g[target(b, g)].idx); + return tie(g[source(a, g)].index, g[target(a, g)].index) < + tie(g[source(b, g)].index, g[target(b, g)].index); }); program.add_block( @@ -5247,7 +5237,7 @@ aligned_unique_ptr RoseBuildImpl::buildFinalEngine(u32 minWidth) { return nullptr; } u32 eodNfaIterOffset = buildEodNfaIterator(bc, leftfixBeginQueue); - buildCountingMiracles(*this, bc); + buildCountingMiracles(bc); u32 queue_count = qif.allocated_count(); /* excludes anchored matcher q; * som rev nfas */ diff --git a/src/rose/rose_build_castle.cpp b/src/rose/rose_build_castle.cpp index c65e840d..7987b0f6 100644 --- a/src/rose/rose_build_castle.cpp +++ b/src/rose/rose_build_castle.cpp @@ -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 * modification, are permitted provided that the following conditions are met: @@ -163,7 +163,7 @@ void renovateCastle(RoseBuildImpl &tbi, CastleProto *castle, for (RoseVertex v : verts) { assert(g[v].left.castle.get() == castle); - DEBUG_PRINTF("%zu checks at lag %u\n", g[v].idx, g[v].left.lag); + DEBUG_PRINTF("%zu checks at lag %u\n", g[v].index, g[v].left.lag); vector lits = literals_for_vertex(tbi, v); for (const auto &e : lits) { DEBUG_PRINTF("%s +%u\n", dumpString(e.s).c_str(), e.delay); diff --git a/src/rose/rose_build_compile.cpp b/src/rose/rose_build_compile.cpp index 38c488be..2f1af8a4 100644 --- a/src/rose/rose_build_compile.cpp +++ b/src/rose/rose_build_compile.cpp @@ -205,14 +205,6 @@ bool RoseBuildImpl::hasOnlyPseudoStarInEdges(RoseVertex v) const { return true; } -void RoseBuildImpl::renumberVertices() { - vertexIndex = 0; - DEBUG_PRINTF("renumbering vertices\n"); - for (auto v : vertices_range(g)) { - g[v].idx = vertexIndex++; - } -} - static size_t trailerDueToSelf(const rose_literal_id &lit) { size_t trailer = lit.s.length() - maxPeriod(lit.s); @@ -231,7 +223,7 @@ RoseRoleHistory findHistoryScheme(const RoseBuildImpl &tbi, const RoseEdge &e) { const RoseVertex u = source(e, g); /* pred role */ const RoseVertex v = target(e, g); /* current role */ - DEBUG_PRINTF("find history for [%zu,%zu]\n", g[u].idx, g[v].idx); + DEBUG_PRINTF("find history for [%zu,%zu]\n", g[u].index, g[v].index); DEBUG_PRINTF("u has min_offset=%u, max_offset=%u\n", g[u].min_offset, g[u].max_offset); @@ -285,7 +277,7 @@ RoseRoleHistory findHistoryScheme(const RoseBuildImpl &tbi, const RoseEdge &e) { // Non-EOD cases. DEBUG_PRINTF("examining edge [%zu,%zu] with bounds {%u,%u}\n", - g[u].idx, g[v].idx, g[e].minBound, g[e].maxBound); + g[u].index, g[v].index, g[e].minBound, g[e].maxBound); if (tbi.isAnchored(v)) { // Matches for literals in the anchored table will always arrive at the @@ -875,8 +867,8 @@ bool reduceTopTriggerLoad(RoseBuildImpl &build, NGHolder &h, RoseVertex u) { if (tops.size() <= 1) { return false; } - DEBUG_PRINTF("%zu triggers %zu tops for %p\n", build.g[u].idx, tops.size(), - &h); + DEBUG_PRINTF("%zu triggers %zu tops for %p\n", build.g[u].index, + tops.size(), &h); auto h_top_info = getTopInfo(h); flat_set edges_to_trigger; @@ -976,7 +968,7 @@ void packInfixTops(NGHolder &h, RoseGraph &g, } h[e].tops = move(updated_tops); if (h[e].tops.empty()) { - DEBUG_PRINTF("edge (start,%u) has only unused tops\n", h[v].index); + DEBUG_PRINTF("edge (start,%zu) has only unused tops\n", h[v].index); dead.push_back(e); } } @@ -1311,15 +1303,9 @@ void addSmallBlockLiteral(RoseBuildImpl &tbi, const simple_anchored_info &sai, assert(old_id < tbi.literal_info.size()); const rose_literal_info &li = tbi.literal_info[old_id]; - // For compile determinism, operate over literal vertices in index - // order. - vector lit_verts(begin(li.vertices), end(li.vertices)); - sort(begin(lit_verts), end(lit_verts), VertexIndexComp(g)); - - for (auto lit_v : lit_verts) { + for (auto lit_v : li.vertices) { // Clone vertex with the new literal ID. RoseVertex v = add_vertex(g[lit_v], g); - g[v].idx = tbi.vertexIndex++; g[v].literals.clear(); g[v].literals.insert(lit_id); g[v].min_offset = sai.min_bound + sai.literal.length(); @@ -1347,7 +1333,6 @@ void addSmallBlockLiteral(RoseBuildImpl &tbi, const ue2_literal &lit, RoseGraph &g = tbi.g; RoseVertex v = add_vertex(g); - g[v].idx = tbi.vertexIndex++; g[v].literals.insert(lit_id); g[v].reports = reports; @@ -1557,7 +1542,7 @@ bool historiesAreValid(const RoseGraph &g) { for (const auto &e : edges_range(g)) { if (g[e].history == ROSE_ROLE_HISTORY_INVALID) { DEBUG_PRINTF("edge [%zu,%zu] has invalid history\n", - g[source(e, g)].idx, g[target(e, g)].idx); + g[source(e, g)].index, g[target(e, g)].index); return false; } } @@ -1576,18 +1561,20 @@ bool danglingVertexRef(RoseBuildImpl &tbi) { const ue2::unordered_set valid_vertices(vi, ve); if (!contains(valid_vertices, tbi.anchored_root)) { - DEBUG_PRINTF("anchored root vertex %p not in graph\n", - tbi.anchored_root); + DEBUG_PRINTF("anchored root vertex %zu not in graph\n", + tbi.g[tbi.anchored_root].index); return true; } for (const auto &e : tbi.ghost) { if (!contains(valid_vertices, e.first)) { - DEBUG_PRINTF("ghost key vertex %p not in graph\n", e.first); + DEBUG_PRINTF("ghost key vertex %zu not in graph\n", + tbi.g[e.first].index); return true; } if (!contains(valid_vertices, e.second)) { - DEBUG_PRINTF("ghost value vertex %p not in graph\n", e.second); + DEBUG_PRINTF("ghost value vertex %zu not in graph\n", + tbi.g[e.second].index); return true; } } @@ -1599,11 +1586,11 @@ static bool roleOffsetsAreValid(const RoseGraph &g) { for (auto v : vertices_range(g)) { if (g[v].min_offset >= ROSE_BOUND_INF) { - DEBUG_PRINTF("invalid min_offset for role %zu\n", g[v].idx); + DEBUG_PRINTF("invalid min_offset for role %zu\n", g[v].index); return false; } if (g[v].min_offset > g[v].max_offset) { - DEBUG_PRINTF("min_offset > max_offset for %zu\n", g[v].idx); + DEBUG_PRINTF("min_offset > max_offset for %zu\n", g[v].index); return false; } } diff --git a/src/rose/rose_build_convert.cpp b/src/rose/rose_build_convert.cpp index dfc0ed23..ae08b7cb 100644 --- a/src/rose/rose_build_convert.cpp +++ b/src/rose/rose_build_convert.cpp @@ -290,7 +290,7 @@ bool isUnconvertibleLeaf(const RoseBuildImpl &tbi, const RoseVertex v) { // Find all of the leaves with literals whose length is <= len. static -void findBadLeaves(RoseBuildImpl &tbi, RoseVertexSet &bad) { +void findBadLeaves(RoseBuildImpl &tbi, set &bad) { RoseGraph &g = tbi.g; u32 len = tbi.cc.grey.roseMaxBadLeafLength; @@ -309,15 +309,7 @@ void findBadLeaves(RoseBuildImpl &tbi, RoseVertexSet &bad) { const rose_literal_info &info = tbi.literal_info[lid]; - // Because we do the "clone pred and re-home" trick below, we need to - // iterate over our vertices in a defined ordering, otherwise we'll get - // non-determinism in our bytecode. So, copy and sort this literal's - // vertices. - - vector verts(info.vertices.begin(), info.vertices.end()); - sort(verts.begin(), verts.end(), VertexIndexComp(g)); - - for (auto v : verts) { + for (auto v : info.vertices) { if (!isLeafNode(v, g)) { continue; } @@ -331,7 +323,7 @@ void findBadLeaves(RoseBuildImpl &tbi, RoseVertexSet &bad) { const RoseEdge &e = *in_edges(v, g).first; RoseVertex u = source(e, g); if (out_degree(u, g) != 1) { - DEBUG_PRINTF("re-homing %zu to cloned pred\n", g[v].idx); + DEBUG_PRINTF("re-homing %zu to cloned pred\n", g[v].index); RoseVertex u2 = tbi.cloneVertex(u); for (const auto &e_in : in_edges_range(u, g)) { add_edge(source(e_in, g), u2, g[e_in], g); @@ -340,7 +332,7 @@ void findBadLeaves(RoseBuildImpl &tbi, RoseVertexSet &bad) { remove_edge(e, g); } - DEBUG_PRINTF("%zu is a bad leaf vertex\n", g[v].idx); + DEBUG_PRINTF("%zu is a bad leaf vertex\n", g[v].index); bad.insert(v); } } @@ -348,7 +340,7 @@ void findBadLeaves(RoseBuildImpl &tbi, RoseVertexSet &bad) { void convertBadLeaves(RoseBuildImpl &tbi) { RoseGraph &g = tbi.g; - RoseVertexSet bad(g); + set bad; findBadLeaves(tbi, bad); DEBUG_PRINTF("found %zu bad leaves\n", bad.size()); @@ -371,7 +363,7 @@ void convertBadLeaves(RoseBuildImpl &tbi) { RoseVertex u = source(e, g); assert(!g[u].suffix); g[u].suffix.graph = h; - DEBUG_PRINTF("%zu's nfa holder %p\n", g[u].idx, h.get()); + DEBUG_PRINTF("%zu's nfa holder %p\n", g[u].index, h.get()); dead.push_back(v); } @@ -784,7 +776,7 @@ bool handleMixedPrefixCliche(const NGHolder &h, RoseGraph &g, RoseVertex v, assert(in_degree(h.acceptEod, h) == 1); bool anchored = !proper_out_degree(h.startDs, h); - NFAVertex key = nullptr; + NFAVertex key = NGHolder::null_vertex(); NFAVertex base = anchored ? h.start : h.startDs; if (!anchored) { @@ -798,7 +790,7 @@ bool handleMixedPrefixCliche(const NGHolder &h, RoseGraph &g, RoseVertex v, } for (auto w : adjacent_vertices_range(base, h)) { - DEBUG_PRINTF("checking %u\n", h[w].index); + DEBUG_PRINTF("checking %zu\n", h[w].index); if (!h[w].char_reach.all()) { continue; } @@ -833,7 +825,7 @@ bool handleMixedPrefixCliche(const NGHolder &h, RoseGraph &g, RoseVertex v, set exits_and_repeat_verts; for (auto repeat_v : ri.vertices) { - DEBUG_PRINTF("repeat vertex %u\n", h[repeat_v].index); + DEBUG_PRINTF("repeat vertex %zu\n", h[repeat_v].index); succ(h, repeat_v, &exits_and_repeat_verts); exits_and_repeat_verts.insert(repeat_v); } @@ -963,7 +955,7 @@ void convertPrefixToBounds(RoseBuildImpl &tbi) { continue; } - DEBUG_PRINTF("inspecting prefix of %zu\n", g[v].idx); + DEBUG_PRINTF("inspecting prefix of %zu\n", g[v].index); if (!proper_out_degree(h.startDs, h)) { if (handleStartPrefixCliche(h, g, v, e, ar, &to_delete)) { @@ -1009,7 +1001,7 @@ void convertPrefixToBounds(RoseBuildImpl &tbi) { continue; } - DEBUG_PRINTF("inspecting prefix of %zu\n", g[v].idx); + DEBUG_PRINTF("inspecting prefix of %zu\n", g[v].index); if (!proper_out_degree(h.startDs, h)) { if (handleStartPrefixCliche(h, g, v, e, ar, &to_delete)) { @@ -1044,7 +1036,7 @@ void convertAnchPrefixToBounds(RoseBuildImpl &tbi) { continue; } - DEBUG_PRINTF("vertex %zu\n", g[v].idx); + DEBUG_PRINTF("vertex %zu\n", g[v].index); // This pass runs after makeCastles, so we use the fact that bounded // repeat detection has already been done for us. diff --git a/src/rose/rose_build_dump.cpp b/src/rose/rose_build_dump.cpp index 516548b3..105ee338 100644 --- a/src/rose/rose_build_dump.cpp +++ b/src/rose/rose_build_dump.cpp @@ -104,7 +104,7 @@ public: } os << "[label=\""; - os << "idx=" << g[v].idx <<"\\n"; + os << "index=" << g[v].index <<"\\n"; for (u32 lit_id : g[v].literals) { writeLiteral(os, lit_id); @@ -267,14 +267,14 @@ void dumpRoseGraph(const RoseBuild &build_base, const RoseEngine *t, ofstream os(ss.str()); RoseGraphWriter writer(build, t); - writeGraphviz(os, build.g, writer, get(&RoseVertexProps::idx, build.g)); + writeGraphviz(os, build.g, writer, get(boost::vertex_index, build.g)); } namespace { struct CompareVertexRole { explicit CompareVertexRole(const RoseGraph &g_in) : g(g_in) {} inline bool operator()(const RoseVertex &a, const RoseVertex &b) const { - return g[a].idx < g[b].idx; + return g[a].index < g[b].index; } private: const RoseGraph &g; @@ -372,7 +372,7 @@ void dumpRoseLiterals(const RoseBuildImpl &build, const char *filename) { for (RoseVertex v : verts) { // role info - os << " Index " << g[v].idx << ": groups=0x" << hex << setw(16) + os << " Index " << g[v].index << ": groups=0x" << hex << setw(16) << setfill('0') << g[v].groups << dec; if (g[v].reports.empty()) { @@ -386,13 +386,13 @@ void dumpRoseLiterals(const RoseBuildImpl &build, const char *filename) { // pred info for (const auto &ie : in_edges_range(v, g)) { const auto &u = source(ie, g); - os << " Predecessor idx="; + os << " Predecessor index="; if (u == build.root) { os << "ROOT"; } else if (u == build.anchored_root) { os << "ANCHORED_ROOT"; } else { - os << g[u].idx; + os << g[u].index; } os << ": bounds [" << g[ie].minBound << ", "; if (g[ie].maxBound == ROSE_BOUND_INF) { diff --git a/src/rose/rose_build_groups.cpp b/src/rose/rose_build_groups.cpp index 5e477e3b..0a1c501f 100644 --- a/src/rose/rose_build_groups.cpp +++ b/src/rose/rose_build_groups.cpp @@ -136,7 +136,7 @@ rose_group calcLocalGroup(const RoseVertex v, const RoseGraph &g, } } else { DEBUG_PRINTF("not sibling different mother %zu %zu\n", - g[v].idx, g[w].idx); + g[v].index, g[w].index); } } } @@ -382,7 +382,7 @@ void assignGroupsToRoles(RoseBuildImpl &build) { g[ghost_it->second].groups |= succ_groups; } - DEBUG_PRINTF("vertex %zu: groups=%llx\n", g[v].idx, g[v].groups); + DEBUG_PRINTF("vertex %zu: groups=%llx\n", g[v].index, g[v].groups); } } @@ -397,8 +397,7 @@ getVertexGroupMap(const RoseBuildImpl &build) { vector v_order; v_order.reserve(num_vertices(g)); - boost::topological_sort(g, back_inserter(v_order), - vertex_index_map(get(&RoseVertexProps::idx, g))); + boost::topological_sort(g, back_inserter(v_order)); unordered_map vertex_group_map; vertex_group_map.reserve(num_vertices(g)); @@ -406,7 +405,7 @@ getVertexGroupMap(const RoseBuildImpl &build) { const rose_group initial_groups = build.getInitialGroups(); for (const auto &v : boost::adaptors::reverse(v_order)) { - DEBUG_PRINTF("vertex %zu\n", g[v].idx); + DEBUG_PRINTF("vertex %zu\n", g[v].index); if (build.isAnyStart(v)) { DEBUG_PRINTF("start vertex, groups=0x%llx\n", initial_groups); @@ -419,7 +418,7 @@ getVertexGroupMap(const RoseBuildImpl &build) { assert(in_degree(v, g) > 0); rose_group pred_groups = ~rose_group{0}; for (auto u : inv_adjacent_vertices_range(v, g)) { - DEBUG_PRINTF("pred %zu\n", g[u].idx); + DEBUG_PRINTF("pred %zu\n", g[u].index); assert(contains(vertex_group_map, u)); pred_groups &= vertex_group_map.at(u); } diff --git a/src/rose/rose_build_impl.h b/src/rose/rose_build_impl.h index b3f986aa..6b326d34 100644 --- a/src/rose/rose_build_impl.h +++ b/src/rose/rose_build_impl.h @@ -527,8 +527,6 @@ public: // max overlap considered for every pair (ulit, vlit). size_t maxLiteralOverlap(RoseVertex u, RoseVertex v) const; - void renumberVertices(void); - bool isPseudoStar(const RoseEdge &e) const; bool isPseudoStarOrFirstOnly(const RoseEdge &e) const; bool hasOnlyPseudoStarInEdges(RoseVertex v) const; @@ -551,7 +549,6 @@ public: const RoseVertex anchored_root; RoseLiteralMap literals; std::map ghost; - size_t vertexIndex; ReportID getNewNfaReport() override { return next_nfa_report++; } diff --git a/src/rose/rose_build_infix.cpp b/src/rose/rose_build_infix.cpp index 73f9e99b..f3e7680f 100644 --- a/src/rose/rose_build_infix.cpp +++ b/src/rose/rose_build_infix.cpp @@ -110,7 +110,7 @@ void contractVertex(NGHolder &g, NFAVertex v, static u32 findMaxLiteralMatches(const NGHolder &h, const set &lits) { DEBUG_PRINTF("h=%p, %zu literals\n", &h, lits.size()); - //dumpGraph("infix.dot", h.g); + //dumpGraph("infix.dot", h); // Indices of vertices that could terminate any of the literals in 'lits'. set terms; @@ -163,7 +163,7 @@ u32 findMaxLiteralMatches(const NGHolder &h, const set &lits) { } remove_vertices(dead, g); - //dumpGraph("relaxed.dot", g.g); + //dumpGraph("relaxed.dot", g); depth maxWidth = findMaxWidth(g); DEBUG_PRINTF("maxWidth=%s\n", maxWidth.str().c_str()); @@ -286,7 +286,7 @@ void findCountingMiracleInfo(const left_id &left, const vector &stopTable, CharReach cyclic_cr; for (NFAVertex v : cyclics) { - DEBUG_PRINTF("considering %u ||=%zu\n", g[v].index, + DEBUG_PRINTF("considering %zu ||=%zu\n", g[v].index, g[v].char_reach.count()); cyclic_cr |= g[v].char_reach; } diff --git a/src/rose/rose_build_lookaround.cpp b/src/rose/rose_build_lookaround.cpp index 7c58f931..d2c4b541 100644 --- a/src/rose/rose_build_lookaround.cpp +++ b/src/rose/rose_build_lookaround.cpp @@ -261,7 +261,7 @@ void findForwardReach(const RoseGraph &g, const RoseVertex v, for (const auto &e : out_edges_range(v, g)) { RoseVertex t = target(e, g); if (!g[t].left) { - DEBUG_PRINTF("successor %zu has no leftfix\n", g[t].idx); + DEBUG_PRINTF("successor %zu has no leftfix\n", g[t].index); return; } rose_look.push_back(map()); @@ -585,7 +585,7 @@ bool getTransientPrefixReach(const NGHolder &g, u32 lag, NFAVertex v = *(inv_adjacent_vertices(g.accept, g).first); u32 i = lag + 1; while (v != g.startDs) { - DEBUG_PRINTF("i=%u, v=%u\n", i, g[v].index); + DEBUG_PRINTF("i=%u, v=%zu\n", i, g[v].index); if (is_special(v, g)) { DEBUG_PRINTF("special\n"); return false; diff --git a/src/rose/rose_build_matchers.cpp b/src/rose/rose_build_matchers.cpp index 522ff6b6..f9251b8a 100644 --- a/src/rose/rose_build_matchers.cpp +++ b/src/rose/rose_build_matchers.cpp @@ -102,7 +102,7 @@ bool maskFromLeftGraph(const LeftEngInfo &left, vector &msk, CharReach cr; for (NFAVertex v : curr) { const auto &v_cr = h[v].char_reach; - DEBUG_PRINTF("vertex %u, reach %s\n", h[v].index, + DEBUG_PRINTF("vertex %zu, reach %s\n", h[v].index, describeClass(v_cr).c_str()); cr |= v_cr; insert(&next, inv_adjacent_vertices(v, h)); @@ -438,45 +438,45 @@ static bool isNoRunsVertex(const RoseBuildImpl &build, RoseVertex u) { const RoseGraph &g = build.g; if (!g[u].isBoring()) { - DEBUG_PRINTF("u=%zu is not boring\n", g[u].idx); + DEBUG_PRINTF("u=%zu is not boring\n", g[u].index); return false; } if (!g[u].reports.empty()) { - DEBUG_PRINTF("u=%zu has accept\n", g[u].idx); + DEBUG_PRINTF("u=%zu has accept\n", g[u].index); return false; } /* TODO: handle non-root roles as well. It can't be that difficult... */ - if (!in_degree_equal_to(u, g, 1)) { - DEBUG_PRINTF("u=%zu is not a root role\n", g[u].idx); + if (in_degree(u, g) != 1) { + DEBUG_PRINTF("u=%zu is not a root role\n", g[u].index); return false; } RoseEdge e; bool exists; - tie(e, exists) = edge_by_target(build.root, u, g); + tie(e, exists) = edge(build.root, u, g); if (!exists) { - DEBUG_PRINTF("u=%zu is not a root role\n", g[u].idx); + DEBUG_PRINTF("u=%zu is not a root role\n", g[u].index); return false; } if (g[e].minBound != 0 || g[e].maxBound != ROSE_BOUND_INF) { - DEBUG_PRINTF("u=%zu has bounds from root\n", g[u].idx); + DEBUG_PRINTF("u=%zu has bounds from root\n", g[u].index); return false; } for (const auto &oe : out_edges_range(u, g)) { RoseVertex v = target(oe, g); if (g[oe].maxBound != ROSE_BOUND_INF) { - DEBUG_PRINTF("edge (%zu,%zu) has max bound\n", g[u].idx, - g[target(oe, g)].idx); + DEBUG_PRINTF("edge (%zu,%zu) has max bound\n", g[u].index, + g[v].index); return false; } if (g[v].left) { - DEBUG_PRINTF("v=%zu has rose prefix\n", g[v].idx); + DEBUG_PRINTF("v=%zu has rose prefix\n", g[v].index); return false; } } @@ -563,7 +563,7 @@ u64a literalMinReportOffset(const RoseBuildImpl &build, u64a lit_min_offset = UINT64_MAX; for (const auto &v : info.vertices) { - DEBUG_PRINTF("vertex %zu min_offset=%u\n", g[v].idx, g[v].min_offset); + DEBUG_PRINTF("vertex %zu min_offset=%u\n", g[v].index, g[v].min_offset); u64a vert_offset = g[v].min_offset; diff --git a/src/rose/rose_build_merge.cpp b/src/rose/rose_build_merge.cpp index 054dd12f..01db84a1 100644 --- a/src/rose/rose_build_merge.cpp +++ b/src/rose/rose_build_merge.cpp @@ -206,8 +206,9 @@ void mergeDupeLeaves(RoseBuildImpl &tbi) { continue; } - DEBUG_PRINTF("inspecting vertex idx=%zu in_degree %zu out_degree %zu\n", - g[v].idx, in_degree(v, g), out_degree(v, g)); + DEBUG_PRINTF("inspecting vertex index=%zu in_degree %zu " + "out_degree %zu\n", g[v].index, in_degree(v, g), + out_degree(v, g)); // Vertex must be a reporting leaf node if (g[v].reports.empty() || !isLeafNode(v, g)) { @@ -227,13 +228,13 @@ void mergeDupeLeaves(RoseBuildImpl &tbi) { } RoseVertex t = leaves.find(dupe)->second; - DEBUG_PRINTF("found two leaf dupe roles, idx=%zu,%zu\n", g[v].idx, - g[t].idx); + DEBUG_PRINTF("found two leaf dupe roles, index=%zu,%zu\n", g[v].index, + g[t].index); vector deadEdges; for (const auto &e : in_edges_range(v, g)) { RoseVertex u = source(e, g); - DEBUG_PRINTF("u idx=%zu\n", g[u].idx); + DEBUG_PRINTF("u index=%zu\n", g[u].index); RoseEdge et; bool exists; tie (et, exists) = edge(u, t, g); @@ -244,7 +245,8 @@ void mergeDupeLeaves(RoseBuildImpl &tbi) { deadEdges.push_back(e); } } else { - DEBUG_PRINTF("rehome edge: add %zu->%zu\n", g[u].idx, g[t].idx); + DEBUG_PRINTF("rehome edge: add %zu->%zu\n", + g[u].index, g[t].index); add_edge(u, t, g[e], g); deadEdges.push_back(e); } @@ -279,7 +281,7 @@ void mergeDupeLeaves(RoseBuildImpl &tbi) { // if we've removed anything, we need to renumber vertices if (countRemovals) { - tbi.renumberVertices(); + renumber_vertices(g); DEBUG_PRINTF("removed %zu vertices.\n", countRemovals); } } @@ -350,7 +352,7 @@ void findUncalcLeavesCandidates(RoseBuildImpl &tbi, // Ref count all suffixes, as we don't want to merge a suffix // that happens to be shared with a non-leaf vertex somewhere. - DEBUG_PRINTF("vertex %zu has suffix %p\n", g[v].idx, + DEBUG_PRINTF("vertex %zu has suffix %p\n", g[v].index, g[v].suffix.graph.get()); fcount[g[v].suffix.graph.get()]++; @@ -459,7 +461,7 @@ struct RoseGroup { const RoseGraph &g = build.g; assert(in_degree(v, g) == 1); RoseVertex u = *inv_adjacent_vertices(v, g).first; - parent = g[u].idx; + parent = g[u].index; } bool operator<(const RoseGroup &b) const { @@ -580,14 +582,14 @@ bool dedupeLeftfixes(RoseBuildImpl &tbi) { } // Scan the rest of the list for dupes. - for (auto kt = next(jt); kt != jte; ++kt) { + for (auto kt = std::next(jt); kt != jte; ++kt) { if (g[v].left == g[*kt].left || !rosecmp(v, *kt)) { continue; } // Dupe found. DEBUG_PRINTF("rose at vertex %zu is a dupe of %zu\n", - g[*kt].idx, g[v].idx); + g[*kt].index, g[v].index); assert(g[v].left.lag == g[*kt].left.lag); g[*kt].left = g[v].left; work_done = true; @@ -1070,8 +1072,8 @@ bool mergeableRoseVertices(const RoseBuildImpl &tbi, RoseVertex u, return false; } - DEBUG_PRINTF("roses on %zu and %zu are mergeable\n", tbi.g[u].idx, - tbi.g[v].idx); + DEBUG_PRINTF("roses on %zu and %zu are mergeable\n", tbi.g[u].index, + tbi.g[v].index); return true; } @@ -1387,7 +1389,7 @@ void processMergeQueue(RoseBuildImpl &tbi, RoseBouquet &roses, static bool nfaHasNarrowStart(const NGHolder &g) { - if (hasGreaterOutDegree(1, g.startDs, g)) { + if (out_degree(g.startDs, g) > 1) { return false; // unanchored } @@ -1409,7 +1411,7 @@ bool nfaHasFiniteMaxWidth(const NGHolder &g) { namespace { struct RoseMergeKey { - RoseMergeKey(const RoseVertexSet &parents_in, + RoseMergeKey(const set &parents_in, bool narrowStart_in, bool hasMaxWidth_in) : narrowStart(narrowStart_in), hasMaxWidth(hasMaxWidth_in), @@ -1427,7 +1429,7 @@ struct RoseMergeKey { bool narrowStart; bool hasMaxWidth; - RoseVertexSet parents; + set parents; }; } @@ -1491,7 +1493,7 @@ void mergeLeftfixesVariableLag(RoseBuildImpl &tbi) { map rosesByParent; RoseGraph &g = tbi.g; - RoseVertexSet parents(g); + set parents; DEBUG_PRINTF("-----\n"); DEBUG_PRINTF("entry\n"); @@ -1626,7 +1628,7 @@ struct DedupeLeftKey { : left_hash(hashLeftfix(build.g[v].left)) { const auto &g = build.g; for (const auto &e : in_edges_range(v, g)) { - preds.emplace(g[source(e, g)].idx, g[e].rose_top); + preds.emplace(g[source(e, g)].index, g[e].rose_top); } } @@ -1726,7 +1728,7 @@ void dedupeLeftfixesVariableLag(RoseBuildImpl &tbi) { for (auto v : verts1) { DEBUG_PRINTF("replacing report %u with %u on %zu\n", g[v].left.leftfix_report, - v2_left.leftfix_report, g[v].idx); + v2_left.leftfix_report, g[v].index); u32 orig_lag = g[v].left.lag; g[v].left = v2_left; g[v].left.lag = orig_lag; @@ -1758,7 +1760,7 @@ void replaceTops(NGHolder &h, const map &top_mapping) { } flat_set new_tops; for (u32 t : h[e].tops) { - DEBUG_PRINTF("vertex %u has top %u\n", h[v].index, t); + DEBUG_PRINTF("vertex %zu has top %u\n", h[v].index, t); new_tops.insert(top_mapping.at(t)); } h[e].tops = move(new_tops); @@ -1806,7 +1808,7 @@ bool setDistinctRoseTops(RoseGraph &g, NGHolder &h1, const NGHolder &h2, } for (auto v : verts1) { - DEBUG_PRINTF("vertex %zu\n", g[v].idx); + DEBUG_PRINTF("vertex %zu\n", g[v].index); assert(!g[v].left.haig); assert(!g[v].left.dfa); for (const auto &e : in_edges_range(v, g)) { @@ -1815,7 +1817,7 @@ bool setDistinctRoseTops(RoseGraph &g, NGHolder &h1, const NGHolder &h2, assert(contains(top_mapping, t)); g[e].rose_top = top_mapping[t]; DEBUG_PRINTF("edge (%zu,%zu) went from top %u to %u\n", - g[source(e, g)].idx, g[target(e, g)].idx, t, + g[source(e, g)].index, g[target(e, g)].index, t, top_mapping[t]); } } @@ -1836,7 +1838,7 @@ bool setDistinctSuffixTops(RoseGraph &g, NGHolder &h1, const NGHolder &h2, } for (auto v : verts1) { - DEBUG_PRINTF("vertex %zu\n", g[v].idx); + DEBUG_PRINTF("vertex %zu\n", g[v].index); u32 t = g[v].suffix.top; assert(contains(top_mapping, t)); g[v].suffix.top = top_mapping[t]; diff --git a/src/rose/rose_build_misc.cpp b/src/rose/rose_build_misc.cpp index dcb2a4eb..50ca1d9e 100644 --- a/src/rose/rose_build_misc.cpp +++ b/src/rose/rose_build_misc.cpp @@ -75,7 +75,6 @@ RoseBuildImpl::RoseBuildImpl(ReportManager &rm_in, : cc(cc_in), root(add_vertex(g)), anchored_root(add_vertex(g)), - vertexIndex(0), delay_base_id(MO_INVALID_IDX), hasSom(false), group_end(0), @@ -89,11 +88,9 @@ RoseBuildImpl::RoseBuildImpl(ReportManager &rm_in, boundary(boundary_in), next_nfa_report(0) { // add root vertices to graph - g[root].idx = vertexIndex++; g[root].min_offset = 0; g[root].max_offset = 0; - g[anchored_root].idx = vertexIndex++; g[anchored_root].min_offset = 0; g[anchored_root].max_offset = 0; } @@ -193,7 +190,7 @@ bool RoseBuildImpl::hasLiteralInTable(RoseVertex v, bool RoseBuildImpl::hasNoFloatingRoots() const { for (auto v : adjacent_vertices_range(root, g)) { if (isFloating(v)) { - DEBUG_PRINTF("direct floating root %zu\n", g[v].idx); + DEBUG_PRINTF("direct floating root %zu\n", g[v].index); return false; } } @@ -201,7 +198,7 @@ bool RoseBuildImpl::hasNoFloatingRoots() const { /* need to check if the anchored_root has any literals which are too deep */ for (auto v : adjacent_vertices_range(anchored_root, g)) { if (isFloating(v)) { - DEBUG_PRINTF("indirect floating root %zu\n", g[v].idx); + DEBUG_PRINTF("indirect floating root %zu\n", g[v].index); return false; } } @@ -337,14 +334,14 @@ size_t RoseBuildImpl::maxLiteralOverlap(RoseVertex u, RoseVertex v) const { void RoseBuildImpl::removeVertices(const vector &dead) { for (auto v : dead) { assert(!isAnyStart(v)); - DEBUG_PRINTF("removing vertex %zu\n", g[v].idx); + DEBUG_PRINTF("removing vertex %zu\n", g[v].index); for (auto lit_id : g[v].literals) { literal_info[lit_id].vertices.erase(v); } - clear_vertex_faster(v, g); + clear_vertex(v, g); remove_vertex(v, g); } - renumberVertices(); + renumber_vertices(g); } // Find the maximum bound on the edges to this vertex's successors ignoring @@ -893,7 +890,6 @@ bool operator<(const RoseEdgeProps &a, const RoseEdgeProps &b) { // Note: only clones the vertex, you'll have to wire up your own edges. RoseVertex RoseBuildImpl::cloneVertex(RoseVertex v) { RoseVertex v2 = add_vertex(g[v], g); - g[v2].idx = vertexIndex++; for (const auto &lit_id : g[v2].literals) { literal_info[lit_id].vertices.insert(v2); @@ -1277,7 +1273,7 @@ bool canImplementGraphs(const RoseBuildImpl &tbi) { // First, check the Rose leftfixes. for (auto v : vertices_range(g)) { - DEBUG_PRINTF("leftfix: check vertex %zu\n", g[v].idx); + DEBUG_PRINTF("leftfix: check vertex %zu\n", g[v].index); if (g[v].left.castle) { DEBUG_PRINTF("castle ok\n"); @@ -1295,8 +1291,8 @@ bool canImplementGraphs(const RoseBuildImpl &tbi) { assert(g[v].left.graph->kind == (tbi.isRootSuccessor(v) ? NFA_PREFIX : NFA_INFIX)); if (!isImplementableNFA(*g[v].left.graph, nullptr, tbi.cc)) { - DEBUG_PRINTF("nfa prefix %zu failed (%zu vertices)\n", g[v].idx, - num_vertices(*g[v].left.graph)); + DEBUG_PRINTF("nfa prefix %zu failed (%zu vertices)\n", + g[v].index, num_vertices(*g[v].left.graph)); return false; } } @@ -1305,7 +1301,7 @@ bool canImplementGraphs(const RoseBuildImpl &tbi) { // Suffix graphs. for (auto v : vertices_range(g)) { - DEBUG_PRINTF("suffix: check vertex %zu\n", g[v].idx); + DEBUG_PRINTF("suffix: check vertex %zu\n", g[v].index); const RoseSuffixInfo &suffix = g[v].suffix; if (suffix.castle) { @@ -1323,8 +1319,8 @@ bool canImplementGraphs(const RoseBuildImpl &tbi) { if (suffix.graph) { assert(suffix.graph->kind == NFA_SUFFIX); if (!isImplementableNFA(*suffix.graph, &tbi.rm, tbi.cc)) { - DEBUG_PRINTF("nfa suffix %zu failed (%zu vertices)\n", g[v].idx, - num_vertices(*suffix.graph)); + DEBUG_PRINTF("nfa suffix %zu failed (%zu vertices)\n", + g[v].index, num_vertices(*suffix.graph)); return false; } } diff --git a/src/rose/rose_build_role_aliasing.cpp b/src/rose/rose_build_role_aliasing.cpp index 4757eb11..099e3e7a 100644 --- a/src/rose/rose_build_role_aliasing.cpp +++ b/src/rose/rose_build_role_aliasing.cpp @@ -111,11 +111,9 @@ struct AliasInEdge : EdgeAndVertex { class CandidateSet { public: - typedef RoseVertexSet::iterator iterator; + typedef set::iterator iterator; typedef RoseVertex key_type; - explicit CandidateSet(const VertexIndexComp &comp) : main_cont(comp) {} - iterator begin() { return main_cont.begin(); } iterator end() { return main_cont.end(); } @@ -151,7 +149,7 @@ public: private: /* if a vertex is worth storing, it is worth storing twice */ - RoseVertexSet main_cont; /* deterministic iterator */ + set main_cont; /* deterministic iterator */ ue2::unordered_set hash_cont; /* member checks */ }; @@ -258,7 +256,7 @@ bool samePredecessors(RoseVertex a, RoseVertex b, const RoseGraph &g) { for (const auto &e_a : in_edges_range(a, g)) { bool exists; RoseEdge e; - tie(e, exists) = edge_by_target(source(e_a, g), b, g); + tie(e, exists) = edge(source(e_a, g), b, g); if (!exists || g[e].rose_top != g[e_a].rose_top) { DEBUG_PRINTF("bad tops\n"); return false; @@ -297,7 +295,7 @@ bool hasCommonPredWithBadBounds(RoseVertex a, RoseVertex b, for (const auto &e_a : in_edges_range(a, g)) { bool exists; RoseEdge e; - tie(e, exists) = edge_by_target(source(e_a, g), b, g); + tie(e, exists) = edge(source(e_a, g), b, g); if (exists) { if (g[e_a].maxBound < g[e].minBound || g[e].maxBound < g[e_a].minBound) { @@ -498,11 +496,11 @@ void mergeEdgeAdd(RoseVertex u, RoseVertex v, const RoseEdge &from_edge, const RoseEdgeProps &from_props = g[from_edge]; if (!to_edge) { - DEBUG_PRINTF("adding edge [%zu,%zu]\n", g[u].idx, g[v].idx); + DEBUG_PRINTF("adding edge [%zu,%zu]\n", g[u].index, g[v].index); add_edge(u, v, from_props, g); } else { // union of the two edges. - DEBUG_PRINTF("updating edge [%zu,%zu]\n", g[u].idx, g[v].idx); + DEBUG_PRINTF("updating edge [%zu,%zu]\n", g[u].index, g[v].index); RoseEdgeProps &to_props = g[*to_edge]; to_props.minBound = min(to_props.minBound, from_props.minBound); to_props.maxBound = max(to_props.maxBound, from_props.maxBound); @@ -626,7 +624,7 @@ static void mergeVerticesLeft(RoseVertex a, RoseVertex b, RoseBuildImpl &build, RoseAliasingInfo &rai) { RoseGraph &g = build.g; - DEBUG_PRINTF("merging vertex %zu into %zu\n", g[a].idx, g[b].idx); + DEBUG_PRINTF("merging vertex %zu into %zu\n", g[a].index, g[b].index); insert(&g[b].reports, g[a].reports); @@ -648,7 +646,7 @@ static void mergeVerticesRight(RoseVertex a, RoseVertex b, RoseBuildImpl &build, RoseAliasingInfo &rai) { RoseGraph &g = build.g; - DEBUG_PRINTF("merging vertex %zu into %zu\n", g[a].idx, g[b].idx); + DEBUG_PRINTF("merging vertex %zu into %zu\n", g[a].index, g[b].index); insert(&g[b].reports, g[a].reports); g[b].min_offset = min(g[a].min_offset, g[b].min_offset); @@ -666,7 +664,7 @@ static void mergeVerticesDiamond(RoseVertex a, RoseVertex b, RoseBuildImpl &build, RoseAliasingInfo &rai) { RoseGraph &g = build.g; - DEBUG_PRINTF("merging vertex %zu into %zu\n", g[a].idx, g[b].idx); + DEBUG_PRINTF("merging vertex %zu into %zu\n", g[a].index, g[b].index); // For a diamond merge, most properties are already the same (with the // notable exception of the literal set). @@ -683,7 +681,7 @@ static never_inline void findCandidates(const RoseBuildImpl &build, CandidateSet *candidates) { for (auto v : vertices_range(build.g)) { if (isAliasingCandidate(v, build)) { - DEBUG_PRINTF("candidate %zu\n", build.g[v].idx); + DEBUG_PRINTF("candidate %zu\n", build.g[v].index); DEBUG_PRINTF("lits: %u\n", *build.g[v].literals.begin()); candidates->insert(v); } @@ -748,7 +746,7 @@ bool hasCommonPredWithDiffRoses(RoseVertex a, RoseVertex b, for (const auto &e_a : in_edges_range(a, g)) { bool exists; RoseEdge e; - tie(e, exists) = edge_by_target(source(e_a, g), b, g); + tie(e, exists) = edge(source(e_a, g), b, g); if (exists) { DEBUG_PRINTF("common pred, e_r=%d r_t %u,%u\n", (int)equal_roses, g[e].rose_top, g[e_a].rose_top); @@ -890,7 +888,7 @@ void pruneUnusedTops(NGHolder &h, const RoseGraph &g, used_tops.begin(), used_tops.end(), pt_inserter); h[e].tops = move(pruned_tops); if (h[e].tops.empty()) { - DEBUG_PRINTF("edge (start,%u) has only unused tops\n", h[v].index); + DEBUG_PRINTF("edge (start,%zu) has only unused tops\n", h[v].index); dead.push_back(e); } } @@ -1295,7 +1293,7 @@ bool attemptRoseGraphMerge(RoseBuildImpl &build, bool preds_same, RoseVertex a, } DEBUG_PRINTF("attempting merge of roses on vertices %zu and %zu\n", - g[a].idx, g[b].idx); + g[a].index, g[b].index); set &b_verts = rai.rev_leftfix[b_left]; set aa; @@ -1387,7 +1385,7 @@ bool attemptRoseMerge(RoseBuildImpl &build, bool preds_same, RoseVertex a, RoseVertex b, bool trivialCasesOnly, RoseAliasingInfo &rai) { DEBUG_PRINTF("attempting rose merge, vertices a=%zu, b=%zu\n", - build.g[a].idx, build.g[b].idx); + build.g[a].index, build.g[b].index); assert(a != b); RoseGraph &g = build.g; @@ -1600,7 +1598,7 @@ void diamondMergePass(CandidateSet &candidates, RoseBuildImpl &build, assert(contains(candidates, a)); - DEBUG_PRINTF("trying to merge %zu into somebody\n", g[a].idx); + DEBUG_PRINTF("trying to merge %zu into somebody\n", g[a].index); for (auto jt = it; jt != siblings.end(); ++jt) { RoseVertex b = *jt; assert(contains(candidates, b)); @@ -1714,8 +1712,8 @@ void leftMergePass(CandidateSet &candidates, RoseBuildImpl &build, RoseVertex pred = pickPred(a, g, build); siblings.clear(); - if (pred == RoseGraph::null_vertex() || build.isAnyStart(pred) || - hasGreaterOutDegree(verts.size(), pred, g)) { + if (pred == RoseGraph::null_vertex() || build.isAnyStart(pred) + || out_degree(pred, g) > verts.size()) { // Select sibling from amongst the vertices that share a literal. siblings.insert(siblings.end(), verts.begin(), verts.end()); } else { @@ -1724,8 +1722,6 @@ void leftMergePass(CandidateSet &candidates, RoseBuildImpl &build, insert(&siblings, siblings.end(), adjacent_vertices(pred, g)); } - sort(siblings.begin(), siblings.end(), VertexIndexComp(g)); - auto jt = findLeftMergeSibling(siblings.begin(), siblings.end(), a, build, rai, candidates); if (jt == siblings.end()) { @@ -1754,12 +1750,12 @@ bool safeRootPreds(RoseVertex a, RoseVertex b, const RoseGraph &g) { set a_roots, b_roots; for (auto u : inv_adjacent_vertices_range(a, g)) { - if (!hasGreaterInDegree(0, u, g)) { + if (!in_degree(u, g)) { a_roots.insert(u); } } for (auto u : inv_adjacent_vertices_range(b, g)) { - if (!hasGreaterInDegree(0, u, g)) { + if (!in_degree(u, g)) { b_roots.insert(u); } } @@ -1867,8 +1863,8 @@ void buildCandidateRightSiblings(CandidateSet &candidates, RoseBuildImpl &build, u32 lit_id = *g[a].literals.begin(); RoseVertex succ = pickSucc(a, g); const auto &verts = build.literal_info.at(lit_id).vertices; - if (succ != RoseGraph::null_vertex() && - !hasGreaterInDegree(verts.size(), succ, g)) { + if (succ != RoseGraph::null_vertex() + && in_degree(succ, g) < verts.size()) { if (!done_succ.insert(succ).second) { continue; // succ already in done_succ. } @@ -1901,7 +1897,7 @@ void buildCandidateRightSiblings(CandidateSet &candidates, RoseBuildImpl &build, } for (auto &siblings : sibling_cache | map_values) { - sort(siblings.begin(), siblings.end(), VertexIndexComp(build.g)); + sort(siblings.begin(), siblings.end()); } } @@ -1976,7 +1972,7 @@ bool hasNoDiamondSiblings(const RoseGraph &g, RoseVertex v) { if (has_successor(v, g)) { bool only_succ = true; for (const auto &w : adjacent_vertices_range(v, g)) { - if (hasGreaterInDegree(1, w, g)) { + if (in_degree(w, g) > 1) { only_succ = false; break; } @@ -1992,7 +1988,7 @@ bool hasNoDiamondSiblings(const RoseGraph &g, RoseVertex v) { bool only_pred = true; for (const auto &u : inv_adjacent_vertices_range(v, g)) { - if (hasGreaterOutDegree(1, u, g)) { + if (out_degree(u, g) > 1) { only_pred = false; break; } @@ -2040,7 +2036,7 @@ void aliasRoles(RoseBuildImpl &build, bool mergeRoses) { mergeRoses &= cc.grey.mergeRose & cc.grey.roseMergeRosesDuringAliasing; - CandidateSet candidates(g); + CandidateSet candidates; findCandidates(build, &candidates); DEBUG_PRINTF("candidates %zu\n", candidates.size()); diff --git a/src/rose/rose_build_util.h b/src/rose/rose_build_util.h index 85cfc010..81bb6845 100644 --- a/src/rose/rose_build_util.h +++ b/src/rose/rose_build_util.h @@ -39,31 +39,6 @@ namespace ue2 { /** Max allowed width for transient graphs in block mode */ #define ROSE_BLOCK_TRANSIENT_MAX_WIDTH 255U -// Comparator for vertices using their index property. -struct VertexIndexComp { - VertexIndexComp(const RoseGraph &gg) : g(gg) {} - - bool operator()(const RoseVertex &a, const RoseVertex &b) const { - const RoseVertexProps &pa = g[a]; - const RoseVertexProps &pb = g[b]; - - if (pa.idx < pb.idx) { - return true; - } - if (pa.idx > pb.idx) { - return false; - } - - assert(a == b); // All vertex indices should be distinct. - return a < b; - } - - const RoseGraph &g; -}; - -// Vertex set type, ordered by index. Construct with a graph reference. -typedef std::set RoseVertexSet; - /** * \brief Add two Rose depths together, coping correctly with infinity at * ROSE_BOUND_INF. diff --git a/src/rose/rose_build_width.cpp b/src/rose/rose_build_width.cpp index 6bfcee48..182b62ee 100644 --- a/src/rose/rose_build_width.cpp +++ b/src/rose/rose_build_width.cpp @@ -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 * modification, are permitted provided that the following conditions are met: @@ -77,19 +77,20 @@ u32 findMinWidth(const RoseBuildImpl &tbi, enum rose_literal_table table) { u32 minWidth = ROSE_BOUND_INF; for (auto v : reachable) { if (g[v].eod_accept) { - DEBUG_PRINTF("skipping %zu - not a real vertex\n", g[v].idx); + DEBUG_PRINTF("skipping %zu - not a real vertex\n", g[v].index); continue; } const u32 w = g[v].min_offset; if (!g[v].reports.empty()) { - DEBUG_PRINTF("%zu can fire report at offset %u\n", g[v].idx, w); + DEBUG_PRINTF("%zu can fire report at offset %u\n", g[v].index, w); minWidth = min(minWidth, w); } if (is_end_anchored(g, v)) { - DEBUG_PRINTF("%zu can fire eod report at offset %u\n", g[v].idx, w); + DEBUG_PRINTF("%zu can fire eod report at offset %u\n", g[v].index, + w); minWidth = min(minWidth, w); } @@ -98,7 +99,7 @@ u32 findMinWidth(const RoseBuildImpl &tbi, enum rose_literal_table table) { assert(suffix_width.is_reachable()); DEBUG_PRINTF("%zu has suffix with top %u (width %s), can fire " "report at %u\n", - g[v].idx, g[v].suffix.top, suffix_width.str().c_str(), + g[v].index, g[v].suffix.top, suffix_width.str().c_str(), w + suffix_width); minWidth = min(minWidth, w + suffix_width); } @@ -203,10 +204,10 @@ u32 findMaxBAWidth(const RoseBuildImpl &tbi, enum rose_literal_table table) { // Everyone's anchored, so the max width can be taken from the max // max_offset on our vertices (so long as all accepts are ACCEPT_EOD). for (auto v : reachable) { - DEBUG_PRINTF("inspecting vert %zu\n", g[v].idx); + DEBUG_PRINTF("inspecting vert %zu\n", g[v].index); if (g[v].eod_accept) { - DEBUG_PRINTF("skipping %zu - not a real vertex\n", g[v].idx); + DEBUG_PRINTF("skipping %zu - not a real vertex\n", g[v].index); continue; } diff --git a/src/rose/rose_graph.h b/src/rose/rose_graph.h index 6abe629b..c3af749f 100644 --- a/src/rose/rose_graph.h +++ b/src/rose/rose_graph.h @@ -44,11 +44,10 @@ #include "util/charreach.h" #include "util/depth.h" #include "util/ue2_containers.h" +#include "util/ue2_graph.h" #include #include -#include -#include namespace ue2 { @@ -139,7 +138,7 @@ struct RoseSuffixInfo { /** \brief Properties attached to each Rose graph vertex. */ struct RoseVertexProps { /** \brief Unique dense vertex index. Used for BGL algorithms. */ - size_t idx = ~size_t{0}; + size_t index = ~size_t{0}; /** \brief IDs of literals in the Rose literal map. */ flat_set literals; @@ -183,6 +182,9 @@ struct RoseVertexProps { /** \brief Properties attached to each Rose graph edge. */ /* bounds are distance from end of prev to start of the next */ struct RoseEdgeProps { + /** \brief Unique dense vertex index. Used for BGL algorithms. */ + size_t index = ~size_t{0}; + /** * \brief Minimum distance from the end of the source role's match to the * start of the target role's match. @@ -215,18 +217,10 @@ bool operator<(const RoseEdgeProps &a, const RoseEdgeProps &b); /** * \brief Core Rose graph structure. - * - * Note that we use the list selector for the edge and vertex lists: we depend - * on insertion order for determinism, so we must use these containers. */ -using RoseGraph = boost::adjacency_list; - +struct RoseGraph : public ue2_graph { + friend class RoseBuildImpl; /* to allow index renumbering */ +}; using RoseVertex = RoseGraph::vertex_descriptor; using RoseEdge = RoseGraph::edge_descriptor; diff --git a/src/rose/rose_in_dump.cpp b/src/rose/rose_in_dump.cpp index fbd6858b..172b58e8 100644 --- a/src/rose/rose_in_dump.cpp +++ b/src/rose/rose_in_dump.cpp @@ -122,7 +122,7 @@ void dumpPreRoseGraph(const RoseInGraph &ig, const Grey &grey, ostringstream name; name << grey.dumpPath << "pre_rose_" << id << ".dot"; - dumpGraph(name.str().c_str(), h->g); + dumpGraph(name.str().c_str(), *h); assert(allMatchStatesHaveReports(*h)); } diff --git a/src/rose/rose_in_graph.h b/src/rose/rose_in_graph.h index 14d4d9b2..0e218576 100644 --- a/src/rose/rose_in_graph.h +++ b/src/rose/rose_in_graph.h @@ -46,13 +46,11 @@ #include "ue2common.h" #include "rose/rose_common.h" #include "util/ue2_containers.h" +#include "util/ue2_graph.h" #include "util/ue2string.h" #include -#include -#include - namespace ue2 { class NGHolder; @@ -128,6 +126,7 @@ public: flat_set reports; /**< for RIV_ACCEPT/RIV_ACCEPT_EOD */ u32 min_offset; /**< Minimum offset at which this vertex can match. */ u32 max_offset; /**< Maximum offset at which this vertex can match. */ + size_t index = 0; }; struct RoseInEdgeProps { @@ -174,11 +173,12 @@ struct RoseInEdgeProps { std::shared_ptr haig; u32 graph_lag; + size_t index = 0; }; -typedef boost::adjacency_list RoseInGraph; +struct RoseInGraph + : public ue2_graph { +}; typedef RoseInGraph::vertex_descriptor RoseInVertex; typedef RoseInGraph::edge_descriptor RoseInEdge; diff --git a/src/rose/rose_in_util.cpp b/src/rose/rose_in_util.cpp index cce6ff35..3b31b38e 100644 --- a/src/rose/rose_in_util.cpp +++ b/src/rose/rose_in_util.cpp @@ -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 * modification, are permitted provided that the following conditions are met: @@ -48,27 +48,15 @@ using namespace std; namespace ue2 { -static -void populateIndexMap(const RoseInGraph &in, - map *index_map) { - size_t i = 0; - for (auto v : vertices_range(in)) { - (*index_map)[v] = i++; - } -} - /* Returns a topological ordering of the vertices in g. That is the starts are * at the front and all the predecessors of a vertex occur earlier in the list * than the vertex. */ vector topo_order(const RoseInGraph &g) { - map index_map; - populateIndexMap(g, &index_map); - + assert(hasCorrectlyNumberedVertices(g)); vector v_order; - v_order.reserve(index_map.size()); + v_order.reserve(num_vertices(g)); - topological_sort(g, back_inserter(v_order), - vertex_index_map(boost::make_assoc_property_map(index_map))); + boost::topological_sort(g, back_inserter(v_order)); reverse(v_order.begin(), v_order.end()); /* put starts at the front */ @@ -105,6 +93,7 @@ private: } unique_ptr cloneRoseGraph(const RoseInGraph &ig) { + assert(hasCorrectlyNumberedVertices(ig)); unique_ptr out = make_unique(); unordered_map> graph_map; @@ -120,12 +109,8 @@ unique_ptr cloneRoseGraph(const RoseInGraph &ig) { } } - map index_map; - populateIndexMap(ig, &index_map); - copy_graph(ig, *out, - boost::edge_copy(RoseEdgeCopier(ig, *out, graph_map, haig_map)) - .vertex_index_map(boost::make_assoc_property_map(index_map))); + boost::edge_copy(RoseEdgeCopier(ig, *out, graph_map, haig_map))); return out; } diff --git a/src/smallwrite/smallwrite_build.cpp b/src/smallwrite/smallwrite_build.cpp index d395a7af..108bca8a 100644 --- a/src/smallwrite/smallwrite_build.cpp +++ b/src/smallwrite/smallwrite_build.cpp @@ -126,7 +126,7 @@ bool pruneOverlongReports(NFAVertex v, NGHolder &g, const depth &max_depth, } if (g[v].reports.empty()) { - DEBUG_PRINTF("none of vertex %u's reports can match, cut accepts\n", + DEBUG_PRINTF("none of vertex %zu's reports can match, cut accepts\n", g[v].index); remove_edge(v, g.accept, g); remove_edge(v, g.acceptEod, g); diff --git a/src/som/slot_manager.h b/src/som/slot_manager.h index 9de78f44..971ea362 100644 --- a/src/som/slot_manager.h +++ b/src/som/slot_manager.h @@ -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 * modification, are permitted provided that the following conditions are met: @@ -34,7 +34,7 @@ #define SLOT_MANAGER_H #include "ue2common.h" -#include "nfagraph/ng_graph.h" +#include "nfagraph/ng_holder.h" #include "util/alloc.h" #include "util/ue2_containers.h" diff --git a/src/util/dump_charclass.cpp b/src/util/dump_charclass.cpp index 74b45414..4c159ec2 100644 --- a/src/util/dump_charclass.cpp +++ b/src/util/dump_charclass.cpp @@ -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 * modification, are permitted provided that the following conditions are met: @@ -249,6 +249,15 @@ string describeClass(const CharReach &cr, size_t maxLength, return oss.str(); } +string describeClasses(const std::vector &v, size_t maxClassLength, + enum cc_output_t out_type) { + std::ostringstream oss; + for (const auto &cr : v) { + describeClass(oss, cr, maxClassLength, out_type); + } + return oss.str(); +} + // C stdio wrapper void describeClass(FILE *f, const CharReach &cr, size_t maxLength, enum cc_output_t out_type) { diff --git a/src/util/dump_charclass.h b/src/util/dump_charclass.h index 9c3362bc..45b707f1 100644 --- a/src/util/dump_charclass.h +++ b/src/util/dump_charclass.h @@ -38,6 +38,7 @@ #include #include #include +#include namespace ue2 { @@ -54,6 +55,10 @@ void describeClass(std::ostream &os, const CharReach &cr, size_t maxLength = 16, std::string describeClass(const CharReach &cr, size_t maxLength = 16, enum cc_output_t out_type = CC_OUT_TEXT); +std::string describeClasses(const std::vector &v, + size_t maxClassLength = 16, + enum cc_output_t out_type = CC_OUT_TEXT); + void describeClass(FILE *f, const CharReach &cr, size_t maxLength, enum cc_output_t out_type); diff --git a/src/util/graph.h b/src/util/graph.h index d15e77aa..ae7c2c90 100644 --- a/src/util/graph.h +++ b/src/util/graph.h @@ -38,71 +38,18 @@ #include "util/graph_range.h" #include "util/ue2_containers.h" -#include -#include #include -#include + +#include +#include +#include namespace ue2 { /** \brief True if the given vertex has no out-edges. */ template bool isLeafNode(const typename Graph::vertex_descriptor& v, const Graph& g) { - typename Graph::adjacency_iterator ai, ae; - std::tie(ai, ae) = adjacent_vertices(v, g); - return ai == ae; // no out edges -} - -/** \brief True if the out-degree of vertex \a v is greater than the given - * limit. */ -template -bool hasGreaterOutDegree(size_t limit, - const typename Graph::vertex_descriptor& v, - const Graph& g) { - typename Graph::out_edge_iterator ei, ee; - for (std::tie(ei, ee) = out_edges(v, g); ei != ee; ++ei) { - if (limit-- == 0) { - return true; - } - } - return false; -} - -/** \brief Returns true if the in-degree of vertex \a v is greater than the - * given limit. */ -template -bool hasGreaterInDegree(size_t limit, - const typename Graph::vertex_descriptor& v, - const Graph& g) { - typename Graph::in_edge_iterator ei, ee; - for (std::tie(ei, ee) = in_edges(v, g); ei != ee; ++ei) { - if (limit-- == 0) { - return true; - } - } - return false; -} - -/** - * \brief True if the degree of vertex \a v is greater than the given limit. - */ -template -bool has_greater_degree(size_t limit, - const typename Graph::vertex_descriptor &v, - const Graph &g) { - typename Graph::in_edge_iterator ei, ee; - for (std::tie(ei, ee) = in_edges(v, g); ei != ee; ++ei) { - if (limit-- == 0) { - return true; - } - } - typename Graph::out_edge_iterator oi, oe; - for (std::tie(oi, oe) = out_edges(v, g); oi != oe; ++oi) { - if (limit-- == 0) { - return true; - } - } - return false; + return out_degree(v, g) == 0; } /** \brief True if vertex \a v has an edge to itself. */ @@ -137,48 +84,10 @@ size_t proper_in_degree(const typename Graph::vertex_descriptor &v, return in_degree(v, g) - (edge(v, v, g).second ? 1 : 0); } -/** \brief Returns true iff the in-degree of vertex \a v is \a expected */ -template -bool in_degree_equal_to(const typename Graph::vertex_descriptor &v, - const Graph &g, size_t expected) { - size_t seen = 0; - typename Graph::in_edge_iterator ei, ee; - for (std::tie(ei, ee) = in_edges(v, g);; ++ei, seen++) { - if (seen == expected) { - return ei == ee; - } - if (ei == ee) { - return false; - } - } -} - -/** \brief same as edge(s, t, g) by finds edge by inspecting in-edges of target. - * Should be used when it is known that t has a small in-degree and when s - * may have a large out-degree. - */ -template -std::pair -edge_by_target(const typename Graph::vertex_descriptor &s, - const typename Graph::vertex_descriptor &t, const Graph &g) { - typename Graph::in_edge_iterator ei, ee; - for (std::tie(ei, ee) = in_edges(t, g); ei != ee; ++ei) { - if (source(*ei, g) == s) { - return std::make_pair(*ei, true); - } - } - - return std::make_pair(typename Graph::edge_descriptor(), false); -} - - /** \brief True if vertex \a v has at least one successor. */ template bool has_successor(const typename Graph::vertex_descriptor &v, const Graph &g) { - typename Graph::adjacency_iterator ai, ae; - std::tie(ai, ae) = adjacent_vertices(v, g); - - return ai != ae; + return out_degree(v, g) > 0; } /** \brief True if vertex \a v has at least one successor other than itself. */ @@ -197,26 +106,6 @@ bool has_proper_successor(const typename Graph::vertex_descriptor &v, return ai != ae; } -/** \brief A version of clear_vertex that explicitly removes in- and out-edges - * for vertex \a v. For many graphs, this is faster than the BGL clear_vertex - * function, which walks the graph's full edge list. */ -template -void clear_vertex_faster(typename Graph::vertex_descriptor v, Graph &g) { - typename Graph::in_edge_iterator ei, ee; - tie(ei, ee) = in_edges(v, g); - while (ei != ee) { - remove_edge(*ei++, g); - } - - typename Graph::out_edge_iterator oi, oe; - tie(oi, oe) = out_edges(v, g); - while (oi != oe) { - // NOTE: version that takes out_edge_iterator is faster according to - // the BGL docs. - remove_edge(oi++, g); - } -} - /** \brief Find the set of vertices that are reachable from the vertices in \a * sources. */ template @@ -329,6 +218,40 @@ std::pair add_edge_if_not_present( return e; } +#ifndef NDEBUG + +template +bool hasCorrectlyNumberedVertices(const Graph &g) { + auto count = num_vertices(g); + std::vector ids(count, false); + for (auto v : vertices_range(g)) { + auto id = g[v].index; + if (id >= count || ids[id]) { + return false; // duplicate + } + ids[id] = true; + } + return std::find(ids.begin(), ids.end(), false) == ids.end() + && count == vertex_index_upper_bound(g); +} + +template +bool hasCorrectlyNumberedEdges(const Graph &g) { + auto count = num_edges(g); + std::vector ids(count, false); + for (const auto &e : edges_range(g)) { + auto id = g[e].index; + if (id >= count || ids[id]) { + return false; // duplicate + } + ids[id] = true; + } + return std::find(ids.begin(), ids.end(), false) == ids.end() + && count == edge_index_upper_bound(g); +} + +#endif + } // namespace ue2 #endif // UTIL_GRAPH_H diff --git a/src/util/graph_range.h b/src/util/graph_range.h index 82814695..3df06911 100644 --- a/src/util/graph_range.h +++ b/src/util/graph_range.h @@ -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 * modification, are permitted provided that the following conditions are met: @@ -51,7 +51,6 @@ #ifndef UTIL_GRAPH_RANGE_H #define UTIL_GRAPH_RANGE_H -#include #include namespace ue2 { diff --git a/src/util/ue2_graph.h b/src/util/ue2_graph.h new file mode 100644 index 00000000..07c24746 --- /dev/null +++ b/src/util/ue2_graph.h @@ -0,0 +1,1083 @@ +/* + * Copyright (c) 2016, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UE2_GRAPH_H +#define UE2_GRAPH_H + +#include "ue2common.h" +#include "util/graph_range.h" + +#include +#include +#include /* vertex_index_t, ... */ +#include /* no_property */ +#include +#include +#include +#include + +#include /* tie */ +#include /* pair, declval */ + +/* + * Basic design of ue2_graph: + * + * Fairly standard adjacency list type graph structure. The main internal + * structures are vertex_node and edge_node. + * + * Each vertex_node maintains lists of incoming and outgoing edge_nodes, a + * serial number and the vertex properties. + * + * Each edge_node contains pointers to the source and target vertex as well as + * the serial number and edge properties. + * + * Every time an edge_node or vertex_node is created in the graph, it is given a + * unique serial number by increasing a private counter in the graph. + * + * The main thing to note is that the in and out edge lists are intrusive lists + * with the edge_node containing the necessary hooks. This means that we can + * easily convert the edge_node to iterators of the in_edge_list and + * out_edge_list and remove them from the lists. + * + * vertex_descriptor and edge_descriptor structures both just wrap pointers to + * the relevant node structure along with the serial number. operator<() for the + * descriptors is overridden to look at the serial member of the node. + * We do not use: + * - the address of the node structure as this would lead to an unstable + * ordering of vertices between runs. + * - the index field as this would mean that the generation of new index + * values (during say renumbering of vertex nodes after removing some + * vertices) would potentially reorder vertices and corrupt containers + * such as std::set<>. + * The serial number is copied into the descriptors so that we can still have + * descriptors in a container (such as set or unordered_set) after removing the + * underlying node. + * + * Hashing of descriptors is based on the serial field for similar reasons. + * + * + * + * Main differences from boost::adjacency_list<> with listS: + * + * (1) Deterministic ordering for vertices and edges + * boost::adjacency_list<> uses pointer ordering for vertex_descriptors. As + * a result, ordering of vertices and edges between runs is + * non-deterministic unless containers, etc use custom comparators. + * + * (2) Proper types for descriptors, etc. + * No more void * for vertex_descriptors and trying to use it for the wrong + * graph type. + * + * (3) Constant time num_edges(), num_vertices(), degree(), in_degree() and + * out_degree() + * std::list is meant to have constant time in C++11 ::size(), but this is + * not always implemented as people want to keep ABI compatibility with + * existing C++98 standard libraries (gcc 4.8). As ue2_graph_h uses + * intrusive lists rather than std::list this is not an issue for us. + * + * (4) Constant time remove_edge(e, g) + * ue2_graph uses boost::intrusive_lists internally so we can easily unlink + * an edge from the in and out edgelist of its source and target. + * + * (5) More efficient edge(u, v, g) and remove_edge(u, v, g) + * ue2_graph will check which of u and v has the smallest relevant degree + * and use that to search for the edge(s). + * + * (6) Automatically populate the index field of vertex and edge bundles. + * Saves us from doing it manually. Naturally there is nothing to prevent + * the user from stuffing up the index properties later. + * + * (7) Different edge iteration order + * ue2_graph does not maintain an explicit global edge list, so the + * edge_iterator is constructed out of vertex_iterator and + * out_edge_iterators by iterating the out_edges of each vertices. This + * means that edge iteration order is not insertion order like for + * adjacency_list. + * + * (8) null_edge() + * Because why not? + * + * (9) vertex and edge properties must have an index field. + * We generally need them so the effort has not been put into specialising + * for when they are not present. + * + * + * + * Possible Future Work: + * + * (1) Improve edge(u, v, g) performance + * This function sees a fair amount of use and is O(n) in the smallest of + * the source out_degree or target in_degree. This could be improved by + * changes on of the edge containers to be something similar to a multiset. + * + * (2) 'Lie' about the number of edges / vertices + * + * One of the main uses of num_edges() and num_vertices() is to allocate a + * vector, etc so that it can be indexed by edge or vertex index. If + * num_edges() and num_vertices() returned the appropriate size for such a + * vector (at least one more than the largest index), we would be able to + * avoid some renumbering operations. Functions would have to be provided to + * get the real number of vertices and edges. Having num_vertices() and + * num_edges() return an over-estimate is not without precedence in the BGL + * - the filtered_graph adaptor does the same thing and is compatible with + * various (all?) BGL algorithms. It is not clear that this was done + * deliberately for the same reason or because it is difficult for + * filtered_graph to get the true counts. + * + * (3) Investigate slab/pooled allocation schemes for nodes. + */ + +namespace ue2 { + +namespace graph_detail { + +class graph_base : boost::noncopyable { +}; + +struct default_edge_property { + size_t index; +}; + +struct default_vertex_property { + size_t index; +}; + +} + +template +class ue2_graph : graph_detail::graph_base { +private: + struct in_edge_tag { }; + struct out_edge_tag { }; + + struct vertex_node; + + using out_edge_hook + = boost::intrusive::list_base_hook >; + + /* in_edge_hook does not use safe mode as during graph destruction we do not + * maintain the in edge lists */ + using in_edge_hook + = boost::intrusive::list_base_hook, + boost::intrusive::link_mode >; + + struct edge_node : public out_edge_hook, public in_edge_hook { + explicit edge_node(u64a serial_in) : serial(serial_in) { } + + vertex_node *source = nullptr; + vertex_node *target = nullptr; + const u64a serial; /*< used to order edges. We do not use props.index so + * that there is no danger of invalidating sets or + * other containers by changing the index due to + * renumbering */ + EdgePropertyType props; + }; + + template using vertex_edge_list + = boost::intrusive::list >; + + struct vertex_node : public boost::intrusive::list_base_hook<> { + explicit vertex_node(u64a serial_in) : serial(serial_in) { } + + VertexPropertyType props; + const u64a serial; /*< used to order vertices. We do not use props.index + * so that there is no danger of invalidating sets or + * other containers by changing the index due to + * renumbering */ + + /* The incoming edges are not considered owned by the vertex */ + vertex_edge_list in_edge_list; + + /* The out going edges are considered owned by the vertex and + * need to be freed when the graph is begin destroyed */ + vertex_edge_list out_edge_list; + + /* The destructor only frees memory owned by the vertex and will leave + * the neighbour's edges in a bad state. If a vertex is being removed + * (rather than the graph being destroyed), then the more gentle clean + * up of clear_vertex() is required to be called first */ + ~vertex_node() { + out_edge_list.clear_and_dispose(delete_disposer()); + } + }; + + struct delete_disposer { + template void operator()(const T *d) const { delete d; } + }; + + struct in_edge_disposer { + void operator()(edge_node *e) const { + /* remove from source's out edge list before deleting */ + vertex_node *u = e->source; + u->out_edge_list.erase(u->out_edge_list.iterator_to(*e)); + delete e; + } + }; + + struct out_edge_disposer { + void operator()(edge_node *e) const { + /* remove from target's in edge list before deleting */ + vertex_node *v = e->target; + v->in_edge_list.erase(v->in_edge_list.iterator_to(*e)); + delete e; + } + }; + + using vertices_list_type + = boost::intrusive::list > >; + + vertices_list_type vertices_list; + +protected: /* to allow renumbering */ + static const size_t N_SPECIAL_VERTICES = 0; /* override in derived class */ + size_t next_vertex_index = 0; + size_t next_edge_index = 0; + +private: + size_t graph_edge_count = 0; /* maintained explicitly as we have no global + edge list */ + + u64a next_serial = 0; + u64a new_serial() { + u64a serial = next_serial++; + if (!next_serial) { + /* if we have created enough graph edges/vertices to overflow a u64a + * we must have spent close to an eternity adding to this graph so + * something must have gone very wrong and we will not be producing + * a final bytecode in a reasonable amount of time. Or, more likely, + * the next_serial value has become corrupt. */ + throw std::overflow_error("too many graph edges/vertices created"); + } + return serial; + } +public: + using vertices_size_type = typename vertices_list_type::size_type; + using degree_size_type + = typename vertex_edge_list::size_type; + using edges_size_type = size_t; + + using vertex_property_type = VertexPropertyType; + using edge_property_type = EdgePropertyType; + + using graph_bundled = boost::no_property; + using vertex_bundled = VertexPropertyType; + using edge_bundled = EdgePropertyType; + + class vertex_descriptor : boost::totally_ordered { + public: + vertex_descriptor() : p(nullptr), serial(0) { } + explicit vertex_descriptor(vertex_node *pp) + : p(pp), serial(pp->serial) { } + + operator bool() const { return p; } + bool operator<(const vertex_descriptor b) const { + if (p && b.p) { + /* no vertices in the same graph can have the same serial */ + assert(p == b.p || serial != b.serial); + return serial < b.serial; + } else { + return p < b.p; + } + } + bool operator==(const vertex_descriptor b) const { + return p == b.p; + } + + friend size_t hash_value(vertex_descriptor v) { + using boost::hash_value; + return hash_value(v.serial); + } + + private: + vertex_node *p; + u64a serial; + friend ue2_graph; + }; + + class edge_descriptor : boost::totally_ordered { + public: + edge_descriptor() : p(nullptr), serial(0) { } + explicit edge_descriptor(edge_node *pp) : p(pp), serial(pp->serial) { } + + operator bool() const { return p; } + bool operator<(const edge_descriptor b) const { + if (p && b.p) { + /* no edges in the same graph can have the same serial */ + assert(p == b.p || serial != b.serial); + return serial < b.serial; + } else { + return p < b.p; + } + } + bool operator==(const edge_descriptor b) const { + return p == b.p; + } + + friend size_t hash_value(edge_descriptor e) { + using boost::hash_value; + return hash_value(e.serial); + } + + private: + edge_node *p; + u64a serial; + friend ue2_graph; + }; + +private: + static + vertex_node *raw(vertex_descriptor v) { return v.p; } + + static + edge_node *raw(edge_descriptor e) { return e.p; } + + /* Note: apparently, nested class templates cannot be fully specialised but + * they can be partially specialised. Sigh, ... */ + template + struct bundle_key_type { + }; + + template + struct bundle_key_type { + using type = vertex_descriptor; + }; + + template + struct bundle_key_type { + using type = edge_descriptor; + }; + +public: + class out_edge_iterator : public boost::iterator_adaptor< + out_edge_iterator, + typename vertex_edge_list::const_iterator, + edge_descriptor, + boost::bidirectional_traversal_tag, + edge_descriptor> { + using super = typename out_edge_iterator::iterator_adaptor_; + public: + out_edge_iterator() : super() { } + explicit out_edge_iterator( + typename vertex_edge_list::const_iterator it) + : super(it) { } + edge_descriptor dereference() const { + /* :( const_cast makes me sad but constness is defined by the graph + * parameter of bgl api calls */ + return edge_descriptor(const_cast(&*super::base())); + } + }; + + class in_edge_iterator : public boost::iterator_adaptor< + in_edge_iterator, + typename vertex_edge_list::const_iterator, + edge_descriptor, + boost::bidirectional_traversal_tag, + edge_descriptor> { + using super = typename in_edge_iterator::iterator_adaptor_; + public: + in_edge_iterator() : super() { } + explicit in_edge_iterator( + typename vertex_edge_list::const_iterator it) + : super(it) { } + edge_descriptor dereference() const { + /* :( const_cast makes me sad but constness is defined by the graph + * parameter of bgl api calls */ + return edge_descriptor(const_cast(&*super::base())); + } + }; + + class adjacency_iterator : public boost::iterator_adaptor< + adjacency_iterator, + out_edge_iterator, + vertex_descriptor, + boost::bidirectional_traversal_tag, + vertex_descriptor> { + using super = typename adjacency_iterator::iterator_adaptor_; + public: + adjacency_iterator(out_edge_iterator a) : super(std::move(a)) { } + adjacency_iterator() { } + + vertex_descriptor dereference() const { + return vertex_descriptor(super::base()->p->target); + } + }; + + class inv_adjacency_iterator : public boost::iterator_adaptor< + inv_adjacency_iterator, + in_edge_iterator, + vertex_descriptor, + boost::bidirectional_traversal_tag, + vertex_descriptor> { + using super = typename inv_adjacency_iterator::iterator_adaptor_; + public: + inv_adjacency_iterator(in_edge_iterator a) : super(std::move(a)) { } + inv_adjacency_iterator() { } + + vertex_descriptor dereference() const { + return vertex_descriptor(super::base()->p->source); + } + }; + + class vertex_iterator : public boost::iterator_adaptor< + vertex_iterator, + typename vertices_list_type::const_iterator, + vertex_descriptor, + boost::bidirectional_traversal_tag, + vertex_descriptor> { + using super = typename vertex_iterator::iterator_adaptor_; + public: + vertex_iterator() : super() { } + explicit vertex_iterator(typename vertices_list_type::const_iterator it) + : super(it) { } + vertex_descriptor dereference() const { + /* :( const_cast makes me sad but constness is defined by the graph + * parameter of bgl api calls */ + return vertex_descriptor( + const_cast(&*super::base())); + } + }; + + class edge_iterator : public boost::iterator_facade< + edge_iterator, + edge_descriptor, + boost::forward_traversal_tag, /* TODO: make bidi */ + edge_descriptor> { + public: + using main_base_iter_type = vertex_iterator; + using aux_base_iter_type = out_edge_iterator; + + edge_iterator(main_base_iter_type b, main_base_iter_type e) + : main(std::move(b)), main_end(std::move(e)) { + if (main == main_end) { + return; + } + std::tie(aux, aux_end) = out_edges_i(*main); + while (aux == aux_end) { + ++main; + if (main == main_end) { + break; + } + std::tie(aux, aux_end) = out_edges_i(*main); + } + } + edge_iterator() { } + + friend class boost::iterator_core_access; + void increment() { + ++aux; + while (aux == aux_end) { + ++main; + if (main == main_end) { + break; + } + std::tie(aux, aux_end) = out_edges_i(*main); + } + } + bool equal(const edge_iterator &other) const { + return main == other.main && (main == main_end || aux == other.aux); + } + edge_descriptor dereference() const { + return *aux; + } + + main_base_iter_type main; + main_base_iter_type main_end; + aux_base_iter_type aux; + aux_base_iter_type aux_end; + }; + +private: + static + std::pair + out_edges_i(vertex_descriptor v) { + return {out_edge_iterator(raw(v)->out_edge_list.begin()), + out_edge_iterator(raw(v)->out_edge_list.end())}; + } + +public: + static + vertex_descriptor null_vertex() { return vertex_descriptor(); } + + friend + vertex_descriptor add_vertex(Graph &g) { + vertex_node *v = new vertex_node(g.new_serial()); + v->props.index = g.next_vertex_index++; + g.vertices_list.push_back(*v); + return vertex_descriptor(v); + } + + friend + void remove_vertex(vertex_descriptor v, Graph &g) { + vertex_node *vv = Graph::raw(v); + assert(vv->in_edge_list.empty()); + assert(vv->out_edge_list.empty()); + g.vertices_list.erase_and_dispose(g.vertices_list.iterator_to(*vv), + delete_disposer()); + } + + friend + void clear_in_edges(vertex_descriptor v, Graph &g) { + g.graph_edge_count -= Graph::raw(v)->in_edge_list.size(); + Graph::raw(v)->in_edge_list.clear_and_dispose(in_edge_disposer()); + } + + friend + void clear_out_edges(vertex_descriptor v, Graph &g) { + g.graph_edge_count -= Graph::raw(v)->out_edge_list.size(); + Graph::raw(v)->out_edge_list.clear_and_dispose(out_edge_disposer()); + } + + friend + void clear_vertex(vertex_descriptor v, Graph &g) { + clear_in_edges(v, g); + clear_out_edges(v, g); + } + + /* IncidenceGraph concept functions */ + + friend + vertex_descriptor source(edge_descriptor e, const Graph &) { + return vertex_descriptor(Graph::raw(e)->source); + } + + friend + vertex_descriptor target(edge_descriptor e, const Graph &) { + return vertex_descriptor(Graph::raw(e)->target); + } + + friend + degree_size_type out_degree(vertex_descriptor v, const Graph &) { + return Graph::raw(v)->out_edge_list.size(); + } + + friend + std::pair + out_edges(vertex_descriptor v, const Graph &) { + return Graph::out_edges_i(v); + } + + /* BidirectionalGraph concept functions */ + + friend + degree_size_type in_degree(vertex_descriptor v, const Graph &) { + return Graph::raw(v)->in_edge_list.size(); + } + + friend + std::pair + in_edges(vertex_descriptor v, const Graph &) { + return {in_edge_iterator(Graph::raw(v)->in_edge_list.begin()), + in_edge_iterator(Graph::raw(v)->in_edge_list.end())}; + } + + /* Note: this is defined so that self loops are counted twice - which may or + * may not be what you want. Actually, you probably don't want this at + * all. */ + friend + degree_size_type degree(vertex_descriptor v, const Graph &g) { + return in_degree(v, g) + out_degree(v, g); + } + + /* AdjacencyList concept functions */ + + friend + std::pair + adjacent_vertices(vertex_descriptor v, const Graph &g) { + auto out_edge_its = out_edges(v, g); + return {adjacency_iterator(out_edge_its.first), + adjacency_iterator(out_edge_its.second)}; + } + + /* AdjacencyMatrix concept functions + * (Note: complexity guarantee is not met) */ + + friend + std::pair edge(vertex_descriptor u, + vertex_descriptor v, const Graph &g) { + if (in_degree(v, g) < out_degree(u, g)) { + for (const edge_descriptor &e : in_edges_range(v, g)) { + if (source(e, g) == u) { + return {e, true}; + } + } + } else { + for (const edge_descriptor &e : out_edges_range(u, g)) { + if (target(e, g) == v) { + return {e, true}; + } + } + } + + return {edge_descriptor(), false}; + } + + /* Misc functions that don't actually seem to belong to a formal BGL + concept. */ + static + edge_descriptor null_edge() { return edge_descriptor(); } + + friend + std::pair + inv_adjacent_vertices(vertex_descriptor v, const Graph &g) { + auto in_edge_its = in_edges(v, g); + return {inv_adjacency_iterator(in_edge_its.first), + inv_adjacency_iterator(in_edge_its.second)}; + } + + /* MutableGraph concept functions */ + + friend + std::pair + add_edge(vertex_descriptor u, vertex_descriptor v, Graph &g) { + bool added = true; /* we always allow parallel edges */ + edge_node *e = new edge_node(g.new_serial()); + e->source = Graph::raw(u); + e->target = Graph::raw(v); + e->props.index = g.next_edge_index++; + + Graph::raw(u)->out_edge_list.push_back(*e); + Graph::raw(v)->in_edge_list.push_back(*e); + + g.graph_edge_count++; + return {edge_descriptor(e), added}; + } + + friend + void remove_edge(edge_descriptor e, Graph &g) { + g.graph_edge_count--; + + vertex_node *u = Graph::raw(source(e, g)); + vertex_node *v = Graph::raw(target(e, g)); + + v->in_edge_list.erase(v->in_edge_list.iterator_to(*Graph::raw(e))); + u->out_edge_list.erase(u->out_edge_list.iterator_to(*Graph::raw(e))); + + delete Graph::raw(e); + } + + template + friend + void remove_edge(Iter it, Graph &g) { + remove_edge(*it, g); + } + + template + friend + void remove_out_edge_if(vertex_descriptor v, Predicate pred, Graph &g) { + out_edge_iterator it, ite; + std::tie(it, ite) = out_edges(v, g); + while (it != ite) { + auto jt = it; + ++it; + if (pred(*jt)) { + remove_edge(*jt, g); + } + } + } + + template + friend + void remove_in_edge_if(vertex_descriptor v, Predicate pred, Graph &g) { + in_edge_iterator it, ite; + std::tie(it, ite) = in_edges(v, g); + while (it != ite) { + auto jt = it; + ++it; + if (pred(*jt)) { + remove_edge(*jt, g); + } + } + } + + template + friend + void remove_edge_if(Predicate pred, Graph &g) { + edge_iterator it, ite; + std::tie(it, ite) = edges(g); + while (it != ite) { + auto jt = it; + ++it; + if (pred(*jt)) { + remove_edge(*jt, g); + } + } + } + +private: + /* GCC 4.8 has bugs with lambdas in templated friend functions, so: */ + struct source_match { + source_match(const vertex_descriptor &uu, const Graph &gg) + : u(uu), g(gg) { } + bool operator()(edge_descriptor e) const { return source(e, g) == u; } + const vertex_descriptor &u; + const Graph &g; + }; + + struct target_match { + target_match(const vertex_descriptor &vv, const Graph &gg) + : v(vv), g(gg) { } + bool operator()(edge_descriptor e) const { return target(e, g) == v; } + const vertex_descriptor &v; + const Graph &g; + }; +public: + + /* Note: (u,v) variant needs to remove all (parallel) edges between (u,v). + * + * The edge_descriptor version should be strongly preferred if the + * edge_descriptor is available. + */ + friend + void remove_edge(const vertex_descriptor &u, + const vertex_descriptor &v, + Graph &g) { + if (in_degree(v, g) < out_degree(u, g)) { + remove_in_edge_if(v, source_match(u, g), g); + } else { + remove_out_edge_if(u, target_match(v, g), g); + } + } + + /* VertexListGraph concept functions */ + + friend + vertices_size_type num_vertices(const Graph &g) { + return g.vertices_list.size(); + } + + friend + std::pair vertices(const Graph &g) { + return {vertex_iterator(g.vertices_list.begin()), + vertex_iterator(g.vertices_list.end())}; + } + + /* EdgeListGraph concept functions (aside from those in IncidenceGraph) */ + + friend + edges_size_type num_edges(const Graph &g) { + return g.graph_edge_count; + } + + friend + std::pair edges(const Graph &g) { + vertex_iterator vi, ve; + std::tie(vi, ve) = vertices(g); + + return {edge_iterator(vi, ve), edge_iterator(ve, ve)}; + } + + /* bundled properties functions */ + + vertex_property_type &operator[](vertex_descriptor v) { + return raw(v)->props; + } + + const vertex_property_type &operator[](vertex_descriptor v) const { + return raw(v)->props; + } + + edge_property_type &operator[](edge_descriptor e) { + return raw(e)->props; + } + + const edge_property_type &operator[](edge_descriptor e) const { + return raw(e)->props; + } + + /* PropertyGraph concept functions & helpers */ + + template + struct prop_map : public boost::put_get_helper > { + using value_type = typename std::decay::type; + using reference = R; + using key_type = typename bundle_key_type::type; + + typedef typename boost::lvalue_property_map_tag category; + + prop_map(value_type P_of::*m_in) : member(m_in) { } + + reference operator[](key_type k) const { + return Graph::raw(k)->props.*member; + } + reference operator()(key_type k) const { return (*this)[k]; } + + private: + value_type P_of::*member; + }; + + template + struct prop_map_all : public boost::put_get_helper > { + using value_type = typename std::decay::type; + using reference = R; + using key_type = typename bundle_key_type::type; + + typedef typename boost::lvalue_property_map_tag category; + + reference operator[](key_type k) const { + return Graph::raw(k)->props; + } + reference operator()(key_type k) const { return (*this)[k]; } + }; + + template + friend + prop_map get(P_type P_of::*t, Graph &) { + return prop_map(t); + } + + template + friend + prop_map get(P_type P_of::*t, const Graph &) { + return prop_map(t); + } + + /* We can't seem to use auto/decltype returns here as it seems that the + * templated member functions are not yet visible when the compile is + * evaluating the decltype for the return value. We could probably work + * around it by making this a dummy templated function. */ + friend + prop_map + get(boost::vertex_index_t, Graph &g) { + return get(&VertexPropertyType::index, g); + } + + friend + prop_map + get(boost::vertex_index_t, const Graph &g) { + return get(&VertexPropertyType::index, g); + } + + friend + prop_map + get(boost::edge_index_t, Graph &g) { + return get(&EdgePropertyType::index, g); + } + + friend + prop_map + get(boost::edge_index_t, const Graph &g) { + return get(&EdgePropertyType::index, g); + } + + friend + prop_map_all get(boost::vertex_all_t, Graph &) { + return {}; + } + + friend + prop_map_all get(boost::vertex_all_t, + const Graph &) { + return {}; + } + + friend + prop_map_all get(boost::edge_all_t, Graph &) { + return {}; + } + + friend + prop_map_all get(boost::edge_all_t, + const Graph &) { + return {}; + } + + friend + prop_map_all get(boost::vertex_bundle_t, Graph &) { + return {}; + } + + friend + prop_map_all get(boost::vertex_bundle_t, + const Graph &) { + return {}; + } + + friend + prop_map_all get(boost::edge_bundle_t, Graph &) { + return {}; + } + + friend + prop_map_all get(boost::edge_bundle_t, + const Graph &) { + return {}; + } + + template + friend + auto get(Prop p, Graph &g, K key) -> decltype(get(p, g)[key]) { + return get(p, g)[key]; + } + + template + friend + auto get(Prop p, const Graph &g, K key) -> decltype(get(p, g)[key]) { + return get(p, g)[key]; + } + + template + friend + void put(Prop p, Graph &g, K key, const V &value) { + get(p, g)[key] = value; + } + + /* MutablePropertyGraph concept functions */ + + /* Note: add_vertex(g, vp) allocates a next index value for the vertex + * rather than using the index in vp. i.e., except for in rare coincidences: + * g[add_vertex(g, vp)].index != vp.index + */ + friend + vertex_descriptor add_vertex(const VertexPropertyType &vp, Graph &g) { + vertex_descriptor v = add_vertex(g); + auto i = g[v].index; + g[v] = vp; + g[v].index = i; + + return v; + } + + /* Note: add_edge(u, v, g, vp) allocates a next index value for the edge + * rather than using the index in ep. i.e., except for in rare coincidences: + * g[add_edge(u, v, g, ep)].index != ep.index + */ + friend + std::pair + add_edge(vertex_descriptor u, vertex_descriptor v, + const EdgePropertyType &ep, Graph &g) { + auto e = add_edge(u, v, g); + auto i = g[e.first].index; + g[e.first] = ep; + g[e.first].index = i; + + return e; + } + + /* End MutablePropertyGraph */ + + /** Pack the edge index into a contiguous range [ 0, num_edges(g) ). */ + friend + void renumber_edges(Graph &g) { + g.next_edge_index = 0; + for (const auto &e : edges_range(g)) { + g[e].index = g.next_edge_index++; + } + } + + /** Pack the vertex index into a contiguous range [ 0, num_vertices(g) ). + * Vertices with indices less than N_SPECIAL_VERTICES are not renumbered. + */ + friend + void renumber_vertices(Graph &g) { + DEBUG_PRINTF("renumbering above %zu\n", Graph::N_SPECIAL_VERTICES); + g.next_vertex_index = Graph::N_SPECIAL_VERTICES; + for (const auto &v : vertices_range(g)) { + if (g[v].index < Graph::N_SPECIAL_VERTICES) { + continue; + } + + g[v].index = g.next_vertex_index++; + } + } + + /** Returns what the next allocated vertex index will be. This is an upper + * on the values of index for vertices (vertex removal means that there may + * be gaps). */ + friend + vertices_size_type vertex_index_upper_bound(const Graph &g) { + return g.next_vertex_index; + } + + /** Returns what the next allocated edge index will be. This is an upper on + * the values of index for edges (edge removal means that there may be + * gaps). */ + friend + vertices_size_type edge_index_upper_bound(const Graph &g) { + return g.next_edge_index; + } + + using directed_category = boost::directed_tag; + using edge_parallel_category = boost::allow_parallel_edge_tag; + struct traversal_category : + public virtual boost::bidirectional_graph_tag, + public virtual boost::adjacency_graph_tag, + public virtual boost::vertex_list_graph_tag, + public virtual boost::edge_list_graph_tag { }; + + ue2_graph() = default; + + ue2_graph(ue2_graph &&old) + : next_vertex_index(old.next_vertex_index), + next_edge_index(old.next_edge_index), + graph_edge_count(old.graph_edge_count), + next_serial(old.next_serial) { + using std::swap; + swap(vertices_list, old.vertices_list); + } + + ue2_graph &operator=(ue2_graph &&old) { + next_vertex_index = old.next_vertex_index; + next_edge_index = old.next_edge_index; + graph_edge_count = old.graph_edge_count; + next_serial = old.next_serial; + using std::swap; + swap(vertices_list, old.vertices_list); + return *this; + } + + ~ue2_graph() { + vertices_list.clear_and_dispose(delete_disposer()); + } +}; + +using boost::vertex_index; +using boost::edge_index; + +} + +namespace boost { + +/* Install partial specialisation of property_map - this is required for + * adaptors (like filtered_graph) to know the type of the property maps */ +template +struct property_map::value + >::type > { + typedef decltype(get(std::declval(), + std::declval())) type; + typedef decltype(get(std::declval(), + std::declval())) const_type; +}; + +} +#endif diff --git a/unit/internal/graph.cpp b/unit/internal/graph.cpp index 3ab3326d..3f81ac13 100644 --- a/unit/internal/graph.cpp +++ b/unit/internal/graph.cpp @@ -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 * modification, are permitted provided that the following conditions are met: @@ -29,10 +29,14 @@ #include "config.h" #include "gtest/gtest.h" #include "util/graph.h" +#include "util/ue2_graph.h" #include #include #include +#include + +#include using namespace boost; using namespace std; @@ -167,107 +171,1614 @@ TEST(graph_util, degrees) { ASSERT_TRUE( has_proper_successor(d, g)); ASSERT_FALSE(has_proper_successor(e, g)); ASSERT_TRUE( has_proper_successor(f, g)); - - ASSERT_TRUE( hasGreaterInDegree(0, a, g)); - ASSERT_FALSE(hasGreaterInDegree(1, a, g)); - ASSERT_TRUE( hasGreaterInDegree(2, b, g)); - ASSERT_FALSE(hasGreaterInDegree(3, b, g)); - ASSERT_TRUE( hasGreaterInDegree(1, c, g)); - ASSERT_FALSE(hasGreaterInDegree(2, c, g)); - ASSERT_FALSE(hasGreaterInDegree(0, d, g)); - ASSERT_TRUE( hasGreaterInDegree(1, e, g)); - ASSERT_FALSE(hasGreaterInDegree(2, e, g)); - ASSERT_FALSE(hasGreaterInDegree(0, f, g)); - - ASSERT_TRUE( hasGreaterOutDegree(0, a, g)); - ASSERT_FALSE(hasGreaterOutDegree(1, a, g)); - ASSERT_TRUE( hasGreaterOutDegree(1, b, g)); - ASSERT_FALSE(hasGreaterOutDegree(2, b, g)); - ASSERT_FALSE(hasGreaterOutDegree(0, c, g)); - ASSERT_TRUE( hasGreaterOutDegree(0, d, g)); - ASSERT_FALSE(hasGreaterOutDegree(1, d, g)); - ASSERT_TRUE( hasGreaterOutDegree(0, e, g)); - ASSERT_FALSE(hasGreaterOutDegree(1, e, g)); - ASSERT_TRUE( hasGreaterOutDegree(2, f, g)); - ASSERT_FALSE(hasGreaterOutDegree(3, f, g)); } -TEST(graph_util, in_degree_equal_to_1) { - unit_graph g; +struct SimpleV { + size_t index; + string test_v = "SimpleV"; +}; - unit_vertex a = add_vertex(g); - unit_vertex b = add_vertex(g); - unit_vertex c = add_vertex(g); - unit_vertex d = add_vertex(g); +struct SimpleE { + size_t index; + string test_e = "SimpleE"; +}; - ASSERT_TRUE(in_degree_equal_to(a, g, 0)); - ASSERT_FALSE(in_degree_equal_to(a, g, 1)); - ASSERT_FALSE(in_degree_equal_to(a, g, 2)); +struct SimpleG : public ue2_graph { +}; + +TEST(ue2_graph, graph_concept) { + static_assert(std::is_same::vertex_descriptor>::value, + "vertex_descriptor"); + static_assert(std::is_same::edge_descriptor>::value, + "edge_descriptor"); + static_assert(std::is_same::directed_category>::value, + "directed_category"); + static_assert(std::is_same::edge_parallel_category>::value, + "edge_parallel_category"); + static_assert(std::is_same::traversal_category>::value, + "traversal_category"); + + UNUSED SimpleG::vertex_descriptor n = SimpleG::null_vertex(); + + BOOST_CONCEPT_ASSERT((GraphConcept)); +} + +TEST(ue2_graph, vertex_list_concept) { + BOOST_CONCEPT_ASSERT((VertexListGraphConcept)); +} + +TEST(ue2_graph, edge_list_concept) { + BOOST_CONCEPT_ASSERT((EdgeListGraphConcept)); +} + +TEST(ue2_graph, incidence_concept) { + BOOST_CONCEPT_ASSERT((IncidenceGraphConcept)); +} + +TEST(ue2_graph, bidi_concept) { + BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept)); +} + +TEST(ue2_graph, mutable_concept) { + BOOST_CONCEPT_ASSERT((MutableGraphConcept)); +} + +TEST(ue2_graph, property_concept) { + static_assert(std::is_same::value, + "vertex_property_type"); + static_assert(std::is_same::value, + "edge_property_type"); + + /* Although documented as part of the MutablePropertyGraph concept, + * (vertex|edge)_property_type don't appear to exist in the traits for any + * existing graph types and the typedefs are not installed by default */ + + // static_assert(std::is_same< + // typename graph_traits::vertex_property_type, + // SimpleV>::value, + // "vertex_property_type"); + // static_assert(std::is_same< + // typename graph_traits::edge_property_type, + // SimpleE>::value, + // "edge_property_type"); + + /* However, there does seem to be an undocumented templated structure + * paralleling the main graph_traits */ + static_assert(std::is_same< + typename vertex_property_type::type, + SimpleV>::value, + "vertex_property_type"); + static_assert(std::is_same< + typename edge_property_type::type, + SimpleE>::value, + "edge_property_type"); + + BOOST_CONCEPT_ASSERT((VertexMutablePropertyGraphConcept)); + BOOST_CONCEPT_ASSERT((EdgeMutablePropertyGraphConcept)); +} + +TEST(ue2_graph, add_vertex) { + SimpleG g; + SimpleG::vertex_descriptor a = add_vertex(g); + ASSERT_NE(SimpleG::null_vertex(), a); +} + +TEST(ue2_graph, add_and_remove_vertex) { + SimpleG g; + ASSERT_EQ(0U, num_vertices(g)); + + SimpleG::vertex_descriptor a = add_vertex(g); + ASSERT_EQ(1U, num_vertices(g)); + ASSERT_NE(SimpleG::null_vertex(), a); + auto p = vertices(g); + ASSERT_NE(p.first, p.second); + ASSERT_EQ(a, *p.first); + ++p.first; + ASSERT_EQ(p.first, p.second); + + remove_vertex(a, g); + ASSERT_EQ(0U, num_vertices(g)); + auto q = vertices(g); + ASSERT_EQ(q.first, q.second); +} + +TEST(ue2_graph, add_edge) { + SimpleG g; + SimpleG::vertex_descriptor a = add_vertex(g); + ASSERT_NE(SimpleG::null_vertex(), a); + SimpleG::vertex_descriptor b = add_vertex(g); + ASSERT_NE(SimpleG::null_vertex(), b); + ASSERT_NE(a, b); + auto p = add_edge(a, b, g); + ASSERT_TRUE(p.second); + ASSERT_EQ(1U, num_edges(g)); + + ASSERT_EQ(a, source(p.first, g)); + ASSERT_EQ(b, target(p.first, g)); + + auto q = edge(a, b, g); + ASSERT_TRUE(q.second); + ASSERT_EQ(p.second, q.first); +} + +TEST(ue2_graph, add_remove_edge1) { + SimpleG g; + SimpleG::vertex_descriptor a = add_vertex(g); + ASSERT_NE(SimpleG::null_vertex(), a); + SimpleG::vertex_descriptor b = add_vertex(g); + ASSERT_NE(SimpleG::null_vertex(), b); + ASSERT_NE(a, b); + auto p = add_edge(a, b, g); + ASSERT_TRUE(p.second); + ASSERT_EQ(1U, num_edges(g)); + + ASSERT_EQ(a, source(p.first, g)); + ASSERT_EQ(b, target(p.first, g)); + + remove_edge(p.first, g); + auto q = edge(a, b, g); + ASSERT_FALSE(q.second); + ASSERT_EQ(q.first, SimpleG::null_edge()); + ASSERT_EQ(0U, num_edges(g)); +} + +TEST(ue2_graph, add_remove_edge2) { + SimpleG g; + SimpleG::vertex_descriptor a = add_vertex(g); + ASSERT_NE(SimpleG::null_vertex(), a); + SimpleG::vertex_descriptor b = add_vertex(g); + ASSERT_NE(SimpleG::null_vertex(), b); + ASSERT_NE(a, b); + auto p = add_edge(a, b, g); + ASSERT_TRUE(p.second); + ASSERT_EQ(1U, num_edges(g)); + + ASSERT_EQ(a, source(p.first, g)); + ASSERT_EQ(b, target(p.first, g)); + + remove_edge(a, b, g); + auto q = edge(a, b, g); + ASSERT_FALSE(q.second); + ASSERT_EQ(q.first, SimpleG::null_edge()); + ASSERT_EQ(0U, num_edges(g)); +} + +TEST(ue2_graph, add_edge_clear1) { + SimpleG g; + SimpleG::vertex_descriptor a = add_vertex(g); + ASSERT_NE(SimpleG::null_vertex(), a); + SimpleG::vertex_descriptor b = add_vertex(g); + ASSERT_NE(SimpleG::null_vertex(), b); + ASSERT_NE(a, b); + auto p = add_edge(a, b, g); + ASSERT_TRUE(p.second); + ASSERT_EQ(1U, num_edges(g)); + + ASSERT_EQ(a, source(p.first, g)); + ASSERT_EQ(b, target(p.first, g)); + + clear_vertex(a, g); + auto q = edge(a, b, g); + ASSERT_FALSE(q.second); + ASSERT_EQ(q.first, SimpleG::null_edge()); + ASSERT_EQ(0U, num_edges(g)); +} + +TEST(ue2_graph, add_edge_clear2) { + SimpleG g; + SimpleG::vertex_descriptor a = add_vertex(g); + ASSERT_NE(SimpleG::null_vertex(), a); + SimpleG::vertex_descriptor b = add_vertex(g); + ASSERT_NE(SimpleG::null_vertex(), b); + ASSERT_NE(a, b); + auto p = add_edge(a, b, g); + ASSERT_TRUE(p.second); + ASSERT_EQ(1U, num_edges(g)); + + ASSERT_EQ(a, source(p.first, g)); + ASSERT_EQ(b, target(p.first, g)); + + clear_vertex(b, g); + auto q = edge(a, b, g); + ASSERT_FALSE(q.second); + ASSERT_EQ(q.first, SimpleG::null_edge()); + ASSERT_EQ(0U, num_edges(g)); +} + +TEST(ue2_graph, add_edge_clear_out) { + SimpleG g; + SimpleG::vertex_descriptor a = add_vertex(g); + ASSERT_NE(SimpleG::null_vertex(), a); + SimpleG::vertex_descriptor b = add_vertex(g); + ASSERT_NE(SimpleG::null_vertex(), b); + ASSERT_NE(a, b); + auto p = add_edge(a, b, g); + ASSERT_TRUE(p.second); + ASSERT_EQ(1U, num_edges(g)); + + ASSERT_EQ(a, source(p.first, g)); + ASSERT_EQ(b, target(p.first, g)); + + clear_out_edges(a, g); + auto q = edge(a, b, g); + ASSERT_FALSE(q.second); + ASSERT_EQ(q.first, SimpleG::null_edge()); + ASSERT_EQ(0U, num_edges(g)); +} + +TEST(ue2_graph, add_edge_clear_in) { + SimpleG g; + SimpleG::vertex_descriptor a = add_vertex(g); + ASSERT_NE(SimpleG::null_vertex(), a); + SimpleG::vertex_descriptor b = add_vertex(g); + ASSERT_NE(SimpleG::null_vertex(), b); + ASSERT_NE(a, b); + auto p = add_edge(a, b, g); + ASSERT_TRUE(p.second); + ASSERT_EQ(1U, num_edges(g)); + + ASSERT_EQ(a, source(p.first, g)); + ASSERT_EQ(b, target(p.first, g)); + + clear_in_edges(b, g); + auto q = edge(a, b, g); + ASSERT_FALSE(q.second); + ASSERT_EQ(q.first, SimpleG::null_edge()); + ASSERT_EQ(0U, num_edges(g)); +} + +TEST(ue2_graph, add_remove_edge_iter) { + SimpleG g; + SimpleG::vertex_descriptor a = add_vertex(g); + ASSERT_NE(SimpleG::null_vertex(), a); + SimpleG::vertex_descriptor b = add_vertex(g); + ASSERT_NE(SimpleG::null_vertex(), b); + ASSERT_NE(a, b); + auto p = add_edge(a, b, g); + ASSERT_TRUE(p.second); + ASSERT_EQ(1U, num_edges(g)); + + ASSERT_EQ(a, source(p.first, g)); + ASSERT_EQ(b, target(p.first, g)); + + remove_edge(edges(g).first, g); + auto q = edge(a, b, g); + ASSERT_FALSE(q.second); + ASSERT_EQ(q.first, SimpleG::null_edge()); + ASSERT_EQ(0U, num_edges(g)); +} + +TEST(ue2_graph, vertices_0) { + SimpleG g; + auto p = vertices(g); + ASSERT_EQ(p.first, p.second); +} + +TEST(ue2_graph, vertices_1) { + SimpleG g; + SimpleG::vertex_iterator vi; + SimpleG::vertex_iterator ve; + auto a = add_vertex(g); + + ASSERT_EQ(1U, num_vertices(g)); + tie(vi, ve) = vertices(g); + ASSERT_EQ(a, *vi++); + ASSERT_EQ(vi, ve); + + auto b = add_vertex(g); + auto c = add_vertex(g); + auto d = add_vertex(g); + + ASSERT_EQ(4U, num_vertices(g)); + tie(vi, ve) = vertices(g); + ASSERT_EQ(a, *vi++); + ASSERT_EQ(b, *vi++); + ASSERT_EQ(c, *vi++); + ASSERT_EQ(d, *vi++); + ASSERT_EQ(vi, ve); + + remove_vertex(c, g); + + ASSERT_EQ(3U, num_vertices(g)); + tie(vi, ve) = vertices(g); + ASSERT_EQ(a, *vi++); + ASSERT_EQ(b, *vi++); + ASSERT_EQ(d, *vi++); + ASSERT_EQ(vi, ve); + + remove_vertex(a, g); + + ASSERT_EQ(2U, num_vertices(g)); + tie(vi, ve) = vertices(g); + ASSERT_EQ(b, *vi++); + ASSERT_EQ(d, *vi++); + ASSERT_EQ(vi, ve); + + auto e = add_vertex(g); + + ASSERT_EQ(3U, num_vertices(g)); + tie(vi, ve) = vertices(g); + ASSERT_EQ(b, *vi++); + ASSERT_EQ(d, *vi++); + ASSERT_EQ(e, *vi++); + ASSERT_EQ(vi, ve); + + remove_vertex(e, g); + + ASSERT_EQ(2U, num_vertices(g)); + tie(vi, ve) = vertices(g); + ASSERT_EQ(b, *vi++); + ASSERT_EQ(d, *vi++); + ASSERT_EQ(vi, ve); + + remove_vertex(b, g); + remove_vertex(d, g); + + ASSERT_EQ(0U, num_vertices(g)); + tie(vi, ve) = vertices(g); + ASSERT_EQ(vi, ve); +} + +TEST(ue2_graph, out_edges_1) { + SimpleG g; + auto a = add_vertex(g); + + ASSERT_EQ(1U, num_vertices(g)); + ASSERT_EQ(0U, out_degree(a, g)); + + SimpleG::out_edge_iterator ei; + SimpleG::out_edge_iterator ee; + + tie(ei, ee) = out_edges(a, g); + ASSERT_TRUE(ei == ee); + + auto p = add_edge(a, a, g); + ASSERT_TRUE(p.second); + ASSERT_EQ(1U, num_edges(g)); + SimpleG::edge_descriptor e1 = p.first; + + ASSERT_EQ(1U, out_degree(a, g)); + tie(ei, ee) = out_edges(a, g); + ASSERT_EQ(e1, *ei++); + ASSERT_EQ(ei, ee); + + p = add_edge(a, a, g); + ASSERT_TRUE(p.second); + ASSERT_EQ(2U, num_edges(g)); + SimpleG::edge_descriptor e2 = p.first; + + ASSERT_EQ(2U, out_degree(a, g)); + tie(ei, ee) = out_edges(a, g); + ASSERT_EQ(e1, *ei++); + ASSERT_EQ(e2, *ei++); + ASSERT_EQ(ei, ee); +} + +TEST(ue2_graph, out_edges_2) { + SimpleG g; + auto a = add_vertex(g); + auto b = add_vertex(g); + auto c = add_vertex(g); + + ASSERT_EQ(3U, num_vertices(g)); + ASSERT_EQ(0U, out_degree(a, g)); + + SimpleG::out_edge_iterator ei; + SimpleG::out_edge_iterator ee; + + tie(ei, ee) = out_edges(a, g); + ASSERT_TRUE(ei == ee); + + auto p = add_edge(a, b, g); + ASSERT_TRUE(p.second); + ASSERT_EQ(1U, num_edges(g)); + SimpleG::edge_descriptor e1 = p.first; + + ASSERT_EQ(1U, out_degree(a, g)); + tie(ei, ee) = out_edges(a, g); + ASSERT_EQ(e1, *ei++); + ASSERT_EQ(ei, ee); + + p = add_edge(a, c, g); + ASSERT_TRUE(p.second); + ASSERT_EQ(2U, num_edges(g)); + SimpleG::edge_descriptor e2 = p.first; + + ASSERT_EQ(2U, out_degree(a, g)); + tie(ei, ee) = out_edges(a, g); + ASSERT_EQ(e1, *ei++); + ASSERT_EQ(e2, *ei++); + ASSERT_EQ(ei, ee); + + p = add_edge(c, b, g); + ASSERT_TRUE(p.second); + ASSERT_EQ(3U, num_edges(g)); + + ASSERT_EQ(2U, out_degree(a, g)); + tie(ei, ee) = out_edges(a, g); + ASSERT_EQ(e1, *ei++); + ASSERT_EQ(e2, *ei++); + ASSERT_EQ(ei, ee); + + p = add_edge(b, a, g); + ASSERT_TRUE(p.second); + ASSERT_EQ(4U, num_edges(g)); + + ASSERT_EQ(2U, out_degree(a, g)); + tie(ei, ee) = out_edges(a, g); + ASSERT_EQ(e1, *ei++); + ASSERT_EQ(e2, *ei++); + ASSERT_EQ(ei, ee); + + remove_edge(a, c, g); + ASSERT_EQ(3U, num_edges(g)); + + ASSERT_EQ(1U, out_degree(a, g)); + tie(ei, ee) = out_edges(a, g); + ASSERT_EQ(e1, *ei++); + ASSERT_EQ(ei, ee); + + p = add_edge(a, a, g); + ASSERT_EQ(4U, num_edges(g)); + ASSERT_TRUE(p.second); + SimpleG::edge_descriptor e3 = p.first; + + ASSERT_EQ(2U, out_degree(a, g)); + tie(ei, ee) = out_edges(a, g); + ASSERT_EQ(e1, *ei++); + ASSERT_EQ(e3, *ei++); + ASSERT_EQ(ei, ee); + + clear_out_edges(a, g); + ASSERT_EQ(2U, num_edges(g)); + + ASSERT_EQ(0U, out_degree(a, g)); + tie(ei, ee) = out_edges(a, g); + ASSERT_EQ(ei, ee); +} + +TEST(ue2_graph, in_edges_1) { + SimpleG g; + auto a = add_vertex(g); + + ASSERT_EQ(1U, num_vertices(g)); + ASSERT_EQ(0U, in_degree(a, g)); + + SimpleG::in_edge_iterator ei; + SimpleG::in_edge_iterator ee; + + tie(ei, ee) = in_edges(a, g); + ASSERT_TRUE(ei == ee); + + auto p = add_edge(a, a, g); + ASSERT_TRUE(p.second); + ASSERT_EQ(1U, num_edges(g)); + SimpleG::edge_descriptor e1 = p.first; + + ASSERT_EQ(1U, in_degree(a, g)); + tie(ei, ee) = in_edges(a, g); + ASSERT_EQ(e1, *ei++); + ASSERT_EQ(ei, ee); + + p = add_edge(a, a, g); + ASSERT_TRUE(p.second); + ASSERT_EQ(2U, num_edges(g)); + SimpleG::edge_descriptor e2 = p.first; + + ASSERT_EQ(2U, in_degree(a, g)); + tie(ei, ee) = in_edges(a, g); + ASSERT_EQ(e1, *ei++); + ASSERT_EQ(e2, *ei++); + ASSERT_EQ(ei, ee); +} + +TEST(ue2_graph, in_edges_2) { + SimpleG g; + auto a = add_vertex(g); + auto b = add_vertex(g); + auto c = add_vertex(g); + + ASSERT_EQ(3U, num_vertices(g)); + ASSERT_EQ(0U, in_degree(a, g)); + + SimpleG::in_edge_iterator ei; + SimpleG::in_edge_iterator ee; + + tie(ei, ee) = in_edges(a, g); + ASSERT_TRUE(ei == ee); + + auto p = add_edge(b, a, g); + ASSERT_TRUE(p.second); + ASSERT_EQ(1U, num_edges(g)); + SimpleG::edge_descriptor e1 = p.first; + + ASSERT_EQ(1U, in_degree(a, g)); + tie(ei, ee) = in_edges(a, g); + ASSERT_EQ(e1, *ei++); + ASSERT_EQ(ei, ee); + + p = add_edge(c, a, g); + ASSERT_TRUE(p.second); + ASSERT_EQ(2U, num_edges(g)); + SimpleG::edge_descriptor e2 = p.first; + + ASSERT_EQ(2U, in_degree(a, g)); + tie(ei, ee) = in_edges(a, g); + ASSERT_EQ(e1, *ei++); + ASSERT_EQ(e2, *ei++); + ASSERT_EQ(ei, ee); + + p = add_edge(c, b, g); + ASSERT_TRUE(p.second); + ASSERT_EQ(3U, num_edges(g)); + + ASSERT_EQ(2U, in_degree(a, g)); + tie(ei, ee) = in_edges(a, g); + ASSERT_EQ(e1, *ei++); + ASSERT_EQ(e2, *ei++); + ASSERT_EQ(ei, ee); + + p = add_edge(a, b, g); + ASSERT_TRUE(p.second); + ASSERT_EQ(4U, num_edges(g)); + + ASSERT_EQ(2U, in_degree(a, g)); + tie(ei, ee) = in_edges(a, g); + ASSERT_EQ(e1, *ei++); + ASSERT_EQ(e2, *ei++); + ASSERT_EQ(ei, ee); + + remove_edge(c, a, g); + ASSERT_EQ(3U, num_edges(g)); + + ASSERT_EQ(1U, in_degree(a, g)); + tie(ei, ee) = in_edges(a, g); + ASSERT_EQ(e1, *ei++); + ASSERT_EQ(ei, ee); + + p = add_edge(a, a, g); + ASSERT_EQ(4U, num_edges(g)); + ASSERT_TRUE(p.second); + SimpleG::edge_descriptor e3 = p.first; + + ASSERT_EQ(2U, in_degree(a, g)); + tie(ei, ee) = in_edges(a, g); + ASSERT_EQ(e1, *ei++); + ASSERT_EQ(e3, *ei++); + ASSERT_EQ(ei, ee); + + clear_in_edges(a, g); + ASSERT_EQ(2U, num_edges(g)); + + ASSERT_EQ(0U, in_degree(a, g)); + tie(ei, ee) = in_edges(a, g); + ASSERT_EQ(ei, ee); +} + +TEST(ue2_graph, parallel_1) { + SimpleG g; + SimpleG::vertex_iterator vi; + SimpleG::vertex_iterator ve; + auto a = add_vertex(g); + + ASSERT_EQ(1U, num_vertices(g)); + ASSERT_EQ(0U, out_degree(a, g)); + + SimpleG::out_edge_iterator ei; + SimpleG::out_edge_iterator ee; + + tie(ei, ee) = out_edges(a, g); + ASSERT_TRUE(ei == ee); + + auto p = add_edge(a, a, g); + ASSERT_TRUE(p.second); + ASSERT_EQ(1U, num_edges(g)); + SimpleG::edge_descriptor e1 = p.first; + + ASSERT_EQ(1U, out_degree(a, g)); + tie(ei, ee) = out_edges(a, g); + ASSERT_EQ(e1, *ei++); + ASSERT_EQ(ei, ee); + + p = add_edge(a, a, g); + ASSERT_TRUE(p.second); + ASSERT_EQ(2U, num_edges(g)); + SimpleG::edge_descriptor e2 = p.first; + + ASSERT_EQ(2U, out_degree(a, g)); + tie(ei, ee) = out_edges(a, g); + ASSERT_EQ(e1, *ei++); + ASSERT_EQ(e2, *ei++); + ASSERT_EQ(ei, ee); + + remove_edge(e1, g); + + ASSERT_EQ(1U, out_degree(a, g)); + tie(ei, ee) = out_edges(a, g); + ASSERT_EQ(e2, *ei++); + ASSERT_EQ(ei, ee); + + p = add_edge(a, a, g); + ASSERT_TRUE(p.second); + ASSERT_EQ(2U, num_edges(g)); + SimpleG::edge_descriptor e3 = p.first; + + ASSERT_EQ(2U, out_degree(a, g)); + tie(ei, ee) = out_edges(a, g); + ASSERT_EQ(e2, *ei++); + ASSERT_EQ(e3, *ei++); + ASSERT_EQ(ei, ee); + + remove_edge(a, a, g); + ASSERT_EQ(0U, out_degree(a, g)); + tie(ei, ee) = out_edges(a, g); + ASSERT_EQ(ei, ee); +} + +TEST(ue2_graph, edges_0a) { + SimpleG g; + auto p = edges(g); + ASSERT_EQ(p.first, p.second); +} + +TEST(ue2_graph, edges_0b) { + SimpleG g; + add_vertex(g); + ASSERT_EQ(1U, num_vertices(g)); + auto p = edges(g); + ASSERT_EQ(p.first, p.second); +} + +TEST(ue2_graph, edges_0c) { + SimpleG g; + add_vertex(g); + add_vertex(g); + ASSERT_EQ(2U, num_vertices(g)); + auto p = edges(g); + ASSERT_EQ(p.first, p.second); +} + +TEST(ue2_graph, edges_1a) { + SimpleG g; + ASSERT_EQ(0U, num_edges(g)); + + auto v = add_vertex(g); + + ASSERT_EQ(0U, num_edges(g)); + auto e1 = add_edge(v, v, g).first; + + SimpleG::edge_iterator ei, ee; + + ASSERT_EQ(1U, num_edges(g)); + tie(ei, ee) = edges(g); + ASSERT_EQ(e1, *ei++); + ASSERT_EQ(ee, ei); + + remove_edge(e1, g); + + ASSERT_EQ(0U, num_edges(g)); + tie(ei, ee) = edges(g); + ASSERT_EQ(ee, ei); +} + +TEST(ue2_graph, edges_1b) { + SimpleG g; + ASSERT_EQ(0U, num_edges(g)); + + auto u = add_vertex(g); + auto v = add_vertex(g); + + ASSERT_EQ(0U, num_edges(g)); + auto e1 = add_edge(u, v, g).first; + + SimpleG::edge_iterator ei, ee; + + ASSERT_EQ(1U, num_edges(g)); + tie(ei, ee) = edges(g); + ASSERT_EQ(e1, *ei++); + ASSERT_EQ(ee, ei); + + remove_edge(e1, g); + + ASSERT_EQ(0U, num_edges(g)); + tie(ei, ee) = edges(g); + ASSERT_EQ(ee, ei); +} + +TEST(ue2_graph, edges_1c) { + SimpleG g; + ASSERT_EQ(0U, num_edges(g)); + + auto u = add_vertex(g); + auto v = add_vertex(g); + + ASSERT_EQ(0U, num_edges(g)); + auto e1 = add_edge(v, u, g).first; + + SimpleG::edge_iterator ei, ee; + + ASSERT_EQ(1U, num_edges(g)); + tie(ei, ee) = edges(g); + ASSERT_EQ(e1, *ei++); + ASSERT_EQ(ee, ei); + + remove_edge(e1, g); + + ASSERT_EQ(0U, num_edges(g)); + tie(ei, ee) = edges(g); + ASSERT_EQ(ee, ei); +} + +TEST(ue2_graph, edges_1d) { + SimpleG g; + ASSERT_EQ(0U, num_edges(g)); + + UNUSED auto u = add_vertex(g); + UNUSED auto v = add_vertex(g); + auto w = add_vertex(g); + auto x = add_vertex(g); + UNUSED auto y = add_vertex(g); + UNUSED auto z = add_vertex(g); + + ASSERT_EQ(0U, num_edges(g)); + auto e1 = add_edge(w, x, g).first; + + SimpleG::edge_iterator ei, ee; + + ASSERT_EQ(1U, num_edges(g)); + tie(ei, ee) = edges(g); + ASSERT_EQ(e1, *ei++); + ASSERT_EQ(ee, ei); + + remove_edge(e1, g); + + ASSERT_EQ(0U, num_edges(g)); + tie(ei, ee) = edges(g); + ASSERT_EQ(ee, ei); +} + +TEST(ue2_graph, edges_2a) { + SimpleG g; + ASSERT_EQ(0U, num_edges(g)); + + auto v = add_vertex(g); + + ASSERT_EQ(0U, num_edges(g)); + auto e1 = add_edge(v, v, g).first; + auto e2 = add_edge(v, v, g).first; + + SimpleG::edge_iterator ei, ee; + + ASSERT_EQ(2U, num_edges(g)); + tie(ei, ee) = edges(g); + ASSERT_EQ(e1, *ei++); + ASSERT_EQ(e2, *ei++); + ASSERT_EQ(ee, ei); + + remove_edge(e1, g); + + ASSERT_EQ(1U, num_edges(g)); + tie(ei, ee) = edges(g); + ASSERT_EQ(e2, *ei++); + ASSERT_EQ(ee, ei); + + remove_edge(e2, g); + + ASSERT_EQ(0U, num_edges(g)); + tie(ei, ee) = edges(g); + ASSERT_EQ(ee, ei); +} + +TEST(ue2_graph, edges_2b) { + SimpleG g; + ASSERT_EQ(0U, num_edges(g)); + + auto u = add_vertex(g); + auto v = add_vertex(g); + + ASSERT_EQ(0U, num_edges(g)); + auto e1 = add_edge(u, v, g).first; + auto e2 = add_edge(v, u, g).first; + + SimpleG::edge_iterator ei, ee; + + ASSERT_EQ(2U, num_edges(g)); + tie(ei, ee) = edges(g); + ASSERT_EQ(e1, *ei++); + ASSERT_EQ(e2, *ei++); + ASSERT_EQ(ee, ei); + + remove_edge(e1, g); + + ASSERT_EQ(1U, num_edges(g)); + tie(ei, ee) = edges(g); + ASSERT_EQ(e2, *ei++); + ASSERT_EQ(ee, ei); + + remove_edge(e2, g); + + ASSERT_EQ(0U, num_edges(g)); + tie(ei, ee) = edges(g); + ASSERT_EQ(ee, ei); +} + +TEST(ue2_graph, edges_2c) { + SimpleG g; + ASSERT_EQ(0U, num_edges(g)); + + UNUSED auto s = add_vertex(g); + UNUSED auto t = add_vertex(g); + auto u = add_vertex(g); + UNUSED auto v = add_vertex(g); + auto w = add_vertex(g); + auto x = add_vertex(g); + UNUSED auto y = add_vertex(g); + UNUSED auto z = add_vertex(g); + + ASSERT_EQ(0U, num_edges(g)); + auto e1 = add_edge(w, x, g).first; + auto e2 = add_edge(u, x, g).first; + + SimpleG::edge_iterator ei, ee; + + ASSERT_EQ(2U, num_edges(g)); + tie(ei, ee) = edges(g); + ASSERT_EQ(e2, *ei++); + ASSERT_EQ(e1, *ei++); + ASSERT_EQ(ee, ei); + + clear_in_edges(x, g); + + ASSERT_EQ(0U, num_edges(g)); + tie(ei, ee) = edges(g); + ASSERT_EQ(ee, ei); +} + +TEST(ue2_graph, edges_3a) { + SimpleG g; + ASSERT_EQ(0U, num_edges(g)); + + UNUSED auto s = add_vertex(g); + UNUSED auto t = add_vertex(g); + auto u = add_vertex(g); + auto v = add_vertex(g); + auto w = add_vertex(g); + auto x = add_vertex(g); + UNUSED auto y = add_vertex(g); + auto z = add_vertex(g); + + ASSERT_EQ(0U, num_edges(g)); + auto e1 = add_edge(w, x, g).first; + auto e2 = add_edge(u, v, g).first; + auto e3 = add_edge(u, z, g).first; + + SimpleG::edge_iterator ei, ee; + + ASSERT_EQ(3U, num_edges(g)); + tie(ei, ee) = edges(g); + ASSERT_EQ(e2, *ei++); + ASSERT_EQ(e3, *ei++); + ASSERT_EQ(e1, *ei++); + ASSERT_EQ(ee, ei); + + remove_edge(e1, g); + + ASSERT_EQ(2U, num_edges(g)); + clear_out_edges(u, g); + + ASSERT_EQ(0U, num_edges(g)); + + tie(ei, ee) = edges(g); + ASSERT_EQ(ee, ei); +} + +TEST(ue2_graph, degree) { + SimpleG g; + auto a = add_vertex(g); + auto b = add_vertex(g); + auto c = add_vertex(g); + auto d = add_vertex(g); + + add_edge(a, b, g); + add_edge(a, c, g); + add_edge(a, d, g); + + ASSERT_EQ(3U, degree(a, g)); + ASSERT_EQ(1U, degree(b, g)); + ASSERT_EQ(1U, degree(c, g)); + ASSERT_EQ(1U, degree(d, g)); + + add_edge(b, c, g); + + ASSERT_EQ(3U, degree(a, g)); + ASSERT_EQ(2U, degree(b, g)); + ASSERT_EQ(2U, degree(c, g)); + ASSERT_EQ(1U, degree(d, g)); + + add_edge(d, d, g); + ASSERT_EQ(3U, degree(a, g)); + ASSERT_EQ(2U, degree(b, g)); + ASSERT_EQ(2U, degree(c, g)); + ASSERT_EQ(3U, degree(d, g)); add_edge(b, a, g); + ASSERT_EQ(4U, degree(a, g)); + ASSERT_EQ(3U, degree(b, g)); + ASSERT_EQ(2U, degree(c, g)); + ASSERT_EQ(3U, degree(d, g)); - ASSERT_FALSE(in_degree_equal_to(a, g, 0)); - ASSERT_TRUE(in_degree_equal_to(a, g, 1)); - ASSERT_FALSE(in_degree_equal_to(a, g, 2)); + add_edge(b, a, g); + ASSERT_EQ(5U, degree(a, g)); + ASSERT_EQ(4U, degree(b, g)); + ASSERT_EQ(2U, degree(c, g)); + ASSERT_EQ(3U, degree(d, g)); - add_edge(c, a, g); - - ASSERT_FALSE(in_degree_equal_to(a, g, 0)); - ASSERT_FALSE(in_degree_equal_to(a, g, 1)); - ASSERT_TRUE(in_degree_equal_to(a, g, 2)); - - add_edge(d, a, g); - - ASSERT_FALSE(in_degree_equal_to(a, g, 0)); - ASSERT_FALSE(in_degree_equal_to(a, g, 1)); - ASSERT_FALSE(in_degree_equal_to(a, g, 2)); + add_edge(d, d, g); + ASSERT_EQ(5U, degree(a, g)); + ASSERT_EQ(4U, degree(b, g)); + ASSERT_EQ(2U, degree(c, g)); + ASSERT_EQ(5U, degree(d, g)); } -TEST(graph_util, edge_by_target_1) { - unit_graph g; +TEST(ue2_graph, adj) { + SimpleG g; + auto a = add_vertex(g); + auto b = add_vertex(g); + auto c = add_vertex(g); + auto d = add_vertex(g); - unit_vertex a = add_vertex(g); - unit_vertex b = add_vertex(g); - unit_vertex c = add_vertex(g); + add_edge(a, b, g); + add_edge(a, c, g); + add_edge(a, d, g); + add_edge(b, a, g); + add_edge(b, b, g); - ASSERT_FALSE(edge_by_target(a, a, g).second); - ASSERT_FALSE(edge_by_target(a, b, g).second); - ASSERT_FALSE(edge_by_target(a, c, g).second); - ASSERT_FALSE(edge_by_target(b, a, g).second); - ASSERT_FALSE(edge_by_target(c, b, g).second); + SimpleG::adjacency_iterator ai, ae; + tie(ai, ae) = adjacent_vertices(a, g); + ASSERT_EQ(b, *ai++); + ASSERT_EQ(c, *ai++); + ASSERT_EQ(d, *ai++); + ASSERT_EQ(ai, ae); - unit_edge ab = add_edge(a, b, g).first; + tie(ai, ae) = adjacent_vertices(b, g); + ASSERT_EQ(a, *ai++); + ASSERT_EQ(b, *ai++); + ASSERT_EQ(ai, ae); - ASSERT_FALSE(edge_by_target(a, a, g).second); - ASSERT_TRUE(edge_by_target(a, b, g).second); - ASSERT_TRUE(ab == edge_by_target(a, b, g).first); - ASSERT_FALSE(edge_by_target(a, c, g).second); - ASSERT_FALSE(edge_by_target(b, a, g).second); - ASSERT_FALSE(edge_by_target(b, b, g).second); - ASSERT_FALSE(edge_by_target(c, b, g).second); + tie(ai, ae) = adjacent_vertices(c, g); + ASSERT_EQ(ai, ae); - unit_edge cb = add_edge(c, b, g).first; - - ASSERT_FALSE(edge_by_target(a, a, g).second); - ASSERT_TRUE(edge_by_target(a, b, g).second); - ASSERT_TRUE(ab == edge_by_target(a, b, g).first); - ASSERT_FALSE(edge_by_target(a, c, g).second); - ASSERT_FALSE(edge_by_target(b, a, g).second); - ASSERT_FALSE(edge_by_target(b, b, g).second); - ASSERT_TRUE(edge_by_target(c, b, g).second); - ASSERT_TRUE(cb == edge_by_target(c, b, g).first); - - unit_edge aa = add_edge(a, a, g).first; - unit_edge bb = add_edge(b, b, g).first; - - ASSERT_TRUE(edge_by_target(a, a, g).second); - ASSERT_TRUE(aa == edge_by_target(a, a, g).first); - ASSERT_TRUE(edge_by_target(a, b, g).second); - ASSERT_TRUE(ab == edge_by_target(a, b, g).first); - ASSERT_FALSE(edge_by_target(a, c, g).second); - ASSERT_FALSE(edge_by_target(b, a, g).second); - ASSERT_TRUE(edge_by_target(b, b, g).second); - ASSERT_TRUE(bb == edge_by_target(b, b, g).first); - ASSERT_TRUE(edge_by_target(c, b, g).second); - ASSERT_TRUE(cb == edge_by_target(c, b, g).first); + tie(ai, ae) = adjacent_vertices(d, g); + ASSERT_EQ(ai, ae); +} + +TEST(ue2_graph, inv_adj) { + SimpleG g; + auto a = add_vertex(g); + auto b = add_vertex(g); + auto c = add_vertex(g); + auto d = add_vertex(g); + + add_edge(a, b, g); + add_edge(a, c, g); + add_edge(a, d, g); + add_edge(b, a, g); + add_edge(b, b, g); + + SimpleG::inv_adjacency_iterator ai, ae; + tie(ai, ae) = inv_adjacent_vertices(a, g); + ASSERT_EQ(b, *ai++); + ASSERT_EQ(ai, ae); + + tie(ai, ae) = inv_adjacent_vertices(b, g); + ASSERT_EQ(a, *ai++); + ASSERT_EQ(b, *ai++); + ASSERT_EQ(ai, ae); + + tie(ai, ae) = inv_adjacent_vertices(c, g); + ASSERT_EQ(a, *ai++); + ASSERT_EQ(ai, ae); + + tie(ai, ae) = inv_adjacent_vertices(d, g); + ASSERT_EQ(a, *ai++); + ASSERT_EQ(ai, ae); +} + +TEST(ue2_graph, square_brackets_v) { + SimpleG g; + auto a = add_vertex(g); + auto b = add_vertex(g); + auto c = add_vertex(g); + auto d = add_vertex(g); + + ASSERT_EQ(0U, g[a].index); + ASSERT_EQ(1U, g[b].index); + ASSERT_EQ(2U, g[c].index); + ASSERT_EQ(3U, g[d].index); + + ASSERT_EQ("SimpleV", g[a].test_v); + ASSERT_EQ("SimpleV", g[b].test_v); + ASSERT_EQ("SimpleV", g[c].test_v); + ASSERT_EQ("SimpleV", g[d].test_v); + + g[a].test_v = "a"; + g[b].test_v = "b"; + g[c].test_v = "c"; + g[d].test_v = "d"; + + ASSERT_EQ("a", g[a].test_v); + ASSERT_EQ("b", g[b].test_v); + ASSERT_EQ("c", g[c].test_v); + ASSERT_EQ("d", g[d].test_v); +} + +TEST(ue2_graph, square_brackets_e) { + SimpleG g; + auto u = add_vertex(g); + auto v = add_vertex(g); + auto a = add_edge(u, v, g).first; + auto b = add_edge(u, v, g).first; + auto c = add_edge(u, u, g).first; + auto d = add_edge(v, u, g).first; + + ASSERT_EQ(0U, g[a].index); + ASSERT_EQ(1U, g[b].index); + ASSERT_EQ(2U, g[c].index); + ASSERT_EQ(3U, g[d].index); + + ASSERT_EQ("SimpleE", g[a].test_e); + ASSERT_EQ("SimpleE", g[b].test_e); + ASSERT_EQ("SimpleE", g[c].test_e); + ASSERT_EQ("SimpleE", g[d].test_e); + + g[a].test_e = "a"; + g[b].test_e = "b"; + g[c].test_e = "c"; + g[d].test_e = "d"; + + ASSERT_EQ("a", g[a].test_e); + ASSERT_EQ("b", g[b].test_e); + ASSERT_EQ("c", g[c].test_e); + ASSERT_EQ("d", g[d].test_e); +} + +TEST(ue2_graph, vertex_ordering_1) { + SimpleG g; + auto a = add_vertex(g); + auto b = add_vertex(g); + auto c = add_vertex(g); + auto d = add_vertex(g); + + ASSERT_LE(a, b); + ASSERT_LE(a, c); + ASSERT_LE(a, d); + ASSERT_LE(b, c); + ASSERT_LE(b, d); + ASSERT_LE(c, d); + + g[a].index = 5; + g[b].index = 0; + g[c].index = 3; + g[d].index = 1; + + ASSERT_LE(a, b); + ASSERT_LE(a, c); + ASSERT_LE(a, d); + ASSERT_LE(b, c); + ASSERT_LE(b, d); + ASSERT_LE(c, d); +} + +TEST(ue2_graph, vertex_ordering_2) { + SimpleG g; + auto a = add_vertex(g); + auto b = add_vertex(g); + auto c = add_vertex(g); + auto d = add_vertex(g); + + set s; + s.insert(a); + s.insert(b); + s.insert(c); + s.insert(d); + + auto it = s.begin(); + ASSERT_EQ(a, *it++); + ASSERT_EQ(b, *it++); + ASSERT_EQ(c, *it++); + ASSERT_EQ(d, *it++); + ASSERT_EQ(it, s.end()); + + g[a].index = 5; + g[b].index = 0; + g[c].index = 3; + g[d].index = 1; + + it = s.begin(); + ASSERT_EQ(a, *it++); + ASSERT_EQ(b, *it++); + ASSERT_EQ(c, *it++); + ASSERT_EQ(d, *it++); + ASSERT_EQ(it, s.end()); +} + +TEST(ue2_graph, get_v_2_arg) { + SimpleG g; + auto a = add_vertex(g); + auto b = add_vertex(g); + + auto pm = get(&SimpleV::test_v, g); + + ASSERT_EQ("SimpleV", pm[a]); + ASSERT_EQ("SimpleV", pm[b]); + + pm[a] = "a"; + pm[b] = "b"; + + ASSERT_EQ("a", pm[a]); + ASSERT_EQ("b", pm[b]); + + ASSERT_EQ("a", g[a].test_v); + ASSERT_EQ("b", g[b].test_v); + + g[a].test_v = "X"; + g[b].test_v = "Y"; + + ASSERT_EQ("X", pm[a]); + ASSERT_EQ("Y", pm[b]); + + ASSERT_EQ("X", get(pm, a)); + ASSERT_EQ("Y", get(pm, b)); + + put(pm, a, "A"); + put(pm, b, "B"); + + ASSERT_EQ("A", g[a].test_v); + ASSERT_EQ("B", g[b].test_v); +} + +TEST(ue2_graph, get_v_2_arg_const) { + SimpleG g; + const SimpleG &gg = g; + auto a = add_vertex(g); + auto b = add_vertex(g); + + auto pm = get(&SimpleV::test_v, gg); + + ASSERT_EQ("SimpleV", pm[a]); + ASSERT_EQ("SimpleV", pm[b]); + + g[a].test_v = "a"; + g[b].test_v = "b"; + + ASSERT_EQ("a", pm[a]); + ASSERT_EQ("b", pm[b]); + + ASSERT_EQ("a", get(pm, a)); + ASSERT_EQ("b", get(pm, b)); +} + +TEST(ue2_graph, get_e_2_arg) { + SimpleG g; + auto u = add_vertex(g); + auto v = add_vertex(g); + auto a = add_edge(u, v, g).first; + auto b = add_edge(v, u, g).first; + + auto pm = get(&SimpleE::test_e, g); + + ASSERT_EQ("SimpleE", pm[a]); + ASSERT_EQ("SimpleE", pm[b]); + + pm[a] = "a"; + pm[b] = "b"; + + ASSERT_EQ("a", pm[a]); + ASSERT_EQ("b", pm[b]); + + ASSERT_EQ("a", g[a].test_e); + ASSERT_EQ("b", g[b].test_e); + + g[a].test_e = "X"; + g[b].test_e = "Y"; + + ASSERT_EQ("X", pm[a]); + ASSERT_EQ("Y", pm[b]); + + ASSERT_EQ("X", get(pm, a)); + ASSERT_EQ("Y", get(pm, b)); + + put(pm, a, "A"); + put(pm, b, "B"); + + ASSERT_EQ("A", g[a].test_e); + ASSERT_EQ("B", g[b].test_e); +} + +TEST(ue2_graph, get_e_2_arg_const) { + SimpleG g; + const SimpleG &gg = g; + auto u = add_vertex(g); + auto v = add_vertex(g); + auto a = add_edge(u, v, g).first; + auto b = add_edge(v, u, g).first; + + auto pm = get(&SimpleE::test_e, gg); + + ASSERT_EQ("SimpleE", pm[a]); + ASSERT_EQ("SimpleE", pm[b]); + + g[a].test_e = "a"; + g[b].test_e = "b"; + + ASSERT_EQ("a", pm[a]); + ASSERT_EQ("b", pm[b]); + + ASSERT_EQ("a", get(pm, a)); + ASSERT_EQ("b", get(pm, b)); +} + +TEST(ue2_graph, get_v_3_arg) { + SimpleG g; + auto a = add_vertex(g); + auto b = add_vertex(g); + + ASSERT_EQ("SimpleV", get(&SimpleV::test_v, g, a)); + ASSERT_EQ("SimpleV", get(&SimpleV::test_v, g, a)); + + get(&SimpleV::test_v, g, a) = "a"; + get(&SimpleV::test_v, g, b) = "b"; + + ASSERT_EQ("a", get(&SimpleV::test_v, g, a)); + ASSERT_EQ("b", get(&SimpleV::test_v, g, b)); + + ASSERT_EQ("a", g[a].test_v); + ASSERT_EQ("b", g[b].test_v); + + g[a].test_v = "X"; + g[b].test_v = "Y"; + + ASSERT_EQ("X", get(&SimpleV::test_v, g, a)); + ASSERT_EQ("Y", get(&SimpleV::test_v, g, b)); + + //std::decay::type x = "A"; + + put(&SimpleV::test_v, g, a, "A"); + put(&SimpleV::test_v, g, b, "B"); + + ASSERT_EQ("A", g[a].test_v); + ASSERT_EQ("B", g[b].test_v); +} + +TEST(ue2_graph, get_v_3_arg_const) { + SimpleG g; + const SimpleG &gg = g; + auto a = add_vertex(g); + auto b = add_vertex(g); + + ASSERT_EQ("SimpleV", get(&SimpleV::test_v, gg, a)); + ASSERT_EQ("SimpleV", get(&SimpleV::test_v, gg, b)); + + g[a].test_v = "a"; + g[b].test_v = "b"; + + ASSERT_EQ("a", get(&SimpleV::test_v, gg, a)); + ASSERT_EQ("b", get(&SimpleV::test_v, gg, b)); +} + +TEST(ue2_graph, get_e_3_arg) { + SimpleG g; + auto u = add_vertex(g); + auto v = add_vertex(g); + auto a = add_edge(u, v, g).first; + auto b = add_edge(v, u, g).first; + + ASSERT_EQ("SimpleE", get(&SimpleE::test_e, g, a)); + ASSERT_EQ("SimpleE", get(&SimpleE::test_e, g, b)); + + get(&SimpleE::test_e, g, a) = "a"; + get(&SimpleE::test_e, g, b) = "b"; + + ASSERT_EQ("a", get(&SimpleE::test_e, g, a)); + ASSERT_EQ("b", get(&SimpleE::test_e, g, b)); + + ASSERT_EQ("a", g[a].test_e); + ASSERT_EQ("b", g[b].test_e); + + g[a].test_e = "X"; + g[b].test_e = "Y"; + + ASSERT_EQ("X", get(&SimpleE::test_e, g, a)); + ASSERT_EQ("Y", get(&SimpleE::test_e, g, b)); +} + +TEST(ue2_graph, get_e_3_arg_const) { + SimpleG g; + const SimpleG &gg = g; + auto u = add_vertex(g); + auto v = add_vertex(g); + auto a = add_edge(u, v, g).first; + auto b = add_edge(v, u, g).first; + + ASSERT_EQ("SimpleE", get(&SimpleE::test_e, gg, a)); + ASSERT_EQ("SimpleE", get(&SimpleE::test_e, gg, b)); + + g[a].test_e = "a"; + g[b].test_e = "b"; + + ASSERT_EQ("a", get(&SimpleE::test_e, gg, a)); + ASSERT_EQ("b", get(&SimpleE::test_e, gg, b)); +} + +TEST(ue2_graph, get_vertex_index) { + SimpleG g; + auto a = add_vertex(g); + auto pm = get(vertex_index, g); + ASSERT_EQ(0U, pm(a)); + pm(a) = 1; + ASSERT_EQ(1U, pm[a]); + ASSERT_EQ(1U, g[a].index); + ASSERT_EQ(1U, get(vertex_index, g, a)); +} + +TEST(ue2_graph, get_vertex_index_const) { + SimpleG g; + const SimpleG &gg = g; + auto a = add_vertex(g); + auto pm = get(vertex_index, gg); + ASSERT_EQ(0U, pm(a)); + g[a].index = 1; + ASSERT_EQ(1U, pm[a]); + ASSERT_EQ(1U, get(vertex_index, gg, a)); +} + +TEST(ue2_graph, get_edge_index) { + SimpleG g; + auto u = add_vertex(g); + auto v = add_vertex(g); + auto a = add_edge(u, v, g).first; + auto pm = get(edge_index, g); + ASSERT_EQ(0U, pm(a)); + pm(a) = 1; + ASSERT_EQ(1U, pm[a]); + ASSERT_EQ(1U, g[a].index); + ASSERT_EQ(1U, get(edge_index, g, a)); +} + +TEST(ue2_graph, get_edge_index_const) { + SimpleG g; + const SimpleG &gg = g; + auto u = add_vertex(g); + auto v = add_vertex(g); + auto a = add_edge(u, v, g).first; + auto pm = get(edge_index, gg); + ASSERT_EQ(0U, pm(a)); + g[a].index = 1; + ASSERT_EQ(1U, pm[a]); + ASSERT_EQ(1U, get(edge_index, gg, a)); +} + +TEST(ue2_graph, get_vertex_all) { + SimpleG g; + auto a = add_vertex(g); + auto pm = get(vertex_all, g); + ASSERT_EQ(0U, pm(a).index); + pm(a).index = 1; + ASSERT_EQ(1U, pm[a].index); + ASSERT_EQ(1U, g[a].index); + ASSERT_EQ(1U, get(vertex_all, g, a).index); + auto &a_all = get(vertex_all, g, a); + ASSERT_EQ(1U, a_all.index); + g[a].index = 2; + ASSERT_EQ(2U, a_all.index); +} + +TEST(ue2_graph, get_vertex_all_const) { + SimpleG g; + const SimpleG &gg = g; + auto a = add_vertex(g); + auto pm = get(vertex_all, gg); + ASSERT_EQ(0U, pm(a).index); + g[a].index = 1; + ASSERT_EQ(1U, pm[a].index); + ASSERT_EQ(1U, get(vertex_all, gg, a).index); + auto &a_all = get(vertex_all, gg, a); + ASSERT_EQ(1U, a_all.index); + g[a].index = 2; + ASSERT_EQ(2U, a_all.index); +} + +TEST(ue2_graph, get_vertex_bundle) { + SimpleG g; + auto a = add_vertex(g); + auto pm = get(vertex_bundle, g); + ASSERT_EQ(0U, pm(a).index); + pm(a).index = 1; + ASSERT_EQ(1U, pm[a].index); + ASSERT_EQ(1U, g[a].index); + ASSERT_EQ(1U, get(vertex_bundle, g, a).index); + auto &a_bundle = get(vertex_bundle, g, a); + ASSERT_EQ(1U, a_bundle.index); + g[a].index = 2; + ASSERT_EQ(2U, a_bundle.index); +} + +TEST(ue2_graph, get_vertex_bundle_const) { + SimpleG g; + const SimpleG &gg = g; + auto a = add_vertex(g); + auto pm = get(vertex_bundle, gg); + ASSERT_EQ(0U, pm(a).index); + g[a].index = 1; + ASSERT_EQ(1U, pm[a].index); + ASSERT_EQ(1U, get(vertex_bundle, gg, a).index); + auto &a_bundle = get(vertex_bundle, gg, a); + ASSERT_EQ(1U, a_bundle.index); + g[a].index = 2; + ASSERT_EQ(2U, a_bundle.index); +} + +TEST(ue2_graph, get_edge_all) { + SimpleG g; + auto u = add_vertex(g); + auto v = add_vertex(g); + auto a = add_edge(u, v, g).first; + auto pm = get(edge_all, g); + ASSERT_EQ(0U, pm(a).index); + pm(a).index = 1; + ASSERT_EQ(1U, pm[a].index); + ASSERT_EQ(1U, g[a].index); + ASSERT_EQ(1U, get(edge_all, g, a).index); + auto &a_all = get(edge_all, g, a); + ASSERT_EQ(1U, a_all.index); + g[a].index = 2; + ASSERT_EQ(2U, a_all.index); +} + +TEST(ue2_graph, get_edge_all_const) { + SimpleG g; + const SimpleG &gg = g; + auto u = add_vertex(g); + auto v = add_vertex(g); + auto a = add_edge(u, v, g).first; + auto pm = get(edge_all, gg); + ASSERT_EQ(0U, pm(a).index); + g[a].index = 1; + ASSERT_EQ(1U, pm[a].index); + ASSERT_EQ(1U, get(edge_all, gg, a).index); + auto &a_all = get(edge_all, gg, a); + ASSERT_EQ(1U, a_all.index); + g[a].index = 2; + ASSERT_EQ(2U, a_all.index); +} + +TEST(ue2_graph, get_edge_bundle) { + SimpleG g; + auto u = add_vertex(g); + auto v = add_vertex(g); + auto a = add_edge(u, v, g).first; + auto pm = get(edge_bundle, g); + ASSERT_EQ(0U, pm(a).index); + pm(a).index = 1; + ASSERT_EQ(1U, pm[a].index); + ASSERT_EQ(1U, g[a].index); + ASSERT_EQ(1U, get(edge_bundle, g, a).index); + auto &a_bundle = get(edge_bundle, g, a); + ASSERT_EQ(1U, a_bundle.index); + g[a].index = 2; + ASSERT_EQ(2U, a_bundle.index); +} + +TEST(ue2_graph, get_edge_bundle_const) { + SimpleG g; + const SimpleG &gg = g; + auto u = add_vertex(g); + auto v = add_vertex(g); + auto a = add_edge(u, v, g).first; + auto pm = get(edge_bundle, gg); + ASSERT_EQ(0U, pm(a).index); + g[a].index = 1; + ASSERT_EQ(1U, pm[a].index); + ASSERT_EQ(1U, get(edge_bundle, gg, a).index); + auto &a_bundle = get(edge_bundle, gg, a); + ASSERT_EQ(1U, a_bundle.index); + g[a].index = 2; + ASSERT_EQ(2U, a_bundle.index); +} + +TEST(ue2_graph, add_vertex_prop) { + SimpleG g; + SimpleV vp; + vp.index = 42; + vp.test_v = "prop"; + auto u = add_vertex(vp, g); + auto v = add_vertex(vp, g); + + ASSERT_EQ(0U, g[u].index); + ASSERT_EQ(1U, g[v].index); + + ASSERT_EQ("prop", g[u].test_v); + ASSERT_EQ("prop", g[v].test_v); +} + +TEST(ue2_graph, add_edge_prop) { + SimpleG g; + SimpleE ep; + ep.index = 42; + ep.test_e = "prop"; + auto u = add_vertex(g); + auto v = add_vertex(g); + + auto e = add_edge(u, v, ep, g).first; + auto f = add_edge(u, v, ep, g).first; + + ASSERT_EQ(0U, g[e].index); + ASSERT_EQ(1U, g[f].index); + + ASSERT_EQ("prop", g[e].test_e); + ASSERT_EQ("prop", g[f].test_e); +} + +TEST(ue2_graph, reverse_graph) { + SimpleG g; + auto a = add_vertex(g); + auto b = add_vertex(g); + auto e = add_edge(a, b, g).first; + reverse_graph rg(g); + auto index_map = get(vertex_index, rg); + + ASSERT_EQ(0U, rg[a].index); + ASSERT_EQ(1U, rg[b].index); + ASSERT_EQ(0U, rg[e].index); + + ASSERT_EQ(0U, get(vertex_index, rg, a)); + ASSERT_EQ(1U, get(vertex_index, rg, b)); + ASSERT_EQ(0U, get(edge_index, rg, edge(b, a, rg).first)); + + ASSERT_EQ(0U, index_map(a)); + ASSERT_EQ(1U, index_map(b)); + + ASSERT_TRUE(edge(b, a, rg).second); + ASSERT_FALSE(edge(a, b, rg).second); +} + +TEST(ue2_graph, reverse_graph_const) { + SimpleG g; + auto a = add_vertex(g); + auto b = add_vertex(g); + auto e = add_edge(a, b, g).first; + reverse_graph rg(g); + auto index_map = get(&SimpleV::index, rg); + + // Note: reverse_graph fails to make bundles const so things break. + // ASSERT_EQ(0U, rg[a].index); + // ASSERT_EQ(1U, rg[b].index); + // ASSERT_EQ(0U, rg[e].index); + + ASSERT_EQ(0U, get(vertex_index, g, a)); + ASSERT_EQ(1U, get(vertex_index, g, b)); + ASSERT_EQ(0U, get(edge_index, g, e)); + + ASSERT_EQ(0U, index_map(a)); + ASSERT_EQ(1U, index_map(b)); + + ASSERT_TRUE(edge(b, a, rg).second); + ASSERT_FALSE(edge(a, b, rg).second); +} + +TEST(ue2_graph, default_param) { + struct TestGraph : ue2_graph { }; + TestGraph g; + + auto v = add_vertex(g); + auto e = add_edge(v, v, g).first; + + ASSERT_EQ(0U, get(vertex_index, g, v)); + ASSERT_EQ(0U, get(&ue2::graph_detail::default_edge_property::index, g, e)); + ASSERT_EQ(0U, get(edge_index, g, e)); } diff --git a/unit/internal/nfagraph_equivalence.cpp b/unit/internal/nfagraph_equivalence.cpp index 3ca1923f..8fda9223 100644 --- a/unit/internal/nfagraph_equivalence.cpp +++ b/unit/internal/nfagraph_equivalence.cpp @@ -84,7 +84,7 @@ TEST(NFAGraph, RemoveEquivalence1) { ASSERT_TRUE(tmpcr.test('a')); } // check if we found our vertex - ASSERT_TRUE(a != nullptr); + ASSERT_TRUE(a != NGHolder::null_vertex()); // There should be two edges from v to nodes with reachability 'b' and 'c' NFAVertex b = NGHolder::null_vertex(); @@ -101,8 +101,8 @@ TEST(NFAGraph, RemoveEquivalence1) { } } // check if we found our vertices - ASSERT_TRUE(b != nullptr); - ASSERT_TRUE(c != nullptr); + ASSERT_TRUE(b != NGHolder::null_vertex()); + ASSERT_TRUE(c != NGHolder::null_vertex()); // both vertices should have an edge to accept ASSERT_TRUE(edge(b, g.accept, g).second); @@ -145,7 +145,7 @@ TEST(NFAGraph, RemoveEquivalence2) { ASSERT_TRUE(tmpcr.test('a')); } // check if we found our vertex - ASSERT_TRUE(a != nullptr); + ASSERT_TRUE(a != NGHolder::null_vertex()); // There should be two edges from v to nodes with reachability 'b' and 'c' NFAVertex b = NGHolder::null_vertex(); @@ -162,8 +162,8 @@ TEST(NFAGraph, RemoveEquivalence2) { } } // check if we found our vertices - ASSERT_TRUE(b != nullptr); - ASSERT_TRUE(c != nullptr); + ASSERT_TRUE(b != NGHolder::null_vertex()); + ASSERT_TRUE(c != NGHolder::null_vertex()); // both new vertices should have edges from startDs ASSERT_TRUE(edge(g.startDs, b, g).second); @@ -207,7 +207,7 @@ TEST(NFAGraph, RemoveEquivalence3) { ASSERT_TRUE(tmpcr.test('a')); } // check if we found our 'a' - ASSERT_TRUE(a != nullptr); + ASSERT_TRUE(a != NGHolder::null_vertex()); // There should be an edge from 'a' to '.' ASSERT_EQ(1U, out_degree(a, g)); @@ -234,7 +234,6 @@ TEST(NFAGraph, RemoveEquivalence3) { NFAVertex X = NGHolder::null_vertex(); NFAVertex Y = NGHolder::null_vertex(); for (NFAVertex tmp : adjacent_vertices_range(dot2, g)) { - // we already know about dot1, so skip it if (tmp == dot1) { continue; @@ -251,8 +250,8 @@ TEST(NFAGraph, RemoveEquivalence3) { } } // check if we found both vertices - ASSERT_TRUE(X != nullptr); - ASSERT_TRUE(Y != nullptr); + ASSERT_TRUE(X != NGHolder::null_vertex()); + ASSERT_TRUE(Y != NGHolder::null_vertex()); // finally, check if these two vertices only have edges to accept ASSERT_EQ(1U, out_degree(X, g)); @@ -306,8 +305,8 @@ TEST(NFAGraph, RemoveEquivalence4) { } } // check if we found both vertices - ASSERT_TRUE(X != nullptr); - ASSERT_TRUE(Y != nullptr); + ASSERT_TRUE(X != NGHolder::null_vertex()); + ASSERT_TRUE(Y != NGHolder::null_vertex()); // now, find first dot from X ASSERT_EQ(1U, out_degree(X, g)); @@ -351,7 +350,7 @@ TEST(NFAGraph, RemoveEquivalence4) { } } // make sure we found our 'a' - ASSERT_TRUE(a != nullptr); + ASSERT_TRUE(a != NGHolder::null_vertex()); // now, check if 'a' has an edge to accept ASSERT_EQ(1U, out_degree(a, g)); @@ -396,7 +395,7 @@ TEST(NFAGraph, RemoveEquivalence5) { ASSERT_TRUE(edge(v, v, g).second); } // check if we found our vertex - ASSERT_TRUE(v != nullptr); + ASSERT_TRUE(v != NGHolder::null_vertex()); // now, find the vertex leading to accept NFAVertex v2 = NGHolder::null_vertex(); @@ -414,7 +413,7 @@ TEST(NFAGraph, RemoveEquivalence5) { ASSERT_TRUE(edge(tmp, g.accept, g).second); } // check if we found our vertex - ASSERT_TRUE(v2 != nullptr); + ASSERT_TRUE(v2 != NGHolder::null_vertex()); } // catching UE-2692 @@ -452,7 +451,7 @@ TEST(NFAGraph, RemoveEquivalence6) { ASSERT_TRUE(edge(v, g.accept, g).second); } // check if we found our vertex - ASSERT_TRUE(v != nullptr); + ASSERT_TRUE(v != NGHolder::null_vertex()); } // catching UE-2692 @@ -492,7 +491,7 @@ TEST(NFAGraph, RemoveEquivalence7) { ASSERT_EQ(1U, proper_out_degree(v, g)); } // check if we found our vertex - ASSERT_TRUE(v != nullptr); + ASSERT_TRUE(v != NGHolder::null_vertex()); // find the next vertex and ensure it has an edge to accept NFAVertex v2 = NGHolder::null_vertex(); @@ -511,7 +510,7 @@ TEST(NFAGraph, RemoveEquivalence7) { ASSERT_TRUE(edge(v2, g.accept, g).second); } // check if we found our vertex - ASSERT_TRUE(v2 != nullptr); + ASSERT_TRUE(v2 != NGHolder::null_vertex()); } TEST(NFAGraph, RemoveEquivalence_Reports1) { diff --git a/unit/internal/nfagraph_redundancy.cpp b/unit/internal/nfagraph_redundancy.cpp index acb3cc7b..be9527fd 100644 --- a/unit/internal/nfagraph_redundancy.cpp +++ b/unit/internal/nfagraph_redundancy.cpp @@ -55,13 +55,13 @@ TEST(NFAGraph, RemoveRedundancy1) { unique_ptr graph(constructGraphWithCC("(a|b)c", cc, 0)); ASSERT_TRUE(graph.get() != nullptr); + NGHolder &g = *graph; // Run removeRedundancy - removeRedundancy(*graph, SOM_NONE); - NFAGraph &g = graph->g; + removeRedundancy(g, SOM_NONE); // Our graph should only have two non-special nodes - ASSERT_EQ((size_t)N_SPECIALS + 2, num_vertices(*graph)); + ASSERT_EQ((size_t)N_SPECIALS + 2, num_vertices(g)); // Dot-star start state should be connected to itself and a single other // vertex @@ -98,13 +98,13 @@ TEST(NFAGraph, RemoveRedundancy2) { unique_ptr graph(constructGraphWithCC("a.*b?c", cc, HS_FLAG_DOTALL)); ASSERT_TRUE(graph.get() != nullptr); + NGHolder &g = *graph; // Run removeRedundancy - removeRedundancy(*graph, SOM_NONE); - NFAGraph &g = graph->g; + removeRedundancy(g, SOM_NONE); // Our graph should now have only 3 non-special vertices - ASSERT_EQ((size_t)N_SPECIALS + 3, num_vertices(*graph)); + ASSERT_EQ((size_t)N_SPECIALS + 3, num_vertices(g)); // Dot-star start state should be connected to itself and a single other // vertex @@ -156,12 +156,12 @@ TEST(NFAGraph, RemoveRedundancy3) { cc, 0)); ASSERT_TRUE(graph.get() != nullptr); - unsigned countBefore = num_vertices(graph->g); + unsigned countBefore = num_vertices(*graph); removeRedundancy(*graph, SOM_NONE); // The '(a|b)?' construction (two states) should have disappeared, leaving // this expr as 'foobar.*teakettle' - ASSERT_EQ(countBefore - 2, num_vertices(graph->g)); + ASSERT_EQ(countBefore - 2, num_vertices(*graph)); } TEST(NFAGraph, RemoveRedundancy4) { @@ -169,11 +169,11 @@ TEST(NFAGraph, RemoveRedundancy4) { unique_ptr graph(constructGraphWithCC("foo([A-Z]|a|b|q)", cc, 0)); ASSERT_TRUE(graph.get() != nullptr); - unsigned countBefore = num_vertices(graph->g); + unsigned countBefore = num_vertices(*graph); removeRedundancy(*graph, SOM_NONE); // We should end up with the alternation collapsing into one state - ASSERT_EQ(countBefore - 3, num_vertices(graph->g)); + ASSERT_EQ(countBefore - 3, num_vertices(*graph)); } TEST(NFAGraph, RemoveRedundancy5) { @@ -182,12 +182,12 @@ TEST(NFAGraph, RemoveRedundancy5) { cc, 0)); ASSERT_TRUE(graph.get() != nullptr); - unsigned countBefore = num_vertices(graph->g); + unsigned countBefore = num_vertices(*graph); removeRedundancy(*graph, SOM_NONE); // Since we don't return a start offset, the first state ('[0-9]?') is // redundant. - ASSERT_EQ(countBefore - 1, num_vertices(graph->g)); + ASSERT_EQ(countBefore - 1, num_vertices(*graph)); } TEST(NFAGraph, RemoveEdgeRedundancy1) { @@ -196,12 +196,12 @@ TEST(NFAGraph, RemoveEdgeRedundancy1) { auto graph = constructGraphWithCC("A+hatstand", cc, HS_FLAG_DOTALL); ASSERT_TRUE(graph.get() != nullptr); - unsigned countBefore = num_edges(graph->g); + unsigned countBefore = num_edges(*graph); removeEdgeRedundancy(*graph, SOM_NONE, cc); // One edge (the self-loop on the leading A+) should have been removed. - ASSERT_EQ(countBefore - 1, num_edges(graph->g)); + ASSERT_EQ(countBefore - 1, num_edges(*graph)); } TEST(NFAGraph, RemoveEdgeRedundancy2) { @@ -210,12 +210,12 @@ TEST(NFAGraph, RemoveEdgeRedundancy2) { auto graph = constructGraphWithCC("foo.*A*bar", cc, HS_FLAG_DOTALL); ASSERT_TRUE(graph.get() != nullptr); - size_t numEdgesBefore = num_edges(graph->g); - size_t numVertsBefore = num_vertices(graph->g); + size_t numEdgesBefore = num_edges(*graph); + size_t numVertsBefore = num_vertices(*graph); removeEdgeRedundancy(*graph, SOM_NONE, cc); // The .* should swallow up the A* and its self-loop. - ASSERT_EQ(numEdgesBefore - 4, num_edges(graph->g)); - ASSERT_EQ(numVertsBefore - 1, num_vertices(graph->g)); + ASSERT_EQ(numEdgesBefore - 4, num_edges(*graph)); + ASSERT_EQ(numVertsBefore - 1, num_vertices(*graph)); } diff --git a/unit/internal/rose_build_merge.cpp b/unit/internal/rose_build_merge.cpp index 3f5a8382..291c241a 100644 --- a/unit/internal/rose_build_merge.cpp +++ b/unit/internal/rose_build_merge.cpp @@ -64,7 +64,6 @@ RoseVertex addVertex(RoseBuildImpl &build, RoseVertex parent, u32 lit_id) { RoseGraph &g = build.g; RoseVertex v = add_vertex(g); - g[v].idx = build.vertexIndex++; g[v].min_offset = 0; g[v].max_offset = ROSE_BOUND_INF; g[v].literals.insert(lit_id); diff --git a/util/ng_corpus_generator.cpp b/util/ng_corpus_generator.cpp index 9fa6743e..ca7c413a 100644 --- a/util/ng_corpus_generator.cpp +++ b/util/ng_corpus_generator.cpp @@ -144,7 +144,7 @@ void findPaths(const NGHolder &g, CorpusProperties &cProps, ue2::unordered_set one_way_in; for (const auto &v : vertices_range(g)) { - if (!hasGreaterInDegree(1, v, g)) { + if (in_degree(v, g) <= 1) { one_way_in.insert(v); } } @@ -155,7 +155,7 @@ void findPaths(const NGHolder &g, CorpusProperties &cProps, ptr_vector::auto_type p = open.pop_back(); NFAVertex u = p->back(); - DEBUG_PRINTF("dequeuing path %s, back %u\n", + DEBUG_PRINTF("dequeuing path %s, back %zu\n", pathToString(g, *p).c_str(), g[u].index); NGHolder::adjacency_iterator ai, ae; @@ -187,7 +187,7 @@ void findPaths(const NGHolder &g, CorpusProperties &cProps, // Note that vertices that only have one predecessor don't need // their cycle limit checked, as their predecessors will have // the same count. - DEBUG_PRINTF("exceeded cycle limit for v=%u, pruning path\n", + DEBUG_PRINTF("exceeded cycle limit for v=%zu, pruning path\n", g[v].index); continue; } @@ -301,7 +301,7 @@ void CorpusGeneratorImpl::addRandom(const min_max &mm, string *out) { } unsigned char CorpusGeneratorImpl::getChar(NFAVertex v) { - const CharReach &cr = graph.g[v].char_reach; + const CharReach &cr = graph[v].char_reach; switch (cProps.throwDice()) { case CorpusProperties::ROLLED_MATCH: @@ -521,7 +521,7 @@ CorpusGeneratorUtf8::pathToCorpus(const vector &path) { } static -u32 classify_vertex(const NFAGraph &g, NFAVertex v) { +u32 classify_vertex(const NGHolder &g, NFAVertex v) { const CharReach &cr = g[v].char_reach; if (cr.isSubsetOf(UTF_ASCII_CR)) { return 1; @@ -560,7 +560,7 @@ void expandCodePointSet(const CharReach &cr, CodePointSet *out, u32 mask, } static -void decodePath(const NFAGraph &g, const VertexPath &in, +void decodePath(const NGHolder &g, const VertexPath &in, vector &out) { VertexPath::const_iterator it = in.begin(); while (it != in.end()) { @@ -618,7 +618,7 @@ void translatePaths(const NGHolder &graph, assert(out); for (const auto &path : allPathsTemp) { out->push_back(vector()); - decodePath(graph.g, path, out->back()); + decodePath(graph, path, out->back()); } } diff --git a/util/ng_find_matches.cpp b/util/ng_find_matches.cpp index 60ff0a17..2b337365 100644 --- a/util/ng_find_matches.cpp +++ b/util/ng_find_matches.cpp @@ -34,7 +34,7 @@ #include "ng_find_matches.h" -#include "nfagraph/ng_graph.h" +#include "nfagraph/ng_holder.h" #include "nfagraph/ng_util.h" #include "parser/position.h" #include "util/container.h"