]> git.ipfire.org Git - thirdparty/vectorscan.git/commitdiff
Introduce custom adjacency-list based graph
authorAlex Coyte <a.coyte@intel.com>
Wed, 24 Aug 2016 06:12:51 +0000 (16:12 +1000)
committerMatthew Barr <matthew.barr@intel.com>
Fri, 2 Dec 2016 00:31:33 +0000 (11:31 +1100)
92 files changed:
CMakeLists.txt
src/compiler/asserts.cpp
src/nfa/accel_dfa_build_strat.cpp
src/nfa/castlecompile.cpp
src/nfa/limex_compile.cpp
src/nfagraph/ng.cpp
src/nfagraph/ng_anchored_dots.cpp
src/nfagraph/ng_asserts.cpp
src/nfagraph/ng_builder.cpp
src/nfagraph/ng_calc_components.cpp
src/nfagraph/ng_cyclic_redundancy.cpp
src/nfagraph/ng_depth.cpp
src/nfagraph/ng_dominators.cpp
src/nfagraph/ng_dump.cpp
src/nfagraph/ng_edge_redundancy.cpp
src/nfagraph/ng_equivalence.cpp
src/nfagraph/ng_execute.cpp
src/nfagraph/ng_expr_info.cpp
src/nfagraph/ng_extparam.cpp
src/nfagraph/ng_fixed_width.cpp
src/nfagraph/ng_graph.h [deleted file]
src/nfagraph/ng_haig.cpp
src/nfagraph/ng_holder.cpp
src/nfagraph/ng_holder.h
src/nfagraph/ng_is_equal.cpp
src/nfagraph/ng_limex.cpp
src/nfagraph/ng_limex_accel.cpp
src/nfagraph/ng_literal_analysis.cpp
src/nfagraph/ng_literal_component.cpp
src/nfagraph/ng_literal_decorated.cpp
src/nfagraph/ng_mcclellan.cpp
src/nfagraph/ng_misc_opt.cpp
src/nfagraph/ng_netflow.cpp
src/nfagraph/ng_prefilter.cpp
src/nfagraph/ng_prune.cpp
src/nfagraph/ng_puff.cpp
src/nfagraph/ng_redundancy.cpp
src/nfagraph/ng_region.cpp
src/nfagraph/ng_region.h
src/nfagraph/ng_region_redundancy.cpp
src/nfagraph/ng_repeat.cpp
src/nfagraph/ng_restructuring.cpp
src/nfagraph/ng_rose.cpp
src/nfagraph/ng_small_literal_set.cpp
src/nfagraph/ng_som.cpp
src/nfagraph/ng_som_add_redundancy.cpp
src/nfagraph/ng_som_util.cpp
src/nfagraph/ng_split.cpp
src/nfagraph/ng_squash.cpp
src/nfagraph/ng_uncalc_components.cpp
src/nfagraph/ng_uncalc_components.h
src/nfagraph/ng_undirected.h
src/nfagraph/ng_utf8.cpp
src/nfagraph/ng_util.cpp
src/nfagraph/ng_util.h
src/nfagraph/ng_violet.cpp
src/nfagraph/ng_width.cpp
src/rose/rose_build_add.cpp
src/rose/rose_build_add_mask.cpp
src/rose/rose_build_anchored.cpp
src/rose/rose_build_bytecode.cpp
src/rose/rose_build_castle.cpp
src/rose/rose_build_compile.cpp
src/rose/rose_build_convert.cpp
src/rose/rose_build_dump.cpp
src/rose/rose_build_groups.cpp
src/rose/rose_build_impl.h
src/rose/rose_build_infix.cpp
src/rose/rose_build_lookaround.cpp
src/rose/rose_build_matchers.cpp
src/rose/rose_build_merge.cpp
src/rose/rose_build_misc.cpp
src/rose/rose_build_role_aliasing.cpp
src/rose/rose_build_util.h
src/rose/rose_build_width.cpp
src/rose/rose_graph.h
src/rose/rose_in_dump.cpp
src/rose/rose_in_graph.h
src/rose/rose_in_util.cpp
src/smallwrite/smallwrite_build.cpp
src/som/slot_manager.h
src/util/dump_charclass.cpp
src/util/dump_charclass.h
src/util/graph.h
src/util/graph_range.h
src/util/ue2_graph.h [new file with mode: 0644]
unit/internal/graph.cpp
unit/internal/nfagraph_equivalence.cpp
unit/internal/nfagraph_redundancy.cpp
unit/internal/rose_build_merge.cpp
util/ng_corpus_generator.cpp
util/ng_find_matches.cpp

index 6f506e9b22899e2f00fe744311175bc8d998caa7..8def2bafc88b33d74178685a7252bd288b255796 100644 (file)
@@ -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
index 0365e268ff54641a48b1fcfb0b2355bc02ea1004..e67fd8bc85853127662ef0649e8f1ac0c957b09a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -117,11 +117,11 @@ typedef map<pair<NFAVertex, NFAVertex>, 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));
index ba21adc789776918f2ccbccf9c43a53f9ea2d245..70d2d103199e327a6b4436fde400e0b0b7a63f3e 100644 (file)
@@ -56,15 +56,6 @@ struct path {
 };
 };
 
-static UNUSED
-string describeClasses(const vector<CharReach> &v) {
-    std::ostringstream oss;
-    for (const auto &cr : v) {
-        describeClass(oss, cr);
-    }
-    return oss.str();
-}
-
 static
 void dump_paths(const vector<path> &paths) {
     for (UNUSED const auto &p : paths) {
index b76078f9b2a5e083bd22ff33f95d59029a96ad3d..fb685f21888049cd113397619f5b9bcf2715ecc6 100644 (file)
@@ -58,6 +58,7 @@
 #include <stack>
 #include <cassert>
 
+#include <boost/graph/adjacency_list.hpp>
 #include <boost/range/adaptor/map.hpp>
 
 using namespace std;
@@ -981,7 +982,7 @@ unique_ptr<NGHolder> 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));
index b7ea93d97de9d98d94e443e78796c1c46938b8a0..481113e356b18a9db211515e2ef857217b3cbdb4 100644 (file)
@@ -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<NFAVertex, AccelScheme> *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<u32, set<NFAVertex>> &tops,
 
     try {
         vector<boost::default_color_type> 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<u32, set<NFAVertex>> &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<u32, set<NFAVertex>> &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<u32, set<NFAVertex>> &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<u32, set<NFAVertex>> &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;
         }
     }
index 071e5c6302dafc8de8e8884f8502a791cac26f47..dff9c7e87ce85842d4f49e02642150844cf281c4 100644 (file)
@@ -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));
index ba352e60559b8bfd1801f09120a210ec082fc1ea..ed9c7f48606da06c546223ffa3788d1f4c3c1173 100644 (file)
@@ -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<NFAVertex> 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.
index e9e3934507ddca46f70538aa661baf6b3f94b1cc..e0d43e7b9b30316a07e8110040ca49db7c49b712 100644 (file)
@@ -101,7 +101,7 @@ vector<NFAEdge> getAsserts(const NGHolder &g) {
 
 static
 void addToSplit(const NGHolder &g, NFAVertex v, map<u32, NFAVertex> *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<NFAEdge> *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);
     }
 }
index 8a92b7eebf86e193ec8dcad060c8057e62f1fede..6e1ea71e5bc86140bd6a20ab1c67173857bfbd90 100644 (file)
@@ -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<NGWrapper> 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<NFAEdge, bool> 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<NFAEdge, bool> 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
index 658e700135f6417c0b0a9500ba918d43685e3fcd..da6775e44729ca4760186f4ba806f73bf105810d 100644 (file)
@@ -162,7 +162,7 @@ flat_set<NFAVertex> 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<NFAVertex> 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<NFAEdge> 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<unique_ptr<NGHolder>> &comps,
 
     NFAUndirectedGraph ug;
     ue2::unordered_map<NFAVertex, NFAUndirectedVertex> old2new;
-    ue2::unordered_map<u32, NFAVertex> newIdx2old;
 
-    createUnGraph(g.g, true, true, ug, old2new, newIdx2old);
+    createUnGraph(g, true, true, ug, old2new);
 
     // Construct reverse mapping.
     ue2::unordered_map<NFAUndirectedVertex, NFAVertex> new2old;
@@ -313,7 +313,7 @@ void splitIntoComponents(const NGHolder &g, deque<unique_ptr<NGHolder>> &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<NFAVertex, NFAVertex> v_map; // temp map for fillHolder
@@ -322,8 +322,9 @@ void splitIntoComponents(const NGHolder &g, deque<unique_ptr<NGHolder>> &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<NGHolder>(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<NGHolder>();
         v_map.clear();
@@ -349,9 +350,6 @@ void splitIntoComponents(const NGHolder &g, deque<unique_ptr<NGHolder>> &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<NGHolder>(g));
-
         auto gc = ue2::make_unique<NGHolder>();
         v_map.clear();
         fillHolder(gc.get(), g, vv, &v_map);
index e2272264469d81df4128760cc957c860c6394c5c..9ae4458c6b1ec7b0ae65d2f74ce88a6a4be82c03 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -99,7 +99,7 @@ class SearchVisitor : public boost::default_dfs_visitor {
 
         template<class Vertex, class Graph>
         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<NFAGraph, NFAGraph&>::edge_descriptor &e,
-               const reverse_graph<NFAGraph, NFAGraph&> &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<NGHolder, NGHolder &>::edge_descriptor &e,
+               const reverse_graph<NGHolder, NGHolder &> &g) {
+    return get(boost::edge_underlying, g, e);
 }
 
-
 /* returns true if we did stuff */
 template<class Graph>
 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<NFAGraph, NFAGraph&> RevGraph;
-    RevGraph revg(g.g);
+    typedef reverse_graph<NGHolder, NGHolder &> RevGraph;
+    RevGraph revg(g);
     bool r_changed = cyclicPathRedundancyPass(revg, g);
     if (r_changed) {
         DEBUG_PRINTF("edges removed by reverse pass\n");
index 8afa644a9a94d62bd22ec761c03a2748e5f7e0be..5111b7526f82142b7b847a9e2811026525dfa81b 100644 (file)
 #include <boost/graph/reverse_graph.hpp>
 #include <boost/graph/topological_sort.hpp>
 #include <boost/graph/property_maps/constant_property_map.hpp>
+#include <boost/range/adaptor/reversed.hpp>
 
 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<class GraphT>
 static
-void findLoopReachable(const GraphT &g, const NFAVertex srcVertex,
+void findLoopReachable(const GraphT &g,
+                       const typename GraphT::vertex_descriptor srcVertex,
                        vector<bool> &deadNodes) {
     typedef typename GraphT::edge_descriptor EdgeT;
+    typedef typename GraphT::vertex_descriptor VertexT;
     typedef set<EdgeT> EdgeSet;
 
     EdgeSet deadEdges;
     BackEdges<EdgeSet> 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<NFAVertex> topoOrder; /* actually reverse topological order */
+    vector<VertexT> 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<EdgeT>(-1)));
+                       distance_map(make_iterator_property_map(dMax.begin(),
+                                                               max_index_map))
+                       .weight_map(make_constant_property<EdgeT>(-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<NFAVertexDepth> &depths) {
      * reachable from a loop need to be removed
      */
     vector<bool> 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<NFAVertexRevDepth> &depths) {
@@ -305,8 +303,8 @@ void calcDepths(const NGHolder &g, std::vector<NFAVertexRevDepth> &depths) {
     vector<int> dMax;
 
     /* reverse the graph before walking it */
-    typedef reverse_graph<NFAGraph, const NFAGraph&> RevNFAGraph;
-    const RevNFAGraph rg(g.g);
+    typedef reverse_graph<NGHolder, const NGHolder &> 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<NFAVertexBidiDepth> &depths) {
      * reachable from a loop need to be removed
      */
     vector<bool> deadNodes(numVertices);
-    findLoopReachable(g.g, g.start, deadNodes);
+    findLoopReachable(g, g.start, deadNodes);
 
     DEBUG_PRINTF("doing start\n");
-    calcAndStoreDepth<NFAGraph, NFAVertexBidiDepth>(
-        g, g.g, g.start, deadNodes, dMin, dMax, depths,
+    calcAndStoreDepth<NGHolder, NFAVertexBidiDepth>(
+        g, g, g.start, deadNodes, dMin, dMax, depths,
         &NFAVertexBidiDepth::fromStart);
     DEBUG_PRINTF("doing startds\n");
-    calcAndStoreDepth<NFAGraph, NFAVertexBidiDepth>(
-        g, g.g, g.startDs, deadNodes, dMin, dMax, depths,
+    calcAndStoreDepth<NGHolder, NFAVertexBidiDepth>(
+        g, g, g.startDs, deadNodes, dMin, dMax, depths,
         &NFAVertexBidiDepth::fromStartDotStar);
 
     /* Now go backwards */
-    typedef reverse_graph<NFAGraph, const NFAGraph&> RevNFAGraph;
-    const RevNFAGraph rg(g.g);
+    typedef reverse_graph<NGHolder, const NGHolder &> 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<bool> deadNodes(numVertices);
-    findLoopReachable(g.g, g.start, deadNodes);
+    findLoopReachable(g, g.start, deadNodes);
 
     vector<int> dMin, dMax;
-    calcDepthFromSource(g, g.g, src, deadNodes, dMin, dMax);
+    calcDepthFromSource(g, g, src, deadNodes, dMin, dMax);
 
     depths.clear();
     depths.resize(numVertices);
index 05650aaf3b632c7cc4b6f200fddad51995f5ddca..d01af9947888dd1d4e221e2d04413ae082459fbb 100644 (file)
@@ -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 <class Graph>
-ue2::unordered_map<NFAVertex, NFAVertex> calcDominators(const Graph &g,
-                                                        NFAVertex source) {
+unordered_map<NFAVertex, NFAVertex> 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<size_t> dfnum(num_verts, 0);
-    vector<NFAVertex> parents(num_verts, Graph::null_vertex());
+    vector<Vertex> 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<NFAVertex> vertices_by_dfnum(num_verts, Graph::null_vertex());
+    vector<Vertex> vertices_by_dfnum(num_verts, Graph::null_vertex());
 
     // Output map.
-    unordered_map<NFAVertex, NFAVertex> doms;
+    unordered_map<Vertex, Vertex> 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<NFAVertex, NFAVertex> doms2;
+    for (const auto &e : doms) {
+        NFAVertex f(e.first);
+        NFAVertex s(e.second);
+        doms2[f] = s;
+    }
+    return doms2;
 }
 
-ue2::unordered_map<NFAVertex, NFAVertex> findDominators(const NGHolder &g) {
+unordered_map<NFAVertex, NFAVertex> findDominators(const NGHolder &g) {
     assert(hasCorrectlyNumberedVertices(g));
-    return calcDominators(g.g, g.start);
+    return calcDominators(g, g.start);
 }
 
-ue2::unordered_map<NFAVertex, NFAVertex> findPostDominators(const NGHolder &g) {
+unordered_map<NFAVertex, NFAVertex> findPostDominators(const NGHolder &g) {
     assert(hasCorrectlyNumberedVertices(g));
-    return calcDominators(boost::reverse_graph<NFAGraph, const NFAGraph &>(g.g),
+    return calcDominators(boost::reverse_graph<NGHolder, const NGHolder &>(g),
                           g.acceptEod);
 }
 
index 7c1894a30dca60896b2aa1ced4af1d59c4eba542..fc840f2513382269634d4566d46a6092b35e5ff8 100644 (file)
@@ -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);
     }
 }
 
index 5944cfefbd28d64c2164c5590de34ea9979eace4..3ce62c41a4aa25aceee52d0ef1d871a1ccab7bf0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
  *
  * Redistribution and use in source and binary forms, with or without
  * 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<NFAEdge> 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);
         }
     }
index 6f8f653291bd7f62c4756182ff0454644bd12e3c..7e1f7c6f43ef2ba450d921b51a8f1c72fede302e 100644 (file)
@@ -77,7 +77,7 @@ public:
     flat_set<VertexInfo *, VertexInfoPtrCmp> pred; //!< predecessors of this vertex
     flat_set<VertexInfo *, VertexInfoPtrCmp> 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
index 4ffd89c06e07bdd16f68d3a904d6e7931245408a..9d90489471ac5333de9e737cd0f804593e181ee2 100644 (file)
@@ -183,8 +183,6 @@ flat_set<NFAVertex> execute_graph(const NGHolder &g,
     return getVertices(work_states, info);
 }
 
-typedef boost::reverse_graph<const NFAGraph, const NFAGraph &> 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<NGHolder, const NGHolder &> &) {
         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<NFAVertex> execute_graph(const NGHolder &running_g,
     map<NFAVertex, boost::default_color_type> 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<NGHolder, const NGHolder &> revg(input_dag);
     map<NFAVertex, dynamic_bitset<> > dfs_states;
 
     auto info = makeInfoTable(running_g);
@@ -308,7 +307,7 @@ flat_set<NFAVertex> 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
index cfd34ce6a01b5123abbe9a1a1658b2cf5cfe7fbf..b43c7fd1f04012330c7cfcd128303b305e64d6c6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
  *
  * Redistribution and use in source and binary forms, with or without
  * 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);
index eeb1529997e8133b4930c3ab5c083b3b61b775d0..a504ac50a7f9185178d847f0a727fa207360fa92 100644 (file)
@@ -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<NFAVertex> preds;
     vector<NFAEdge> 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;
index 46d77913e9a095f7371887a26916d63ade9cc57d..978dad4406c3d9ea5ff9921745b58585116fa99e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -77,7 +77,7 @@ bool findMask(const NGHolder &g, vector<CharReach> *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 (file)
index 2d6fea1..0000000
+++ /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 <boost/graph/adjacency_iterator.hpp>
-#include <boost/graph/adjacency_list.hpp>
-#include <boost/graph/graph_traits.hpp>
-
-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<ReportID> 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<u32> 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<boost::listS,
-                              boost::listS,
-                              boost::bidirectionalS,
-                              NFAGraphVertexProps,
-                              NFAGraphEdgeProps> 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
index 143dca16b79c280f50c5c03155e31f0a08d12945..e4be14c328590834cf5c15924fa670bd5ffd0d00 100644 (file)
 #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<u32> &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<u32, u32> *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<u32, u32> *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);
         }
     }
index 5d83e626cd8fc75649374660870d4471670d34ae..a2fbb28863db7358fa3bc2cc5f14dbd307b463ea 100644 (file)
@@ -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<NFAEdge, bool> add_edge(NFAVertex u, NFAVertex v, NGHolder &h) {
-    assert(edge(u, v, h.g).second == false);
-    pair<NFAEdge, bool> 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<NFAEdge, bool> add_edge(NFAVertex u, NFAVertex v,
-                                  const NFAGraph::edge_property_type &ep,
-                                  NGHolder &h) {
-    assert(edge(u, v, h.g).second == false);
-    pair<NFAEdge, bool> 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();
     }
 }
 
index 4905080882c1b519f4ea53390c3a64ae26f6b71d..fbb6ac5290c7811ae8f8302b455ce81400d07d77 100644 (file)
  * 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 <boost/graph/adjacency_iterator.hpp>
-#include <boost/graph/adjacency_list.hpp>
-#include <boost/graph/graph_traits.hpp>
+#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<ReportID> 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<u32> 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<NGHolder, NFAGraphVertexProps,
+                                  NFAGraphEdgeProps> {
 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();
-
-    NFAVertex getSpecialVertex(u32 id) const;
-
-    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<class Predicate>
-    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<class Predicate>
-    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<class Predicate>
-    friend void remove_edge_if(Predicate pred, NGHolder &h) {
-        boost::remove_edge_if(pred, h.g);
-        h.isValidNumEdges = false;
-    }
-
-    friend std::pair<NFAEdge, bool> add_edge(NFAVertex u, NFAVertex v,
-                                             NGHolder &h);
-    friend std::pair<NFAEdge, bool> 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];
-    }
+    nfa_kind kind; /* Role that this plays in Rose */
 
-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. */
+    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.
 
-    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 <typename GraphT>
-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<NGHolder::adjacency_iterator, NGHolder::adjacency_iterator>
-adjacent_vertices(NFAVertex v, const NGHolder &h) {
-    return adjacent_vertices(v, h.g);
-}
-
-static really_inline
-std::pair<NFAEdge, bool> edge(NFAVertex u, NFAVertex v, const NGHolder &h) {
-    return boost::edge(u, v, h.g);
-}
-
-static really_inline
-std::pair<NGHolder::edge_iterator, NGHolder::edge_iterator>
-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<NGHolder::in_edge_iterator, NGHolder::in_edge_iterator>
-in_edges(NFAVertex v, const NGHolder &h) {
-    return in_edges(v, h.g);
-}
-
-static really_inline
-std::pair<NGHolder::inv_adjacency_iterator, NGHolder::inv_adjacency_iterator>
-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<NGHolder::out_edge_iterator, NGHolder::out_edge_iterator>
-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<NGHolder::vertex_iterator, NGHolder::vertex_iterator>
-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);
     }
 }
 
index 8e71c337d86825e4ff5586f3f02a6792c1e5b968..2df79f501cc16d03f1235072adfb00c8bfc87068 100644 (file)
@@ -77,6 +77,26 @@ private:
     ReportID a_rep;
     ReportID b_rep;
 };
+
+/** Comparison functor used to sort by vertex_index. */
+template<typename Graph>
+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<typename Graph>
+static
+VertexIndexOrdering<Graph> make_index_ordering(const Graph &g) {
+    return VertexIndexOrdering<Graph>(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) {
index 5e5a18d9dbdcf5011391a6e5fbe92096cb4bff0e..e92790b98580e7d98f5827c5e023f47abcbd27e2 100644 (file)
@@ -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<u32> &tops,
     CharReach top_cr = calcTopVertexReach(tops, top_reach);
     g[u].char_reach = top_cr;
 
-    // Add edges in vertex index order, for determinism.
-    vector<NFAVertex> 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<u32, CharReach> &top_reach,
                         map<u32, flat_set<NFAVertex>> &unhandled_top_succs,
                         map<NFAVertex, flat_set<u32>> &unhandled_succ_tops,
                         map<u32, set<NFAVertex>> &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<NFAVertex> cand_starts;
     for (NFAVertex u : unhandled_succ_tops | map_keys) {
@@ -397,7 +389,6 @@ void reusePredsAsStarts(const NGHolder &g, const map<u32, CharReach> &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());
     }
index deaf2ffd67d40c0df26c9f7df96b87efad00a610..bfba7c71b9d70e6cac490851d65bf7d56d05229e 100644 (file)
@@ -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)" : "");
 
index 9229457c160253243ed219e6ba36bcf8cfc7c2a6..68c1bdd6a16e95d734beea853e8467a3fb3bbecf 100644 (file)
@@ -46,6 +46,7 @@
 #include <fstream>
 #include <queue>
 
+#include <boost/graph/adjacency_list.hpp>
 #include <boost/graph/boykov_kolmogorov_max_flow.hpp>
 
 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);
 
index 871c8ac7802e501ee391e661bfdc3602dfa26457..e3cfe8678c7c42e3b6d8fe292ce83614b11a4c99 100644 (file)
@@ -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<NFAVertex> &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) {
index 02b25a730f2ed820fcb6cc58f0bfc34eeade83eb..89c01a6ce3332c36584c435c703bbe1c3eb5c169 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -77,7 +77,7 @@ bool findPaths(const NGHolder &g, vector<Path> &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<Path> &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());
     }
 
index 71c9a05e329dd316ea0b2aec266d2844913aa830..375086a46a4631d50783fcd2f983f80fd4dd3a77 100644 (file)
@@ -328,7 +328,7 @@ void markToppableStarts(const NGHolder &g, const flat_set<NFAVertex> &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;
             }
index 716802ba8a02f6f9fe5a53d52b9a6598642e614b..29939fec2b2f016b0a6043cda632f87f94ceffcc 100644 (file)
@@ -80,6 +80,7 @@
 #include <vector>
 
 using namespace std;
+using boost::make_filtered_graph;
 
 namespace ue2 {
 
@@ -108,7 +109,7 @@ void findCandidates(NGHolder &g, const vector<NFAVertex> &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<NFAVertex> &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<NFAVertex> 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<NFAVertex> 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<NFAVertex, BoundedRepeatSummary> &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<NFAVertex> 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<boost::default_color_type> 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<NFAVertex> 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<NFAVertex> findDependentVertices(const NGHolder &g, NFAVertex v) {
     flat_set<NFAVertex> 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<NFAVertex> 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<NFAEdge> 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;
                 }
index 9004024fb1424fbb03c93e75991bcd93dd4abc6d..4859d864a976abccdf6150c02ac4d9c8c9a13749 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -111,6 +111,7 @@ static
 void removeEdgesFromIndex(NGHolder &g, vector<u64a> &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<u64a> &capacityMap_in,
     vector<s32> 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<u64a> &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<NFAEdge> findMinCut(NGHolder &h, const vector<u64a> &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);
index 8abc45b3a59716e0100c66f09cb180c700f62008..012b4e8d888eb18621ec881d659a3d8355d81f02 100644 (file)
@@ -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));
index 473b958669ded46d46305ae11143ef7f39a49ee9..88f1880f0bd0c8397114532455e705a19a545844 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -57,9 +57,8 @@ namespace ue2 {
 void pruneUnreachable(NGHolder &g) {
     deque<NFAVertex> 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<NFAGraph, NFAGraph&> RevNFAGraph;
-        RevNFAGraph revg(g.g);
+        typedef reverse_graph<NGHolder, NGHolder &> RevNFAGraph;
+        RevNFAGraph revg(g);
 
-        map<NFAVertex, default_color_type> colours;
+        map<RevNFAGraph::vertex_descriptor, default_color_type> colours;
 
         depth_first_visit(revg, g.acceptEod,
                           make_dfs_visitor(boost::null_visitor()),
@@ -104,7 +103,8 @@ void pruneUnreachable(NGHolder &g) {
 
 template<class nfag_t>
 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<default_color_type> &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<default_color_type> vertexColor(num_vertices(g));
 
-    bool work_done = pruneForwardUseless(g, g.g, g.start, vertexColor);
-    work_done |= pruneForwardUseless(
-        g, reverse_graph<NFAGraph, NFAGraph &>(g.g), g.acceptEod, vertexColor);
+    bool work_done = pruneForwardUseless(g, g, g.start, vertexColor);
+    work_done |= pruneForwardUseless(g, reverse_graph<NGHolder, NGHolder &>(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
index 00b2e8acabb392c3b1ff9632f1ab10df6e3733d1..7281471fccb93dead053183b02c713f7cfc4443d 100644 (file)
@@ -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<ReportID> &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 {
index 8fc5d5f3e6b28b0ac0c8391063e0a49cc97dcebc..4ca695d81e56ea3d214434609dd0cc8fc244bc05 100644 (file)
@@ -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<NFAGraph, const NFAGraph &>;
+    using RevGraph = boost::reverse_graph<NGHolder, const NGHolder &>;
     map<RevGraph::vertex_descriptor, boost::default_color_type> 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<RevGraph, RevGraph::vertex_descriptor>(dom));
@@ -674,16 +666,15 @@ bool forwardPathReachSubset(const NFAEdge &e, const NFAVertex &dom,
     }
 
     NFAVertex start = target(e, g);
-    map<NFAGraph::vertex_descriptor, boost::default_color_type> vertexColor;
+    map<NFAVertex, boost::default_color_type> 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<NFAGraph, NFAVertex>(dom));
+                          VertexIs<NGHolder, NFAVertex>(dom));
     } catch(ReachMismatch&) {
         return false;
     }
@@ -775,9 +766,8 @@ void findCyclicDom(NGHolder &g, vector<bool> &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<bool> &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<bool> &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<bool> &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<bool> &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
index c7472e0daa0f09d873b3f239e149d57513316793..0ecd7bd63466fd8169ed13e1d075af901f435093 100644 (file)
@@ -71,7 +71,7 @@ using namespace std;
 namespace ue2 {
 
 typedef ue2::unordered_set<NFAEdge> BackEdgeSet;
-typedef boost::filtered_graph<NFAGraph, bad_edge_filter<BackEdgeSet>>
+typedef boost::filtered_graph<NGHolder, bad_edge_filter<BackEdgeSet>>
     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<exit_info> &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<exit_info> exits;
     ue2::unordered_set<NFAVertex> candidate;
     ue2::unordered_set<NFAVertex> 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<NFAVertex> &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<NFAVertex> &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<NFAVertex> &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<NFAVertex> &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<NFAVertex> 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<NFAVertex> buildTopoOrder(const NGHolder &w,
                                  vector<boost::default_color_type> &colours) {
     vector<NFAVertex> 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<NFAVertex> 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<NFAVertex, u32> assignRegions(const NGHolder &g) {
 
     // Build an acyclic graph for this NGHolder.
     BackEdgeSet deadEdges;
-    depth_first_search(
-        g.g, visitor(BackEdges<BackEdgeSet>(deadEdges))
-                 .root_vertex(g.start)
-                 .color_map(make_iterator_property_map(
-                     colours.begin(), get(&NFAGraphVertexProps::index, g.g))));
+    depth_first_search(g,
+                       visitor(BackEdges<BackEdgeSet>(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<NFAVertex> topoOrder = buildTopoOrder(g, acyclic_g, colours);
index 464a68380a2e73537a5a9cadf3a3aec9f0750eb7..a56933dc47373d8f2c95f5bbac40026b7f0f7e5e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
  *
  * Redistribution and use in source and binary forms, with or without
  * 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<NFAVertex, u32> &region_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;
             }
index 5cd266dc93aae5498e40ee623c873ef950015a45..264e43128fc888730a97eaf9693b3b3c54b427f7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
  *
  * Redistribution and use in source and binary forms, with or without
  * 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<u32, RegionInfo>::const_iterator it;
@@ -98,7 +98,7 @@ void processCyclicStateForward(NGHolder &h, NFAVertex cyc,
         NFAVertex v = it->second.entry;
         const CharReach &region_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<u32, RegionInfo>::const_iterator it;
     while ((it = info.find(--region)) != info.end()) {
         NFAVertex v = it->second.entry;
         const CharReach &region_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)) {
index 6eb2a9d799256fec32b08a5987d366c49fb9a3e7..0aa6dc4b7458d1b667c1f302a580bfa14ba0f6b4 100644 (file)
@@ -61,6 +61,8 @@
 #include <boost/icl/interval_set.hpp>
 
 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<NFAGraph, ReachFilter<NFAGraph> > RepeatGraph;
+typedef boost::filtered_graph<NGHolder, ReachFilter<NGHolder>> RepeatGraph;
 
 struct ReachSubgraph {
     vector<NFAVertex> vertices;
@@ -126,9 +128,11 @@ void findInitDepths(const NGHolder &g,
     }
 }
 
-template<class Graph>
 static
-void buildTopoOrder(const Graph &g, vector<NFAVertex> &topoOrder) {
+vector<NFAVertex> buildTopoOrder(const RepeatGraph &g) {
+    /* Note: RepeatGraph is a filtered version of NGHolder and still has
+     * NFAVertex as its vertex descriptor */
+
     typedef ue2::unordered_set<NFAEdge> EdgeSet;
     EdgeSet deadEdges;
 
@@ -140,10 +144,13 @@ void buildTopoOrder(const Graph &g, vector<NFAVertex> &topoOrder) {
                           color_map(make_assoc_property_map(colours)));
     auto acyclic_g = make_filtered_graph(g, make_bad_edge_filter(&deadEdges));
 
+    vector<NFAVertex> 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<NFAVertex> &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<NFAVertex> &pred,
                  const ue2::unordered_set<NFAVertex> &succ,
                  const flat_set<ReportID> &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<NFAVertex> &verts,
 
     NFAUndirectedGraph ug;
     ue2::unordered_map<NFAVertex, NFAUndirectedVertex> old2new;
-    ue2::unordered_map<u32, NFAVertex> newIdx2old;
-    createUnGraph(verts_g.g, true, true, ug, old2new, newIdx2old);
+    createUnGraph(verts_g, true, true, ug, old2new);
 
     ue2::unordered_map<NFAUndirectedVertex, u32> 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<NFAVertex> &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<ReachSubgraph> &rs,
                          const u32 minNumVertices) {
-    const ReachFilter<NFAGraph> fil(&g.g);
-    const RepeatGraph rg(g.g, fil);
+    const ReachFilter<NGHolder> 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<ReachSubgraph> &rs,
     }
 
     NFAUndirectedGraph ug;
-    ue2::unordered_map<NFAVertex, NFAUndirectedVertex> old2new;
-    ue2::unordered_map<u32, NFAVertex> newIdx2old;
-    createUnGraph(rg, true, true, ug, old2new, newIdx2old);
+    unordered_map<RepeatGraph::vertex_descriptor, NFAUndirectedVertex> old2new;
+    createUnGraph(rg, true, true, ug, old2new);
 
-    ue2::unordered_map<NFAUndirectedVertex, u32> repeatMap;
+    unordered_map<NFAUndirectedVertex, u32> 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<NFAVertex> topoOrder;
-    buildTopoOrder(rg, topoOrder);
+    vector<NFAVertex> 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<CharReach> &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<NFAVertex, NFAVertex> &lhs_map,
                      const NGHolder &g, const NFAVertex first,
                      const map<u32, vector<vector<CharReach>>> &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<NFAEdge> dead;
     BackEdges<set<NFAEdge> > 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<NFAVertex> &straw) const {
-        DEBUG_PRINTF("walk from %u\n", g[v].index);
+        DEBUG_PRINTF("walk from %zu\n", g[v].index);
         ue2::unordered_set<NFAVertex> 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<BoundedRepeatData> &all_repeats,
                                vector<NFAVertex> &straw) {
-    typedef boost::reverse_graph<NFAGraph, const NFAGraph&> RevGraph;
-    const RevGraph revg(g.g);
+    typedef boost::reverse_graph<NGHolder, const NGHolder &> RevGraph;
+    const RevGraph revg(g);
 
     auto cyclic = StrawWalker<RevGraph>(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<BoundedRepeatData> &all_repeats,
                                vector<NFAVertex> &straw) {
-    return StrawWalker<NFAGraph>(g, g.g, all_repeats).walk(v, straw);
+    return StrawWalker<NGHolder>(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<NFAVertex> 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<BoundedRepeatData> &all_repeats) {
     vector<NFAVertex> 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<u32, u32> &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<NFAVertex> 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;
     }
index 3b30a6892e1e8cc08f329ae60c65e8c04fdfb74d..7bb3e9918f76951b06e4d8ac45ab322d40087ac6 100644 (file)
@@ -52,11 +52,7 @@ namespace ue2 {
 static
 void wireStartToTops(NGHolder &g, const flat_set<NFAVertex> &tops,
                      vector<NFAEdge> &tempEdges) {
-    // Construct edges in vertex index order, for determinism.
-    vector<NFAVertex> 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<NFAVertex> &tops,
     vector<NFAEdge> tempEdges;
     wireStartToTops(g, tops, tempEdges);
 
-    renumberGraphVertices(g);
+    renumber_vertices(g);
 
     vector<NFAVertex> temp = getTopoOrdering(g);
 
@@ -144,7 +140,7 @@ getStateIndices(const NGHolder &h, const vector<NFAVertex> &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<NFAVertex> &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);
index 46f180a8a2bb0e020674568e18bd263cc7b22a99..b3649ce0da94bcd56b4e913f27a7a9ce78c21e05 100644 (file)
@@ -538,7 +538,7 @@ void getRegionRoseLiterals(const NGHolder &g,
         DEBUG_PRINTF("inspecting region %u\n", region);
         set<ue2_literal> 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<ue2_literal> ss = getLiteralSet(g, v, false);
@@ -573,8 +573,7 @@ void gatherBackEdges(const NGHolder &g,
                      ue2::unordered_map<NFAVertex, vector<NFAVertex>> *out) {
     set<NFAEdge> backEdges;
     BackEdges<set<NFAEdge>> 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<VertLitInfo> LitCollection::pickNext() {
         unique_ptr<VertLitInfo> 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<NFAVertex> 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<NFAVertex> verts(pred.begin(), pred.end());
-    sort(verts.begin(), verts.end(), VertexIndexOrdering<NGHolder>(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<RoseInEdge> &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<NFAVertex, NFAVertex> temp_map;
         shared_ptr<NGHolder> new_lhs = make_shared<NGHolder>();
         splitLHS(h, pivot, new_lhs.get(), &temp_map);
@@ -1774,8 +1768,8 @@ bool doNetflowCut(RoseInGraph &ig, const vector<RoseInEdge> &to_cut,
         return false;
     }
 
-    h.renumberVertices();
-    h.renumberEdges();
+    renumber_vertices(h);
+    renumber_edges(h);
     /* Step 1: Get scores for all edges */
     vector<u64a> 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<NFAVertex> &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<RoseInGraph> 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<RoseInGraph> 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<RoseInGraph> igp;
 
index b5867bb91ff2b365e884a2797391d6825f1ef594..1d7be65b9e3dba0a1ebdfc560d115f2ad055806f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -125,7 +125,7 @@ bool findLiterals(const NGHolder &g,
         set<sls_literal> &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<sls_literal> &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();
             }
         }
index 09687c4f8af3c4747dff0d9012f58aa1cb43b4b5..862f5b539073d748c958476d58bb1512db89616c 100644 (file)
@@ -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<NFAEdge> be;
     BackEdges<set<NFAEdge> > 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<NFAVertex, u32> &regions,
     vector<NFAVertex> 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<NFAVertex, u32> &regions,
     }
 
     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<som_plan> &plan, u32 parent) {
 // Fetches all preds of {accept, acceptEod} for this graph.
 static
 void addReporterVertices(const NGHolder &g, vector<NFAVertex> &reporters) {
-    // Order reporter vertices by index for determinism.
-    set<NFAVertex, VertexIndexOrdering<NGHolder> > tmp(g);
+    set<NFAVertex> 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<NFAVertex> &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<NFAVertex> &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<NFAVertex> &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<NFAVertex, NFAVertex>::const_iterator it =
                 mapping.find(v);
             assert(it != mapping.end());
@@ -1105,7 +1100,7 @@ void expandGraph(NGHolder &g, ue2::unordered_map<NFAVertex, u32> &regions,
     }
 
     for (auto enter : enters) {
-        DEBUG_PRINTF("processing enter %u\n", g[enter].index);
+        DEBUG_PRINTF("processing enter %zu\n", g[enter].index);
         map<NFAVertex, NFAVertex> 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<NFAVertex, u32> &regions,
                               [&](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<NFA> 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<SomRevNfa> &som_nfas, const NGHolder &g,
         return true;
     }
 
-    g2.renumberVertices(); // for findMinWidth, findMaxWidth.
+    renumber_vertices(g2); // for findMinWidth, findMaxWidth.
 
     aligned_unique_ptr<NFA> nfa = makeBareSomRevNfa(g2, cc);
     if (!nfa) {
@@ -2220,7 +2215,7 @@ bool leadingLiterals(const NGHolder &g, set<ue2_literal> *lits,
         for (const auto &m : curr) {
             const NFAVertex u = m.first;
             const vector<ue2_literal> &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<ue2_literal> *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<ue2_literal> *lits,
                 CharReach cr = g[v].char_reach;
                 vector<ue2_literal> &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<ue2_literal> *lit_out,
     set<NFAVertex> 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<NFAVertex> 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<u32, region_info>::const_iterator lit = info.begin();
     while (1) {
@@ -2390,7 +2384,7 @@ bool splitOffBestLiteral(const NGHolder &g,
                          const ue2::unordered_map<NFAVertex, u32> &regions,
                          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<u32, region_info>::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<NGHolder> 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);
index 924cfad1eb1b46c2caf096ae4007d1aac25c0fa5..33544ec173697031fe5508856f20162a262b7fd8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -155,13 +155,13 @@ bool addSomRedundancy(NGHolder &g, vector<DepthMinMax> &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) {
index 676fb523e37527da52f12f4293811ee747e4698d..c43373415c18522d2feddd2e858bbc95c003066d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -76,7 +76,7 @@ vector<DepthMinMax> getDistancesFromSOM(const NGHolder &g_orig) {
         clear_in_edges(v, g);
     }
 
-    //dumpGraph("som_depth.dot", g.g);
+    //dumpGraph("som_depth.dot", g);
 
     vector<DepthMinMax> 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<NFAEdge> be;
     BackEdges<set<NFAEdge>> 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));
index 4576a49878b69db848bddbaa4d58eff2973288b6..ce267d0f69f0c6228135ae238226260ad0b44806 100644 (file)
@@ -87,7 +87,7 @@ void splitLHS(const NGHolder &base, const vector<NFAVertex> &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<NFAVertex> &pivots,
                           vector<NFAVertex> &succ) {
     assert(!pivots.empty());
 
-    // Note: for determinism, we must sort our successor sets by vertex_index.
-    set<NFAVertex, VertexIndexOrdering<NGHolder> > adj(g), adj_temp(g);
+    set<NFAVertex> adj;
+    set<NFAVertex> adj_temp;
 
     insert(&adj, adjacent_vertices(pivots.at(0), g));
 
index 21703f8b0eaeb5ba32b0234edad8cc779940cb27..ebec3a4a17d4b72abad2181781f3e21ce960c47d 100644 (file)
@@ -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<DepthMinMax> &som_depths,
                      const ue2::unordered_map<NFAVertex, u32> &region_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<NFAVertex> q;
 
@@ -301,7 +299,7 @@ void findDerivedSquashers(const NGHolder &g, const vector<NFAVertex> &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<NFAVertex> &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<NFAVertex> findUnreachable(const NGHolder &g) {
-    const boost::reverse_graph<NFAGraph, const NFAGraph &> revg(g.g);
+    const boost::reverse_graph<NGHolder, const NGHolder &> revg(g);
 
     ue2::unordered_map<NFAVertex, boost::default_color_type> colours;
     colours.reserve(num_vertices(g));
@@ -633,7 +630,7 @@ vector<NFAVertex> findUnreachable(const NGHolder &g) {
     vector<NFAVertex> 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);
         }
     }
index 3326d6f4f37dee6591ddd90f719fb8b08d8bba75..baab3b0fe02300f01a1e49f6cfa5620097e78255 100644 (file)
@@ -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 {
index ddab88252abe7a02316adc1d7560f5979f04c656..d78835789071ee6b0514a0d6e91332ce275b6854 100644 (file)
 #include <map>
 #include <vector>
 
-#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;
 
 /**
index 12632e0565475d098e3d8e28052bb30719d6f18a..7df6c7dc4d45f22912f62f39a30d6d1640886674 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
 #include "util/graph_range.h"
 #include "util/ue2_containers.h"
 
+#include <vector>
+
+#include <boost/graph/adjacency_list.hpp>
+
 namespace ue2 {
 
 /**
@@ -51,7 +55,7 @@ namespace ue2 {
 typedef boost::adjacency_list<boost::setS,        // out edges
                               boost::listS,       // vertices
                               boost::undirectedS, // graph is undirected
-                              boost::property<boost::vertex_index_t, u32> >
+                              boost::property<boost::vertex_index_t, size_t> >
 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 <typename GraphT>
 void createUnGraph(const GraphT &g,
-                   bool excludeStarts,
-                   bool excludeAccepts,
-                   NFAUndirectedGraph &ug,
-                   ue2::unordered_map<NFAVertex, NFAUndirectedVertex> &old2new,
-                   ue2::unordered_map<u32, NFAVertex> &newIdx2old) {
-    u32 idx = 0;
+           bool excludeStarts,
+           bool excludeAccepts,
+           NFAUndirectedGraph &ug,
+           ue2::unordered_map<typename GraphT::vertex_descriptor,
+                              NFAUndirectedVertex> &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))) {
index 352359f2c0a38f2a0ac08901236994a766942127..383aa142d04564ba6d4fbe52ba47a6a39d2cfabf 100644 (file)
@@ -176,7 +176,7 @@ void findSeeds(const NGHolder &h, const bool som, vector<NFAVertex> *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<NFAVertex> *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;
         }
 
index de4ca656f76e8765f7f3eaaa38aa72141a2dee21..ad40debeb46a7ee75094231ef943c6e3f59c99f6 100644 (file)
@@ -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<NFAEdge> dead;
     BackEdges<set<NFAEdge>> 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<NFAVertex> findVerticesInCycles(const NGHolder &g) {
     map<NFAVertex, size_t> 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<size_t, set<NFAVertex> > comps;
 
@@ -298,8 +291,7 @@ set<NFAVertex> 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<NFAVertex> getTopoOrdering(const NGHolder &g) {
     EdgeSet backEdges;
     BackEdges<EdgeSet> 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<NFAVertex> 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<NFAVertex> &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<NFAVertex> 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<NGHolder> cloneHolder(const NGHolder &in) {
 void reverseHolder(const NGHolder &g_in, NGHolder &g) {
     // Make the BGL do the grunt work.
     ue2::unordered_map<NFAVertex, NFAVertex> 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<NFAVertex> 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<bool> 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<bool> 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
index 6b5090ceabc3c4606e884107ec2234a16499217c..a07525339a17ffa38cb05c26e1213e85a184e048 100644 (file)
@@ -65,9 +65,8 @@ bool is_dot(NFAVertex v, const GraphT &g) {
 template<class U>
 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<class ContTemp = flat_set<NFAVertex>>
@@ -81,9 +80,8 @@ ContTemp succs(NFAVertex u, const NGHolder &g) {
 template<class U>
 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<class ContTemp = flat_set<NFAVertex>>
@@ -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<typename GraphT>
-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<typename GraphT>
-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 <typename GraphT>
 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 <typename GraphT>
-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 <typename GraphT>
-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<NFAVertex> getTopoOrdering(const NGHolder &g);
 
-/** Comparison functor used to sort by vertex_index. */
-template<typename Graph>
-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<typename Graph>
-static
-VertexIndexOrdering<Graph> make_index_ordering(const Graph &g) {
-    return VertexIndexOrdering<Graph>(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
index 9c99ba8a5bc2c4b5e7587611403d3765e1ca3adb..9e50ea3d08b049647fbd5c068892e6d4a19db8de 100644 (file)
@@ -464,7 +464,7 @@ void getRegionRoseLiterals(const NGHolder &g, bool seeking_anchored,
         DEBUG_PRINTF("inspecting region %u\n", region);
         set<ue2_literal> 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<ue2_literal> ss = getLiteralSet(g, v, false);
@@ -669,7 +669,7 @@ unique_ptr<VertLitInfo> 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<NFAVertex> poisonVertices(const NGHolder &h, const RoseInGraph &vg,
     set<NFAVertex> 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<NFAVertex, NFAVertex> temp_map;
             shared_ptr<NGHolder> new_lhs = make_shared<NGHolder>();
             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");
index 5fb58ee4d2c731a03c814731f74c42eb3eb719ff..d596b7b5d8eb8104030d533771ba691a5bcad44c 100644 (file)
@@ -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<NFAGraph, SpecialEdgeFilter> g(h.g, filter);
+    boost::filtered_graph<NGHolder, SpecialEdgeFilter> 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<NFAGraph, SpecialEdgeFilter> g(h.g, filter);
+    boost::filtered_graph<NGHolder, SpecialEdgeFilter> 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<NFAEdge>(-1))
-            .vertex_index_map(index_map)
             .color_map(make_iterator_property_map(colors.begin(), index_map)));
 
     depth acceptDepth, acceptEodDepth;
index 72a791ba9ed01826ad7a592d68561e8662bfaf6b..e185bb37039def825777ac544cd722c049121d1a 100644 (file)
@@ -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<NFAVertex> 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<u8> &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<NGHolder *, vector<RoseInEdge> > graphs;
     vector<NGHolder *> 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<ReportID, u32> &allocated_reports,
                                  flat_set<u32> &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;
index ef83cae1271474ba550502024f8bab0b9427aca9..f46e10040646cbe5d4d6147fa1e5120656b4564e 100644 (file)
@@ -532,7 +532,7 @@ void addTransientMask(RoseBuildImpl &build, const vector<CharReach> &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
index 60732ff9105fc63d709a8267777b5bbeb8e65cd0..3d0affc6b7f40048b5121b7263197ee2867b8b98 100644 (file)
@@ -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;
         }
index 80e6450d324c649bcc8abcc6614dc09995a51ea1..43df79628242bff72db7c09dd338668e5bbfa521 100644 (file)
@@ -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<CharReach> &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<pair<CharReach, u8>, 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<RoseVertex> 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<u32, vector<RoseEdge>> findEdgesByLiteral(const RoseBuildImpl &build) {
         auto edge_list = vector<RoseEdge>(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<RoseEdge> 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<RoseEngine> 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 */
index c65e840d880c7802ca120962b0a3338c57ac56a5..7987b0f6138e79c89afbeed263f7e8d8d65634a6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
  *
  * Redistribution and use in source and binary forms, with or without
  * 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<rose_literal_id> lits = literals_for_vertex(tbi, v);
         for (const auto &e : lits) {
             DEBUG_PRINTF("%s +%u\n", dumpString(e.s).c_str(), e.delay);
index 38c488be31447913a903dcf639a5faf285f8dd60..2f1af8a467a220878267c80ef9236e6dd2e4a9a8 100644 (file)
@@ -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<NFAEdge> 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<RoseVertex> 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<RoseVertex> 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;
         }
     }
index dfc0ed2320aeefa16369ceae344730e8eb191489..ae08b7cb78e1619a9ae7a61501a186815485fce5 100644 (file)
@@ -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<RoseVertex> &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<RoseVertex> 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<RoseVertex> 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<NFAVertex> 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.
index 516548b3ef214e18e89a1594025cb5e6f14aa07b..105ee338d3edd5ed37204be2bac64281c4bab9f2 100644 (file)
@@ -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) {
index 5e477e3b4ac542f29207718b438fffad4139481e..0a1c501f2b91ec86ed247a1dd559c9a593214f40 100644 (file)
@@ -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<RoseVertex> 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<RoseVertex, rose_group> 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);
         }
index b3f986aa817d7a4e3a456e4c0d9f28fedae76847..6b326d34bfb1605b2ffcad23e464cafd0f401d17 100644 (file)
@@ -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<RoseVertex, RoseVertex> ghost;
-    size_t vertexIndex;
     ReportID getNewNfaReport() override {
         return next_nfa_report++;
     }
index 73f9e99b3c62d83c5bb90bb96317f66bdf5c5c84..f3e7680f7396b01b6ab9a8759c69cebe182fc8a8 100644 (file)
@@ -110,7 +110,7 @@ void contractVertex(NGHolder &g, NFAVertex v,
 static
 u32 findMaxLiteralMatches(const NGHolder &h, const set<ue2_literal> &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<u32> terms;
@@ -163,7 +163,7 @@ u32 findMaxLiteralMatches(const NGHolder &h, const set<ue2_literal> &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<u8> &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;
     }
index 7c58f931d980d863c9609c289dcc59ab671ef085..d2c4b541bd1960ab42a5592cb99f66db2eea03f8 100644 (file)
@@ -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<s32, CharReach>());
@@ -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;
index 522ff6b63e85b79ef2971644422aa8450ca729a6..f9251b8a45f5a30ad9f45bd499b3807c8c7850be 100644 (file)
@@ -102,7 +102,7 @@ bool maskFromLeftGraph(const LeftEngInfo &left, vector<u8> &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;
 
index 054dd12fdf8ee1845a343f92ff930ae1581edfcc..01db84a15acc6379792974a057823b23004eee8d 100644 (file)
@@ -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<RoseEdge> 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<RoseVertex> &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<RoseVertex> parents;
 };
 }
 
@@ -1491,7 +1493,7 @@ void mergeLeftfixesVariableLag(RoseBuildImpl &tbi) {
 
     map<RoseMergeKey, RoseBouquet> rosesByParent;
     RoseGraph &g = tbi.g;
-    RoseVertexSet parents(g);
+    set<RoseVertex> 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<u32, u32> &top_mapping) {
         }
         flat_set<u32> 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];
index dcb2a4ebbde5fca1eab1d506e91dca9973162853..50ca1d9e403a4a0e912fc5f22d85b8d86bd09844 100644 (file)
@@ -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<RoseVertex> &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;
             }
         }
index 4757eb112bfa7a5571d26179dd0e8b00c20d027c..099e3e7af323e20d1c78fda49974acec5df5c8f0 100644 (file)
@@ -111,11 +111,9 @@ struct AliasInEdge : EdgeAndVertex {
 
 class CandidateSet {
 public:
-    typedef RoseVertexSet::iterator iterator;
+    typedef set<RoseVertex>::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<RoseVertex> main_cont; /* deterministic iterator */
     ue2::unordered_set<RoseVertex> 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<RoseVertex> &b_verts = rai.rev_leftfix[b_left];
     set<RoseVertex> 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<RoseVertex> 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());
index 85cfc01015786aa5102f3beace6a1dca72ad3591..81bb68459bb8ffabf818b17e78d7cf5926eece45 100644 (file)
@@ -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<RoseVertex, VertexIndexComp> RoseVertexSet;
-
 /**
  * \brief Add two Rose depths together, coping correctly with infinity at
  * ROSE_BOUND_INF.
index 6bfcee4859bb69f13e08be121017a531d3f705f2..182b62ee6fb3e6f04919c37a866b031a0931da29 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
  *
  * Redistribution and use in source and binary forms, with or without
  * 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;
         }
 
index 6abe629bbc504c6afc517766c3475acda6888447..c3af749fbe7da1626b0342c69d6e89339140976d 100644 (file)
 #include "util/charreach.h"
 #include "util/depth.h"
 #include "util/ue2_containers.h"
+#include "util/ue2_graph.h"
 
 #include <memory>
 #include <set>
-#include <boost/graph/adjacency_list.hpp>
-#include <boost/graph/graph_traits.hpp>
 
 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<u32> 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<boost::listS, // out edge list per vertex
-                                        boost::listS, // vertex list
-                                        boost::bidirectionalS, // bidirectional
-                                        RoseVertexProps, // bundled vertex properties
-                                        RoseEdgeProps, // bundled edge properties
-                                        boost::listS // graph edge list
-                                        >;
-
+struct RoseGraph : public ue2_graph<RoseGraph, RoseVertexProps, RoseEdgeProps> {
+    friend class RoseBuildImpl; /* to allow index renumbering */
+};
 using RoseVertex = RoseGraph::vertex_descriptor;
 using RoseEdge = RoseGraph::edge_descriptor;
 
index fbd6858b20be78f60f221092bd50a2b94be39a68..172b58e8417466cac2dd523b3decc3c00c77b393 100644 (file)
@@ -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));
     }
 
index 14d4d9b256ddcb4df5281950c65095eba0aeb30e..0e2185768fe1792acd3f2c904bd1976738571e34 100644 (file)
 #include "ue2common.h"
 #include "rose/rose_common.h"
 #include "util/ue2_containers.h"
+#include "util/ue2_graph.h"
 #include "util/ue2string.h"
 
 #include <memory>
 
-#include <boost/graph/graph_traits.hpp>
-#include <boost/graph/adjacency_list.hpp>
-
 namespace ue2 {
 
 class NGHolder;
@@ -128,6 +126,7 @@ public:
     flat_set<ReportID> 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<raw_som_dfa> haig;
 
     u32 graph_lag;
+    size_t index = 0;
 };
 
-typedef boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS,
-                              RoseInVertexProps,
-                              RoseInEdgeProps> RoseInGraph;
+struct RoseInGraph
+    : public ue2_graph<RoseInGraph, RoseInVertexProps, RoseInEdgeProps> {
+};
 typedef RoseInGraph::vertex_descriptor RoseInVertex;
 typedef RoseInGraph::edge_descriptor RoseInEdge;
 
index cce6ff359b8fc53fd9c7c457da13d30c17fc597f..3b31b38e065e2adae9c0561b361b1a7c8ade1410 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
  *
  * Redistribution and use in source and binary forms, with or without
  * 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<RoseInVertex, size_t> *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<RoseInVertex> topo_order(const RoseInGraph &g) {
-    map<RoseInVertex, size_t> index_map;
-    populateIndexMap(g, &index_map);
-
+    assert(hasCorrectlyNumberedVertices(g));
     vector<RoseInVertex> 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<RoseInGraph> cloneRoseGraph(const RoseInGraph &ig) {
+    assert(hasCorrectlyNumberedVertices(ig));
     unique_ptr<RoseInGraph> out = make_unique<RoseInGraph>();
 
     unordered_map<const NGHolder *, shared_ptr<NGHolder>> graph_map;
@@ -120,12 +109,8 @@ unique_ptr<RoseInGraph> cloneRoseGraph(const RoseInGraph &ig) {
         }
     }
 
-    map<RoseInVertex, size_t> 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;
 }
 
index d395a7af62638063b0a9fb724374a36a19604222..108bca8aa4f51403ea2903718202df4d47b8f615 100644 (file)
@@ -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);
index 9de78f4455f3711ab62e54f97265b1e1efaf6aa1..971ea362315794c15888ccaf7a371b6fd9f8372a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
  *
  * Redistribution and use in source and binary forms, with or without
  * 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"
 
index 74b45414a95f296c137b331a710a48dae7392c6d..4c159ec2466a3d56dc61a5e180809c10c99fdb4b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
  *
  * Redistribution and use in source and binary forms, with or without
  * 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<CharReach> &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) {
index 9c3362bc6ff9b51a420b696cfec1f56b1156ad3b..45b707f1e001a8703750ea216ed04f6d6e5454ee 100644 (file)
@@ -38,6 +38,7 @@
 #include <cstdio>
 #include <ostream>
 #include <string>
+#include <vector>
 
 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<CharReach> &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);
 
index d15e77aa9fd6f5dd7e6f83930ac2dca9e25f69ac..ae7c2c90984259bff50be005dbbb2cc512a6b88c 100644 (file)
 #include "util/graph_range.h"
 #include "util/ue2_containers.h"
 
-#include <boost/graph/adjacency_iterator.hpp>
-#include <boost/graph/adjacency_list.hpp>
 #include <boost/graph/depth_first_search.hpp>
-#include <boost/graph/graph_traits.hpp>
+
+#include <algorithm>
+#include <utility>
+#include <vector>
 
 namespace ue2 {
 
 /** \brief True if the given vertex has no out-edges. */
 template<class Graph>
 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<class Graph>
-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<class Graph>
-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 <class Graph>
-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<class Graph>
-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<class Graph>
-std::pair<typename Graph::edge_descriptor, bool>
-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<class Graph>
 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 <class Graph>
-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<class Graph, class SourceCont, class OutCont>
@@ -329,6 +218,40 @@ std::pair<typename Graph::edge_descriptor, bool> add_edge_if_not_present(
     return e;
 }
 
+#ifndef NDEBUG
+
+template <class Graph>
+bool hasCorrectlyNumberedVertices(const Graph &g) {
+    auto count = num_vertices(g);
+    std::vector<bool> 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 <class Graph>
+bool hasCorrectlyNumberedEdges(const Graph &g) {
+    auto count = num_edges(g);
+    std::vector<bool> 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
index 8281469553f3aba77a1bf772dccb33c844d2e564..3df06911a729a8902fda800af19a221bb56476e6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
  *
  * Redistribution and use in source and binary forms, with or without
  * 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 <boost/graph/adjacency_list.hpp>
 #include <boost/range/iterator_range.hpp>
 
 namespace ue2 {
diff --git a/src/util/ue2_graph.h b/src/util/ue2_graph.h
new file mode 100644 (file)
index 0000000..07c2474
--- /dev/null
@@ -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 <boost/operators.hpp>
+#include <boost/functional/hash.hpp>
+#include <boost/graph/properties.hpp> /* vertex_index_t, ... */
+#include <boost/pending/property.hpp> /* no_property */
+#include <boost/property_map/property_map.hpp>
+#include <boost/intrusive/list.hpp>
+#include <boost/iterator/iterator_adaptor.hpp>
+#include <boost/iterator/iterator_facade.hpp>
+
+#include <tuple> /* tie */
+#include <utility> /* 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<typename Graph,
+         typename VertexPropertyType = graph_detail::default_vertex_property,
+         typename EdgePropertyType = graph_detail::default_edge_property>
+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<boost::intrusive::tag<out_edge_tag> >;
+
+    /* 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::tag<in_edge_tag>,
+                   boost::intrusive::link_mode<boost::intrusive::normal_link> >;
+
+    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<typename hook_type> using vertex_edge_list
+        = boost::intrusive::list<edge_node,
+                                 boost::intrusive::base_hook<hook_type> >;
+
+    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_hook> 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_hook> 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<typename T> 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<vertex_node,
+             boost::intrusive::base_hook<boost::intrusive::list_base_hook<> > >;
+
+    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<out_edge_hook>::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<vertex_descriptor> {
+    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<edge_descriptor> {
+    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<typename BundleType, typename dummy = void>
+    struct bundle_key_type {
+    };
+
+    template<typename dummy>
+    struct bundle_key_type<VertexPropertyType, dummy> {
+        using type = vertex_descriptor;
+    };
+
+    template<typename dummy>
+    struct bundle_key_type<EdgePropertyType, dummy> {
+        using type = edge_descriptor;
+    };
+
+public:
+    class out_edge_iterator : public boost::iterator_adaptor<
+        out_edge_iterator,
+        typename vertex_edge_list<out_edge_hook>::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<out_edge_hook>::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<edge_node *>(&*super::base()));
+        }
+    };
+
+    class in_edge_iterator : public boost::iterator_adaptor<
+        in_edge_iterator,
+        typename vertex_edge_list<in_edge_hook>::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<in_edge_hook>::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<edge_node *>(&*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<vertex_node *>(&*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_edge_iterator, out_edge_iterator>
+    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_edge_iterator, out_edge_iterator>
+    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_edge_iterator, in_edge_iterator>
+    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<adjacency_iterator, adjacency_iterator>
+    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_descriptor, bool> 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_adjacency_iterator, inv_adjacency_iterator>
+    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<edge_descriptor, bool>
+    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<class Iter>
+    friend
+    void remove_edge(Iter it, Graph &g) {
+        remove_edge(*it, g);
+    }
+
+    template<class Predicate>
+    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<class Predicate>
+    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<class Predicate>
+    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<vertex_iterator, vertex_iterator> 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<edge_iterator, edge_iterator> 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<typename R, typename P_of>
+    struct prop_map : public boost::put_get_helper<R, prop_map<R, P_of> > {
+        using value_type = typename std::decay<R>::type;
+        using reference = R;
+        using key_type = typename bundle_key_type<P_of>::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<typename R>
+    struct prop_map_all : public boost::put_get_helper<R, prop_map_all<R> > {
+        using value_type = typename std::decay<R>::type;
+        using reference = R;
+        using key_type = typename bundle_key_type<value_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<typename P_type, typename P_of>
+    friend
+    prop_map<P_type &, P_of> get(P_type P_of::*t, Graph &) {
+        return prop_map<P_type &, P_of>(t);
+    }
+
+    template<typename P_type, typename P_of>
+    friend
+    prop_map<const P_type &, P_of> get(P_type P_of::*t, const Graph &) {
+        return prop_map<const P_type &, P_of>(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<size_t &, VertexPropertyType>
+    get(boost::vertex_index_t, Graph &g) {
+        return get(&VertexPropertyType::index, g);
+    }
+
+    friend
+    prop_map<const size_t &, VertexPropertyType>
+    get(boost::vertex_index_t, const Graph &g) {
+        return get(&VertexPropertyType::index, g);
+    }
+
+    friend
+    prop_map<size_t &, EdgePropertyType>
+    get(boost::edge_index_t, Graph &g) {
+        return get(&EdgePropertyType::index, g);
+    }
+
+    friend
+    prop_map<const size_t &, EdgePropertyType>
+    get(boost::edge_index_t, const Graph &g) {
+        return get(&EdgePropertyType::index, g);
+    }
+
+    friend
+    prop_map_all<VertexPropertyType &> get(boost::vertex_all_t, Graph &) {
+        return {};
+    }
+
+    friend
+    prop_map_all<const VertexPropertyType &> get(boost::vertex_all_t,
+                                                 const Graph &) {
+        return {};
+    }
+
+    friend
+    prop_map_all<EdgePropertyType &> get(boost::edge_all_t, Graph &) {
+        return {};
+    }
+
+    friend
+    prop_map_all<const EdgePropertyType &> get(boost::edge_all_t,
+                                               const Graph &) {
+        return {};
+    }
+
+    friend
+    prop_map_all<VertexPropertyType &> get(boost::vertex_bundle_t, Graph &) {
+        return {};
+    }
+
+    friend
+    prop_map_all<const VertexPropertyType &> get(boost::vertex_bundle_t,
+                                                 const Graph &) {
+        return {};
+    }
+
+    friend
+    prop_map_all<EdgePropertyType &> get(boost::edge_bundle_t, Graph &) {
+        return {};
+    }
+
+    friend
+    prop_map_all<const EdgePropertyType &> get(boost::edge_bundle_t,
+                                               const Graph &) {
+        return {};
+    }
+
+    template<typename Prop, typename K>
+    friend
+    auto get(Prop p, Graph &g, K key) -> decltype(get(p, g)[key]) {
+        return get(p, g)[key];
+    }
+
+    template<typename Prop, typename K>
+    friend
+    auto get(Prop p, const Graph &g, K key) -> decltype(get(p, g)[key]) {
+        return get(p, g)[key];
+    }
+
+    template<typename Prop, typename K, typename V>
+    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<edge_descriptor, bool>
+    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<typename Graph, typename Prop>
+struct property_map<Graph, Prop,
+                typename std::enable_if<
+                    std::is_base_of<ue2::graph_detail::graph_base, Graph>::value
+                 >::type > {
+    typedef decltype(get(std::declval<Prop>(),
+                         std::declval<Graph &>())) type;
+    typedef decltype(get(std::declval<Prop>(),
+                         std::declval<const Graph &>())) const_type;
+};
+
+}
+#endif
index 3ab3326d552e18689629ec02f46dc96af5bac8d7..3f81ac132093586177212c4b2fb83110465303a5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
 #include "config.h"
 #include "gtest/gtest.h"
 #include "util/graph.h"
+#include "util/ue2_graph.h"
 
 #include <boost/graph/adjacency_iterator.hpp>
 #include <boost/graph/adjacency_list.hpp>
 #include <boost/graph/graph_traits.hpp>
+#include <boost/graph/reverse_graph.hpp>
+
+#include <type_traits>
 
 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";
+};
+
+struct SimpleG : public ue2_graph<SimpleG, SimpleV, SimpleE> {
+};
+
+TEST(ue2_graph, graph_concept) {
+    static_assert(std::is_same<SimpleG::vertex_descriptor,
+                               graph_traits<SimpleG>::vertex_descriptor>::value,
+                  "vertex_descriptor");
+    static_assert(std::is_same<SimpleG::edge_descriptor,
+                               graph_traits<SimpleG>::edge_descriptor>::value,
+                  "edge_descriptor");
+    static_assert(std::is_same<SimpleG::directed_category,
+                               graph_traits<SimpleG>::directed_category>::value,
+                  "directed_category");
+    static_assert(std::is_same<SimpleG::edge_parallel_category,
+                           graph_traits<SimpleG>::edge_parallel_category>::value,
+                  "edge_parallel_category");
+    static_assert(std::is_same<SimpleG::traversal_category,
+                               graph_traits<SimpleG>::traversal_category>::value,
+                  "traversal_category");
+
+    UNUSED SimpleG::vertex_descriptor n = SimpleG::null_vertex();
+
+    BOOST_CONCEPT_ASSERT((GraphConcept<SimpleG>));
+}
+
+TEST(ue2_graph, vertex_list_concept) {
+    BOOST_CONCEPT_ASSERT((VertexListGraphConcept<SimpleG>));
+}
+
+TEST(ue2_graph, edge_list_concept) {
+    BOOST_CONCEPT_ASSERT((EdgeListGraphConcept<SimpleG>));
+}
+
+TEST(ue2_graph, incidence_concept) {
+    BOOST_CONCEPT_ASSERT((IncidenceGraphConcept<SimpleG>));
+}
+
+TEST(ue2_graph, bidi_concept) {
+    BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept<SimpleG>));
+}
+
+TEST(ue2_graph, mutable_concept) {
+    BOOST_CONCEPT_ASSERT((MutableGraphConcept<SimpleG>));
+}
+
+TEST(ue2_graph, property_concept) {
+    static_assert(std::is_same<SimpleG::vertex_property_type, SimpleV>::value,
+                  "vertex_property_type");
+    static_assert(std::is_same<SimpleG::edge_property_type, SimpleE>::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<SimpleG>::vertex_property_type,
+    //                   SimpleV>::value,
+    //               "vertex_property_type");
+    // static_assert(std::is_same<
+    //                   typename graph_traits<SimpleG>::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<SimpleG>::type,
+                      SimpleV>::value,
+                  "vertex_property_type");
+    static_assert(std::is_same<
+                      typename edge_property_type<SimpleG>::type,
+                      SimpleE>::value,
+                  "edge_property_type");
+
+    BOOST_CONCEPT_ASSERT((VertexMutablePropertyGraphConcept<SimpleG>));
+    BOOST_CONCEPT_ASSERT((EdgeMutablePropertyGraphConcept<SimpleG>));
+}
+
+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_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));
+    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));
+
+    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(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(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);
+
+    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(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));
+    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);
 
-    add_edge(c, a, g);
+    tie(ai, ae) = adjacent_vertices(b, g);
+    ASSERT_EQ(a, *ai++);
+    ASSERT_EQ(b, *ai++);
+    ASSERT_EQ(ai, ae);
 
-    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));
+    tie(ai, ae) = adjacent_vertices(c, g);
+    ASSERT_EQ(ai, ae);
+
+    tie(ai, ae) = adjacent_vertices(d, g);
+    ASSERT_EQ(ai, ae);
+}
 
-    add_edge(d, a, g);
+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);
 
-    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(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(graph_util, edge_by_target_1) {
-    unit_graph g;
+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);
 
-    unit_vertex a = add_vertex(g);
-    unit_vertex b = add_vertex(g);
-    unit_vertex c = 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<SimpleG::vertex_descriptor> 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<decltype(get(&SimpleV::test_v, g)[a])>::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<SimpleG, SimpleG &> 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<const SimpleG, const SimpleG &> 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> { };
+    TestGraph g;
+
+    auto v = add_vertex(g);
+    auto e = add_edge(v, v, g).first;
 
-    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);
-
-    unit_edge ab = add_edge(a, 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_FALSE(edge_by_target(c, b, g).second);
-
-    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);
+    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));
 }
index 3ca1923fd7b7441cb6ff4b03bd506e52c5a28801..8fda92231f594e51e46c6b2f65add06293809c3b 100644 (file)
@@ -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) {
index acb3cc7b12ce481f16a4990ea42fc26c88eb559e..be9527fd36361f4a2f1440152e807cbfddd69bdd 100644 (file)
@@ -55,13 +55,13 @@ TEST(NFAGraph, RemoveRedundancy1) {
 
     unique_ptr<NGWrapper> 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<NGWrapper> 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<NGWrapper> 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));
 }
index 3f5a8382a5c2fa758f7ce6a55c6d4cf596ab5a0c..291c241a2165ff8853e59900169a9a4a8ec54d96 100644 (file)
@@ -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);
index 9fa6743e1eff3990bcd751805f7c9122434a5e6f..ca7c413ab0a4646b47c169e3cba33aee1fae3646 100644 (file)
@@ -144,7 +144,7 @@ void findPaths(const NGHolder &g, CorpusProperties &cProps,
 
     ue2::unordered_set<NFAVertex> 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<VertexPath>::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<CodePointSet> &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<CodePointSet> &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<CodePointSet>());
-        decodePath(graph.g, path, out->back());
+        decodePath(graph, path, out->back());
     }
 }
 
index 60ff0a17dca4d3980aa095843ad93863aa97cb55..2b33736534a9d38e7c01a210df13098d006a054d 100644 (file)
@@ -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"