From 1614c73eeb18a1feb81138eca9bb704f77cd5dab Mon Sep 17 00:00:00 2001 From: Alex Coyte Date: Thu, 15 Sep 2016 15:44:35 +1000 Subject: [PATCH] Implement some ue2_graph functions using TMP rather than friends This helps work around issues with some compilers --- src/util/ue2_graph.h | 568 +++++++++++++++++++++++++++++-------------- 1 file changed, 390 insertions(+), 178 deletions(-) diff --git a/src/util/ue2_graph.h b/src/util/ue2_graph.h index 7751e332..9634b032 100644 --- a/src/util/ue2_graph.h +++ b/src/util/ue2_graph.h @@ -318,6 +318,7 @@ public: } private: + vertex_node *raw(void) { return p; } vertex_node *p; u64a serial; friend ue2_graph; @@ -357,18 +358,13 @@ public: } private: + edge_node *raw(void) { return p; } 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 @@ -489,13 +485,13 @@ public: if (main == main_end) { return; } - std::tie(aux, aux_end) = out_edges_i(*main); + std::tie(aux, aux_end) = out_edges_impl(*main); while (aux == aux_end) { ++main; if (main == main_end) { break; } - std::tie(aux, aux_end) = out_edges_i(*main); + std::tie(aux, aux_end) = out_edges_impl(*main); } } edge_iterator() { } @@ -508,7 +504,7 @@ public: if (main == main_end) { break; } - std::tie(aux, aux_end) = out_edges_i(*main); + std::tie(aux, aux_end) = out_edges_impl(*main); } } bool equal(const edge_iterator &other) const { @@ -524,104 +520,87 @@ public: aux_base_iter_type aux_end; }; -private: - static - std::pair - out_edges_i(vertex_descriptor v) { - return {out_edge_iterator(raw(v)->out_edge_list.begin()), - out_edge_iterator(raw(v)->out_edge_list.end())}; - } - public: static vertex_descriptor null_vertex() { return vertex_descriptor(); } - friend - vertex_descriptor add_vertex(Graph &g) { - vertex_node *v = new vertex_node(g.new_serial()); - v->props.index = g.next_vertex_index++; - g.vertices_list.push_back(*v); + vertex_descriptor add_vertex_impl() { + vertex_node *v = new vertex_node(new_serial()); + v->props.index = next_vertex_index++; + vertices_list.push_back(*v); return vertex_descriptor(v); } - friend - void remove_vertex(vertex_descriptor v, Graph &g) { - vertex_node *vv = Graph::raw(v); + void remove_vertex_impl(vertex_descriptor v) { + vertex_node *vv = v.raw(); 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()); + vertices_list.erase_and_dispose(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()); + void clear_in_edges_impl(vertex_descriptor v) { + graph_edge_count -= v.raw()->in_edge_list.size(); + v.raw()->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); + void clear_out_edges_impl(vertex_descriptor v) { + graph_edge_count -= v.raw()->out_edge_list.size(); + v.raw()->out_edge_list.clear_and_dispose(out_edge_disposer()); } /* IncidenceGraph concept functions */ - friend - vertex_descriptor source(edge_descriptor e, const Graph &) { - return vertex_descriptor(Graph::raw(e)->source); + static + vertex_descriptor source_impl(edge_descriptor e) { + return vertex_descriptor(e.raw()->source); } - friend - vertex_descriptor target(edge_descriptor e, const Graph &) { - return vertex_descriptor(Graph::raw(e)->target); + static + vertex_descriptor target_impl(edge_descriptor e) { + return vertex_descriptor(e.raw()->target); } - friend - degree_size_type out_degree(vertex_descriptor v, const Graph &) { - return Graph::raw(v)->out_edge_list.size(); + static + degree_size_type out_degree_impl(vertex_descriptor v) { + return v.raw()->out_edge_list.size(); } - friend + static std::pair - out_edges(vertex_descriptor v, const Graph &) { - return Graph::out_edges_i(v); + out_edges_impl(vertex_descriptor v) { + return {out_edge_iterator(v.raw()->out_edge_list.begin()), + out_edge_iterator(v.raw()->out_edge_list.end())}; } /* BidirectionalGraph concept functions */ - friend - degree_size_type in_degree(vertex_descriptor v, const Graph &) { - return Graph::raw(v)->in_edge_list.size(); + static + degree_size_type in_degree_impl(vertex_descriptor v) { + return v.raw()->in_edge_list.size(); } - friend + static std::pair - in_edges(vertex_descriptor v, const Graph &) { - return {in_edge_iterator(Graph::raw(v)->in_edge_list.begin()), - in_edge_iterator(Graph::raw(v)->in_edge_list.end())}; + in_edges_impl(vertex_descriptor v) { + return {in_edge_iterator(v.raw()->in_edge_list.begin()), + in_edge_iterator(v.raw()->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); + static + degree_size_type degree_impl(vertex_descriptor v) { + return in_degree_impl(v) + out_degree_impl(v); } /* AdjacencyList concept functions */ - friend + static std::pair - adjacent_vertices(vertex_descriptor v, const Graph &g) { - auto out_edge_its = out_edges(v, g); + adjacent_vertices_impl(vertex_descriptor v) { + auto out_edge_its = out_edges_impl(v); return {adjacency_iterator(out_edge_its.first), adjacency_iterator(out_edge_its.second)}; } @@ -629,18 +608,17 @@ public: /* AdjacencyMatrix concept functions * (Note: complexity guarantee is not met) */ - friend - std::pair edge(vertex_descriptor u, - vertex_descriptor v, const Graph &g) { - if (in_degree(v, g) < out_degree(u, g)) { - for (const edge_descriptor &e : in_edges_range(v, g)) { - if (source(e, g) == u) { + std::pair edge_impl(vertex_descriptor u, + vertex_descriptor v) const { + if (in_degree_impl(v) < out_degree_impl(u)) { + for (const edge_descriptor &e : in_edges_range(v, *this)) { + if (source_impl(e) == u) { return {e, true}; } } } else { - for (const edge_descriptor &e : out_edges_range(u, g)) { - if (target(e, g) == v) { + for (const edge_descriptor &e : out_edges_range(u, *this)) { + if (target_impl(e) == v) { return {e, true}; } } @@ -654,89 +632,78 @@ public: static edge_descriptor null_edge() { return edge_descriptor(); } - friend + static std::pair - inv_adjacent_vertices(vertex_descriptor v, const Graph &g) { - auto in_edge_its = in_edges(v, g); + inv_adjacent_vertices_impl(vertex_descriptor v) { + auto in_edge_its = in_edges_impl(v); return {inv_adjacency_iterator(in_edge_its.first), inv_adjacency_iterator(in_edge_its.second)}; } /* MutableGraph concept functions */ - friend std::pair - add_edge(vertex_descriptor u, vertex_descriptor v, Graph &g) { + add_edge_impl(vertex_descriptor u, vertex_descriptor v) { 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++; + edge_node *e = new edge_node(new_serial()); + e->source = u.raw(); + e->target = v.raw(); + e->props.index = next_edge_index++; - Graph::raw(u)->out_edge_list.push_back(*e); - Graph::raw(v)->in_edge_list.push_back(*e); + u.raw()->out_edge_list.push_back(*e); + v.raw()->in_edge_list.push_back(*e); - g.graph_edge_count++; + graph_edge_count++; return {edge_descriptor(e), added}; } - friend - void remove_edge(edge_descriptor e, Graph &g) { - g.graph_edge_count--; + void remove_edge_impl(edge_descriptor e) { + graph_edge_count--; - vertex_node *u = Graph::raw(source(e, g)); - vertex_node *v = Graph::raw(target(e, g)); + vertex_node *u = e.raw()->source; + vertex_node *v = e.raw()->target; - 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))); + v->in_edge_list.erase(v->in_edge_list.iterator_to(*e.raw())); + u->out_edge_list.erase(u->out_edge_list.iterator_to(*e.raw())); - delete Graph::raw(e); - } - - template - friend - void remove_edge(Iter it, Graph &g) { - remove_edge(*it, g); + delete e.raw(); } template - friend - void remove_out_edge_if(vertex_descriptor v, Predicate pred, Graph &g) { + void remove_out_edge_if_impl(vertex_descriptor v, Predicate pred) { out_edge_iterator it, ite; - std::tie(it, ite) = out_edges(v, g); + std::tie(it, ite) = out_edges_impl(v); while (it != ite) { auto jt = it; ++it; if (pred(*jt)) { - remove_edge(*jt, g); + this->remove_edge_impl(*jt); } } } template - friend - void remove_in_edge_if(vertex_descriptor v, Predicate pred, Graph &g) { + void remove_in_edge_if_impl(vertex_descriptor v, Predicate pred) { in_edge_iterator it, ite; - std::tie(it, ite) = in_edges(v, g); + std::tie(it, ite) = in_edges_impl(v); while (it != ite) { auto jt = it; ++it; if (pred(*jt)) { - remove_edge(*jt, g); + remove_edge_impl(*jt); } } } template - friend - void remove_edge_if(Predicate pred, Graph &g) { + void remove_edge_if_impl(Predicate pred) { edge_iterator it, ite; - std::tie(it, ite) = edges(g); + std::tie(it, ite) = edges_impl(); while (it != ite) { auto jt = it; ++it; if (pred(*jt)) { - remove_edge(*jt, g); + remove_edge_impl(*jt); } } } @@ -744,62 +711,50 @@ public: 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; } + explicit source_match(const vertex_descriptor &uu) : u(uu) { } + bool operator()(edge_descriptor e) const { return source_impl(e) == 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; } + explicit target_match(const vertex_descriptor &vv) : v(vv) { } + bool operator()(edge_descriptor e) const { return target_impl(e) == 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); + void remove_edge_impl(const vertex_descriptor &u, + const vertex_descriptor &v) { + if (in_degree_impl(v) < out_degree_impl(u)) { + remove_in_edge_if_impl(v, source_match(u)); } else { - remove_out_edge_if(u, target_match(v, g), g); + remove_out_edge_if_impl(u, target_match(v)); } } /* VertexListGraph concept functions */ - - friend - vertices_size_type num_vertices(const Graph &g) { - return g.vertices_list.size(); + vertices_size_type num_vertices_impl() const { + return vertices_list.size(); } - friend - std::pair vertices(const Graph &g) { - return {vertex_iterator(g.vertices_list.begin()), - vertex_iterator(g.vertices_list.end())}; + std::pair vertices_impl() const { + return {vertex_iterator(vertices_list.begin()), + vertex_iterator(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; + edges_size_type num_edges_impl() const { + return graph_edge_count; } - friend - std::pair edges(const Graph &g) { + std::pair edges_impl() const { vertex_iterator vi, ve; - std::tie(vi, ve) = vertices(g); + std::tie(vi, ve) = vertices_impl(); return {edge_iterator(vi, ve), edge_iterator(ve, ve)}; } @@ -807,19 +762,19 @@ public: /* bundled properties functions */ vertex_property_type &operator[](vertex_descriptor v) { - return raw(v)->props; + return v.raw()->props; } const vertex_property_type &operator[](vertex_descriptor v) const { - return raw(v)->props; + return v.raw()->props; } edge_property_type &operator[](edge_descriptor e) { - return raw(e)->props; + return e.raw()->props; } const edge_property_type &operator[](edge_descriptor e) const { - return raw(e)->props; + return e.raw()->props; } /* PropertyGraph concept functions & helpers */ @@ -835,7 +790,7 @@ public: prop_map(value_type P_of::*m_in) : member(m_in) { } reference operator[](key_type k) const { - return Graph::raw(k)->props.*member; + return k.raw()->props.*member; } reference operator()(key_type k) const { return (*this)[k]; } @@ -852,7 +807,7 @@ public: typedef typename boost::lvalue_property_map_tag category; reference operator[](key_type k) const { - return Graph::raw(k)->props; + return k.raw()->props; } reference operator()(key_type k) const { return (*this)[k]; } }; @@ -965,12 +920,11 @@ public: * 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; + vertex_descriptor add_vertex_impl(const VertexPropertyType &vp) { + vertex_descriptor v = add_vertex_impl(); + auto i = (*this)[v].index; + (*this)[v] = vp; + (*this)[v].index = i; return v; } @@ -979,14 +933,13 @@ public: * rather than using the index in ep. i.e., except for in rare coincidences: * g[add_edge(u, v, g, ep)].index != ep.index */ - friend std::pair - add_edge(vertex_descriptor u, vertex_descriptor v, - const EdgePropertyType &ep, Graph &g) { - auto e = add_edge(u, v, g); - auto i = g[e.first].index; - g[e.first] = ep; - g[e.first].index = i; + add_edge_impl(vertex_descriptor u, vertex_descriptor v, + const EdgePropertyType &ep) { + auto e = add_edge_impl(u, v); + auto i = (*this)[e.first].index; + (*this)[e.first] = ep; + (*this)[e.first].index = i; return e; } @@ -994,44 +947,44 @@ public: /* 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++; + void renumber_edges_impl() { + next_edge_index = 0; + edge_iterator it; + edge_iterator ite; + for (std::tie(it, ite) = edges_impl(); it != ite; ++it) { + (*this)[*it].index = 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) { + void renumber_vertices_impl() { 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) { + next_vertex_index = Graph::N_SPECIAL_VERTICES; + vertex_iterator it; + vertex_iterator ite; + for (std::tie(it, ite) = vertices_impl(); it != ite; ++it) { + if ((*this)[*it].index < Graph::N_SPECIAL_VERTICES) { continue; } - g[v].index = g.next_vertex_index++; + (*this)[*it].index = 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; + vertices_size_type vertex_index_upper_bound_impl() const { + return 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; + vertices_size_type edge_index_upper_bound_impl() const { + return next_edge_index; } using directed_category = boost::directed_tag; @@ -1068,6 +1021,265 @@ public: } }; +template +typename std::enable_if< + std::is_base_of::value, + typename Graph::vertex_descriptor>::type +add_vertex(Graph &g) { + return g.add_vertex_impl(); +} + +template +typename std::enable_if< + std::is_base_of::value>::type +remove_vertex(typename Graph::vertex_descriptor v, Graph &g) { + g.remove_vertex_impl(v); +} + +template +typename std::enable_if< + std::is_base_of::value>::type +clear_in_edges(typename Graph::vertex_descriptor v, Graph &g) { + g.clear_in_edges_impl(v); +} + +template +typename std::enable_if< + std::is_base_of::value>::type +clear_out_edges(typename Graph::vertex_descriptor v, Graph &g) { + g.clear_out_edges_impl(v); +} + +template +typename std::enable_if< + std::is_base_of::value>::type +clear_vertex(typename Graph::vertex_descriptor v, Graph &g) { + g.clear_in_edges_impl(v); + g.clear_out_edges_impl(v); +} + +template +typename std::enable_if< + std::is_base_of::value, + typename Graph::vertex_descriptor>::type +source(typename Graph::edge_descriptor e, const Graph &) { + return Graph::source_impl(e); +} + +template +typename std::enable_if< + std::is_base_of::value, + typename Graph::vertex_descriptor>::type +target(typename Graph::edge_descriptor e, const Graph &) { + return Graph::target_impl(e); +} + +template +typename std::enable_if< + std::is_base_of::value, + typename Graph::degree_size_type>::type +out_degree(typename Graph::vertex_descriptor v, const Graph &) { + return Graph::out_degree_impl(v); +} + +template +typename std::enable_if< + std::is_base_of::value, + std::pair>::type +out_edges(typename Graph::vertex_descriptor v, const Graph &) { + return Graph::out_edges_impl(v); +} + +template +typename std::enable_if< + std::is_base_of::value, + typename Graph::degree_size_type>::type +in_degree(typename Graph::vertex_descriptor v, const Graph &) { + return Graph::in_degree_impl(v); +} + +template +typename std::enable_if< + std::is_base_of::value, + std::pair>::type +in_edges(typename Graph::vertex_descriptor v, const Graph &) { + return Graph::in_edges_impl(v); +} + +template +typename std::enable_if< + std::is_base_of::value, + typename Graph::degree_size_type>::type +degree(typename Graph::vertex_descriptor v, const Graph &) { + return Graph::degree_impl(v); +} + +template +typename std::enable_if< + std::is_base_of::value, + std::pair>::type +adjacent_vertices(typename Graph::vertex_descriptor v, const Graph &) { + return Graph::adjacent_vertices_impl(v); +} + +template +typename std::enable_if< + std::is_base_of::value, + std::pair>::type +edge(typename Graph::vertex_descriptor u, typename Graph::vertex_descriptor v, + const Graph &g) { + return g.edge_impl(u, v); +} + +template +typename std::enable_if< + std::is_base_of::value, + std::pair>::type +inv_adjacent_vertices(typename Graph::vertex_descriptor v, const Graph &) { + return Graph::inv_adjacent_vertices_impl(v); +} + +template +typename std::enable_if< + std::is_base_of::value, + std::pair>::type +add_edge(typename Graph::vertex_descriptor u, + typename Graph::vertex_descriptor v, Graph &g) { + return g.add_edge_impl(u, v); +} + +template +typename std::enable_if< + std::is_base_of::value>::type +remove_edge(typename Graph::edge_descriptor e, Graph &g) { + g.remove_edge_impl(e); +} + +template +typename std::enable_if< + !std::is_convertible::value + && std::is_base_of::value>::type +remove_edge(Iter it, Graph &g) { + g.remove_edge_impl(*it); +} + +template +typename std::enable_if< + std::is_base_of::value>::type +remove_out_edge_if(typename Graph::vertex_descriptor v, Predicate pred, + Graph &g) { + g.remove_out_edge_if_impl(v, pred); +} + +template +typename std::enable_if< + std::is_base_of::value>::type +remove_in_edge_if(typename Graph::vertex_descriptor v, Predicate pred, + Graph &g) { + g.remove_in_edge_if_impl(v, pred); +} + +template +typename std::enable_if< + std::is_base_of::value>::type +remove_edge_if(Predicate pred, Graph &g) { + g.remove_edge_if_impl(pred); +} + +template +typename std::enable_if< + std::is_base_of::value>::type +remove_edge(const typename Graph::vertex_descriptor &u, + const typename Graph::vertex_descriptor &v, Graph &g) { + g.remove_edge_impl(u, v); +} + +template +typename std::enable_if< + std::is_base_of::value, + typename Graph::vertices_size_type>::type +num_vertices(const Graph &g) { + return g.num_vertices_impl(); +} + +template +typename std::enable_if< + std::is_base_of::value, + std::pair>::type +vertices(const Graph &g) { + return g.vertices_impl(); +} + +template +typename std::enable_if< + std::is_base_of::value, + typename Graph::edges_size_type>::type +num_edges(const Graph &g) { + return g.num_edges_impl(); +} + +template +typename std::enable_if< + std::is_base_of::value, + std::pair>::type +edges(const Graph &g) { + return g.edges_impl(); +} + +template +typename std::enable_if< + std::is_base_of::value, + typename Graph::vertex_descriptor>::type +add_vertex(const typename Graph::vertex_property_type &vp, Graph &g) { + return g.add_vertex_impl(vp); +} + +template +typename std::enable_if< + std::is_base_of::value, + std::pair>::type +add_edge(typename Graph::vertex_descriptor u, + typename Graph::vertex_descriptor v, + const typename Graph::edge_property_type &ep, Graph &g) { + return g.add_edge_impl(u, v, ep); +} + +template +typename std::enable_if< + std::is_base_of::value>::type +renumber_edges(Graph &g) { + g.renumber_edges_impl(); +} + +template +typename std::enable_if< + std::is_base_of::value>::type +renumber_vertices(Graph &g) { + g.renumber_vertices_impl(); +} + +template +typename std::enable_if< + std::is_base_of::value, + typename Graph::vertices_size_type>::type +vertex_index_upper_bound(const Graph &g) { + return g.vertex_index_upper_bound_impl(); +} + +template +typename std::enable_if< + std::is_base_of::value, + typename Graph::edges_size_type>::type +edge_index_upper_bound(const Graph &g) { + return g.edge_index_upper_bound_impl(); +} + using boost::vertex_index; using boost::edge_index;