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
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
/*
- * 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:
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.
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) {
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;
}
} 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;
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
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) */
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));
};
};
-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) {
#include <stack>
#include <cassert>
+#include <boost/graph/adjacency_list.hpp>
#include <boost/range/adaptor/map.hpp>
using namespace std;
addToHolder(*g, m.first, m.second);
}
- //dumpGraph("castle_holder.dot", g->g);
+ //dumpGraph("castle_holder.dot", *g);
// Sanity checks.
assert(allMatchStatesHaveReports(*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;
}
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;
}
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;
}
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 */
}
/* 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);
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);
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);
// 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;
}
// 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;
}
}
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));
}
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;
}
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);
}
// 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;
}
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);
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);
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;
}
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);
}
}
}
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);
}
}
addDotsBetween(g, root, rhs, startBegin, startEnd);
- g.renumberVertices();
- g.renumberEdges();
+ renumber_vertices(g);
+ renumber_edges(g);
}
// Entry point.
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);
}
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
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;
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) {
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);
}
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);
}
}
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;
}
id2vertex.resize(pos + 1);
}
id2vertex[pos] = v;
- graph->g[v].index = pos;
+ (*graph)[v].index = pos;
}
unique_ptr<NGWrapper> NFABuilderImpl::getGraph() {
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);
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 {
}
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
}
for (UNUSED auto v : shell) {
- DEBUG_PRINTF("shell: %u\n", g[v].index);
+ DEBUG_PRINTF("shell: %zu\n", g[v].index);
}
return shell;
}
for (UNUSED auto v : shell) {
- DEBUG_PRINTF("shell: %u\n", g[v].index);
+ DEBUG_PRINTF("shell: %zu\n", g[v].index);
}
return shell;
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);
}
}
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;
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
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();
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);
/*
- * 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:
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();
}
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
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();
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;
}
}
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);
}
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);
// 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");
#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 {
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;
}
}
- 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;
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) {
* 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) {
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
* 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);
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);
/*
- * 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:
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);
}
}
// 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) {
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);
}
}
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);
}
}
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);
}
}
stringstream ss;
ss << grey.dumpPath << "Holder_X_" << stageNumber
<< "-" << stageName << ".dot";
- dumpGraphImpl(ss.str().c_str(), h.g);
+ dumpGraphImpl(ss.str().c_str(), 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);
}
}
/*
- * 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:
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;
}
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);
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;
}
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);
}
}
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;
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 &&
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
return getVertices(work_states, info);
}
-typedef boost::reverse_graph<const NFAGraph, const NFAGraph &> RevNFAGraph;
-
namespace {
class eg_visitor : public boost::default_dfs_visitor {
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
/* 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 */
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);
#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
/*
- * 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:
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);
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);
}
}
add_edge(u, v, g);
}
- g.renumberVertices();
- g.renumberEdges();
+ renumber_vertices(g);
+ renumber_edges(g);
return true;
}
}
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;
// 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)) {
// 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) {
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) {
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;
}
add_edge(u, cyclic, g);
}
- g.renumberVertices();
- g.renumberEdges();
+ renumber_vertices(g);
+ renumber_edges(g);
clearReports(g);
g.min_length = 0;
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)) {
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;
}
}
}
}
}
- //dumpGraph("final.dot", g.g);
+ //dumpGraph("final.dot", g);
if (!hasExtParams(g)) {
return;
/*
- * 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:
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);
+++ /dev/null
-/*
- * 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
#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"
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);
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;
}
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);
}
}
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;) {
}
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);
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();
}
}
* 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.
*
* - (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.
*
*/
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.
}
if (renumber) {
- h.renumberEdges();
- h.renumberVertices();
+ renumber_edges(h);
+ renumber_vertices(h);
}
}
}
if (renumber) {
- h.renumberEdges();
+ renumber_edges(h);
}
}
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
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) {
// 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;
}
}
// 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;
}
}
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;
}
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);
}
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) {
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)) {
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());
}
}
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());
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:;
}
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) {
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)" : "");
#include <fstream>
#include <queue>
+#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/boykov_kolmogorov_max_flow.hpp>
using namespace std;
// 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());
}
}
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);
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));
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;
}
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) {
/*
- * 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:
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) {
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();
}
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;
}
}
}
// 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());
}
}
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;
}
#include <vector>
using namespace std;
+using boost::make_filtered_graph;
namespace ue2 {
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:;
}
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:;
}
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;
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. */
/* 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;
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());
/* 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;
}
* 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;
}
}
- 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)) {
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);
}
}
}
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)) {
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
* 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;
}
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;
}
/*
- * 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:
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
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),
// 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;
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);
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);
}
}
// 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) {
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));
/*
- * 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:
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)) {
} 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()),
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.
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));
}
}
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);
}
}
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);
}
}
// 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;
}
}
- 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",
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);
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);
}
}
// 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
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,
remove_edges(dead, g);
pruneUnreachable(g);
- g.renumberVertices();
- g.renumberEdges();
+ renumber_vertices(g);
+ renumber_edges(g);
}
} // namespace ue2
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;
}
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);
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);
}
}
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;
}
* */
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;
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;
}
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);
}
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);
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 {
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,
}
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;
}
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;
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) {
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;
}
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));
}
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;
}
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.
}
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) {
// 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.
}
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;
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
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 {
/* 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);
}
}
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;
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);
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;
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);
&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);
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);
}
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));
}
}
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:;
}
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
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);
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");
// 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);
/*
- * 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:
const ue2::unordered_map<NFAVertex, u32> ®ion_map) {
assert(isRegionEntry(g, v, region_map));
- DEBUG_PRINTF("check if r%u is optional (inspecting v%u)\n",
+ DEBUG_PRINTF("check if r%u is optional (inspecting v%zu)\n",
region_map.at(v), g[v].index);
// Region zero is never optional.
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;
}
/*
- * 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:
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;
NFAVertex v = it->second.entry;
const CharReach ®ion_cr = it->second.cr;
assert(isRegionEntry(h, v, region_map) && !is_special(v, h));
- DEBUG_PRINTF("checking %u\n", h[v].index);
+ DEBUG_PRINTF("checking %zu\n", h[v].index);
if (!region_cr.isSubsetOf(cr)) {
DEBUG_PRINTF("doesn't cover the reach of region %u\n", region);
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
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 ®ion_cr = it->second.cr;
assert(isRegionEntry(h, v, region_map) && !is_special(v, h));
- DEBUG_PRINTF("checking %u\n", h[v].index);
+ DEBUG_PRINTF("checking %zu\n", h[v].index);
if (!region_cr.isSubsetOf(cr)) {
DEBUG_PRINTF("doesn't cover the reach of region %u\n", region);
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)) {
#include <boost/icl/interval_set.hpp>
using namespace std;
+using boost::depth_first_search;
+using boost::depth_first_visit;
namespace ue2 {
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;
}
}
-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;
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
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;
}
}
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;
}
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) {
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;
}
// 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;
}
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;
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);
}
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);
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);
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;
}
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;
}
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);
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",
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",
// 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;
}
}
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);
}
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");
}
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);
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;
}
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;
}
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;
}
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.
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);
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);
}
}
if (next == v) { // Ignore self loop.
++ai;
if (ai == ae) {
- return NFAGraph::null_vertex();
+ return NGHolder::null_vertex();
}
next = *ai;
}
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;
}
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;
}
// 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;
}
}
straw.clear();
- return NFAGraph::null_vertex();
+ return NGHolder::null_vertex();
}
private:
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
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
// 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
const vector<BoundedRepeatData> &all_repeats) {
vector<NFAVertex> straw;
return walkStrawToCyclicFwd(g, rsi.vertices.back(), all_repeats, straw) !=
- NFAGraph::null_vertex();
+ NGHolder::null_vertex();
}
static
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());
// 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;
}
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);
}
}
- 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);
}
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;
}
}
// 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());
// Some of our analyses require correctly numbered vertices, so we
// renumber after changes.
- g.renumberVertices();
+ renumber_vertices(g);
}
bool modified_start_ds = false;
// 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);
}
// 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;
}
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;
vector<NFAEdge> tempEdges;
wireStartToTops(g, tops, tempEdges);
- renumberGraphVertices(g);
+ renumber_vertices(g);
vector<NFAVertex> temp = getTopoOrdering(g);
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++;
}
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);
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);
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));
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),
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));
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) {
g[u].reports.insert(0);
}
- g.renumberVertices();
- g.renumberEdges();
+ renumber_vertices(g);
+ renumber_edges(g);
assert(allMatchStatesHaveReports(g));
assert(isCorrectlyTopped(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.size());
if (v == g.startDs || !g[v].char_reach.all()) {
}
clear_vertex(v, g);
remove_vertex(v, g);
- g.renumberVertices();
+ renumber_vertices(g);
return;
}
/* 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);
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 */
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;
}
}
// TODO: handle cases with multiple out-edges.
- if (hasGreaterOutDegree(1, source(e, g), g)) {
+ if (out_degree(source(e, g), g) > 1) {
continue;
}
}
for (auto v : accepts) {
- if (!hasGreaterInDegree(0, v, g)) {
+ if (!in_degree(v, g)) {
remove_vertex(v, g);
}
}
dumpPreRoseGraph(ig, cc.grey);
+ renumber_vertices(ig);
calcVertexOffsets(ig);
return igp;
}
handleLongMixedSensitivityLiterals(ig);
dedupe(ig);
pruneUseless(ig);
+ renumber_vertices(ig);
calcVertexOffsets(ig);
}
}
// 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)) {
add_edge(v, a, RoseInEdgeProps(rhs, 0U), ig);
}
+ renumber_vertices(ig);
calcVertexOffsets(ig);
return rose.addRose(ig, prefilter, true /* final chance */);
}
// 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;
/*
- * 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:
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());
}
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]);
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();
}
}
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
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;
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);
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");
}
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);
}
}
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) {
}
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);
}
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);
}
/* 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;
}
}
assert(in_degree(midfix.accept, midfix));
- midfix.renumberVertices();
+ renumber_vertices(midfix);
}
static
/* 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;
}
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;
// 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);
#ifdef DEBUG
DEBUG_PRINTF("add reporters:");
for (UNUSED auto v : tmp) {
- printf(" %u", g[v].index);
+ printf(" %zu", g[v].index);
}
printf("\n");
#endif
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);
}
}
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());
}
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
[&](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]);
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
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
/* 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.");
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);
return true;
}
- g2.renumberVertices(); // for findMinWidth, findMaxWidth.
+ renumber_vertices(g2); // for findMinWidth, findMaxWidth.
aligned_unique_ptr<NFA> nfa = makeBareSomRevNfa(g2, cc);
if (!nfa) {
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;
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;
}
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))
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) {
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) {
const ue2::unordered_map<NFAVertex, u32> ®ions,
ue2_literal *lit_out, NGHolder *lhs, NGHolder *rhs,
const CompileContext &cc) {
- NFAVertex v = nullptr;
+ NFAVertex v = NGHolder::null_vertex();
findBestLiteral(g, regions, lit_out, &v, cc);
if (lit_out->empty()) {
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;
}
}
} 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;
}
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);
}
depths->clear(); /* renumbering invalidates depths */
- prefix->renumberVertices();
+ renumber_vertices(*prefix);
DEBUG_PRINTF("done\n");
return prefix;
// 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;
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);
/*
- * 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:
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) {
/*
- * 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:
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);
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);
}
}
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;
}
}
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) {
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 */
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");
}
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 */
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));
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));
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));
}
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);
}
}
som_type som, const vector<DepthMinMax> &som_depths,
const ue2::unordered_map<NFAVertex, u32> ®ion_map,
smgb_cache &cache) {
- DEBUG_PRINTF("build base squash mask for vertex %u)\n",
- g[v].index);
+ DEBUG_PRINTF("build base squash mask for vertex %zu)\n", g[v].index);
vector<NFAVertex> q;
}
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);
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);
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");
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);
}
}
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);
}
}
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));
vector<NFAVertex> unreach;
for (auto v : vertices_range(revg)) {
if (!contains(colours, v)) {
- unreach.push_back(v);
+ unreach.push_back(NFAVertex(v));
}
}
return unreach;
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
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);
}
}
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.
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]" : "");
add_edge(u, v, vic[e], dest);
}
- dest.renumberEdges();
- dest.renumberVertices();
+ renumber_edges(dest);
+ renumber_vertices(dest);
}
namespace {
#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;
/**
/*
- * 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 {
/**
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;
* 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
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))) {
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);
}
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);
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);
}
}
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);
}
}
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)) {
}
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)) {
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;
}
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;
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:
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;
}
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;
}
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)) {
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;
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;
}
}
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;
}
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);
}
}
- 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,
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];
}
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
/* 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;
}
// 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));
}
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
// 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));
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);
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);
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;
}
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)) {
return true;
}
-
#endif // NDEBUG
} // namespace ue2
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>>
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>>
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;
}
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;
}
*/
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. */
*/
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
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);
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,
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);
}
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);
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()) {
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;
}
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);
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");
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) {
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);
// 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(),
static
depth findMaxWidth(const NGHolder &h, const SpecialEdgeFilter &filter,
NFAVertex src) {
- if (isLeafNode(src, h.g)) {
+ if (isLeafNode(src, h)) {
return depth::unreachable();
}
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);
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;
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);
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;
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);
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;
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) {
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];
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));
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;
}
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);
}
}
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));
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);
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;
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);
}
}
|| (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();
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;
}
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;
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;
}
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;
}
|| 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");
bool finalChance) {
DEBUG_PRINTF("trying to rose\n");
assert(validateKinds(ig));
+ assert(hasCorrectlyNumberedVertices(ig));
if (::ue2::empty(ig)) {
assert(0);
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.
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);
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);
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;
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
/* 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;
}
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;
}
appendTailToHolder(h, e.first, e.second, tail);
}
- h.renumberEdges();
+ renumber_edges(h);
}
static
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);
}
}
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;
}
}
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];
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)) {
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)) {
}
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());
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;
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;
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);
// 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);
}
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));
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));
}
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);
}
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;
}
}
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;
}
}
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);
// 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(
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 */
/*
- * 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:
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);
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);
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);
// 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
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;
}
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);
}
}
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();
RoseGraph &g = tbi.g;
RoseVertex v = add_vertex(g);
- g[v].idx = tbi.vertexIndex++;
g[v].literals.insert(lit_id);
g[v].reports = reports;
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;
}
}
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;
}
}
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;
}
}
// 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;
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;
}
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);
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);
}
}
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());
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);
}
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) {
}
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;
}
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);
}
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)) {
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)) {
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.
}
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);
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;
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()) {
// 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) {
}
} else {
DEBUG_PRINTF("not sibling different mother %zu %zu\n",
- g[v].idx, g[w].idx);
+ g[v].index, g[w].index);
}
}
}
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);
}
}
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));
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);
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);
}
// 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;
const RoseVertex anchored_root;
RoseLiteralMap literals;
std::map<RoseVertex, RoseVertex> ghost;
- size_t vertexIndex;
ReportID getNewNfaReport() override {
return next_nfa_report++;
}
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;
}
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());
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;
}
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>());
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;
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));
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;
}
}
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;
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)) {
}
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);
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);
}
// if we've removed anything, we need to renumber vertices
if (countRemovals) {
- tbi.renumberVertices();
+ renumber_vertices(g);
DEBUG_PRINTF("removed %zu vertices.\n", countRemovals);
}
}
// 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()]++;
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 {
}
// 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;
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;
}
static
bool nfaHasNarrowStart(const NGHolder &g) {
- if (hasGreaterOutDegree(1, g.startDs, g)) {
+ if (out_degree(g.startDs, g) > 1) {
return false; // unanchored
}
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),
bool narrowStart;
bool hasMaxWidth;
- RoseVertexSet parents;
+ set<RoseVertex> parents;
};
}
map<RoseMergeKey, RoseBouquet> rosesByParent;
RoseGraph &g = tbi.g;
- RoseVertexSet parents(g);
+ set<RoseVertex> parents;
DEBUG_PRINTF("-----\n");
DEBUG_PRINTF("entry\n");
: 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);
}
}
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;
}
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);
}
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)) {
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]);
}
}
}
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];
: 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),
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;
}
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;
}
}
/* 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;
}
}
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
// 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);
// 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");
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;
}
}
// 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) {
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;
}
}
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(); }
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 */
};
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;
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) {
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);
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);
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);
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).
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);
}
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);
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);
}
}
}
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;
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;
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));
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 {
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()) {
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);
}
}
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.
}
}
for (auto &siblings : sibling_cache | map_values) {
- sort(siblings.begin(), siblings.end(), VertexIndexComp(build.g));
+ sort(siblings.begin(), siblings.end());
}
}
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;
}
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;
}
mergeRoses &= cc.grey.mergeRose & cc.grey.roseMergeRosesDuringAliasing;
- CandidateSet candidates(g);
+ CandidateSet candidates;
findCandidates(build, &candidates);
DEBUG_PRINTF("candidates %zu\n", candidates.size());
/** 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.
/*
- * 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:
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);
}
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);
}
// 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;
}
#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 {
/** \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;
/** \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.
/**
* \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;
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));
}
#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;
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 {
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;
/*
- * 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:
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 */
}
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;
}
}
- 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;
}
}
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);
/*
- * 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:
#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"
/*
- * 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:
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) {
#include <cstdio>
#include <ostream>
#include <string>
+#include <vector>
namespace ue2 {
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);
#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. */
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. */
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>
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
/*
- * 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:
#ifndef UTIL_GRAPH_RANGE_H
#define UTIL_GRAPH_RANGE_H
-#include <boost/graph/adjacency_list.hpp>
#include <boost/range/iterator_range.hpp>
namespace ue2 {
--- /dev/null
+/*
+ * 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
/*
- * 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;
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));
}
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();
}
}
// 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);
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();
}
}
// 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);
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));
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;
}
}
// 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));
}
}
// 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));
}
}
// 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));
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();
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
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
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();
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) {
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
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
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) {
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) {
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) {
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) {
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));
}
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);
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);
}
}
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;
// 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;
}
}
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:
}
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;
}
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()) {
assert(out);
for (const auto &path : allPathsTemp) {
out->push_back(vector<CodePointSet>());
- decodePath(graph.g, path, out->back());
+ decodePath(graph, path, out->back());
}
}
#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"