diff options
author | Ivan Blinkov <ivan@blinkov.ru> | 2022-02-10 16:47:10 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:47:10 +0300 |
commit | 1aeb9a455974457866f78722ad98114bafc84e8a (patch) | |
tree | e4340eaf1668684d83a0a58c36947c5def5350ad /contrib/libs/hyperscan/src/util/ue2_graph.h | |
parent | bd5ef432f5cfb1e18851381329d94665a4c22470 (diff) | |
download | ydb-1aeb9a455974457866f78722ad98114bafc84e8a.tar.gz |
Restoring authorship annotation for Ivan Blinkov <ivan@blinkov.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/libs/hyperscan/src/util/ue2_graph.h')
-rw-r--r-- | contrib/libs/hyperscan/src/util/ue2_graph.h | 2462 |
1 files changed, 1231 insertions, 1231 deletions
diff --git a/contrib/libs/hyperscan/src/util/ue2_graph.h b/contrib/libs/hyperscan/src/util/ue2_graph.h index aa9718d73a..72a525374b 100644 --- a/contrib/libs/hyperscan/src/util/ue2_graph.h +++ b/contrib/libs/hyperscan/src/util/ue2_graph.h @@ -1,1032 +1,1032 @@ -/* +/* * Copyright (c) 2016-2018, 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 "util/noncopyable.h" -#include "util/operators.h" - -#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 <functional> /* hash */ -#include <tuple> /* tie */ -#include <type_traits> /* is_same, etc */ -#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 + * + * 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 "util/noncopyable.h" +#include "util/operators.h" + +#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 <functional> /* hash */ +#include <tuple> /* tie */ +#include <type_traits> /* is_same, etc */ +#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 : noncopyable { -}; - -struct default_edge_property { - size_t index; -}; - -struct default_vertex_property { - size_t index; -}; - -template<typename Graph> -class vertex_descriptor : totally_ordered<vertex_descriptor<Graph>> { - using vertex_node = typename Graph::vertex_node; -public: - vertex_descriptor() : p(nullptr), serial(0) {} - explicit vertex_descriptor(vertex_node *pp) : p(pp), serial(pp->serial) {} - + * + * (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 : noncopyable { +}; + +struct default_edge_property { + size_t index; +}; + +struct default_vertex_property { + size_t index; +}; + +template<typename Graph> +class vertex_descriptor : totally_ordered<vertex_descriptor<Graph>> { + using vertex_node = typename Graph::vertex_node; +public: + vertex_descriptor() : p(nullptr), serial(0) {} + explicit vertex_descriptor(vertex_node *pp) : p(pp), serial(pp->serial) {} + explicit 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; } - - size_t hash() const { - return std::hash<u64a>()(serial); - } - -private: - vertex_node *raw(void) { return p; } - vertex_node *p; - u64a serial; - friend Graph; -}; - -template<typename Graph> -class edge_descriptor : totally_ordered<edge_descriptor<Graph>> { - using edge_node = typename Graph::edge_node; -public: - edge_descriptor() : p(nullptr), serial(0) {} - explicit edge_descriptor(edge_node *pp) : p(pp), serial(pp->serial) {} - - /* Convenience ctor to allow us to directly get an edge_descriptor from - * edge() and add_edge(). As we have null_edges and we always allow - * parallel edges, the bool component of the return from these functions is - * not required. */ - edge_descriptor(const std::pair<edge_descriptor, bool> &tup) - : p(tup.first.p), serial(tup.first.serial) { - assert(tup.second == (bool)tup.first); - } - - 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; } - - size_t hash() const { - return std::hash<u64a>()(serial); - } - -private: - edge_node *raw(void) { return p; } - edge_node *p; - u64a serial; - friend Graph; -}; - -} // namespace graph_detail - -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 + 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; } + + size_t hash() const { + return std::hash<u64a>()(serial); + } + +private: + vertex_node *raw(void) { return p; } + vertex_node *p; + u64a serial; + friend Graph; +}; + +template<typename Graph> +class edge_descriptor : totally_ordered<edge_descriptor<Graph>> { + using edge_node = typename Graph::edge_node; +public: + edge_descriptor() : p(nullptr), serial(0) {} + explicit edge_descriptor(edge_node *pp) : p(pp), serial(pp->serial) {} + + /* Convenience ctor to allow us to directly get an edge_descriptor from + * edge() and add_edge(). As we have null_edges and we always allow + * parallel edges, the bool component of the return from these functions is + * not required. */ + edge_descriptor(const std::pair<edge_descriptor, bool> &tup) + : p(tup.first.p), serial(tup.first.serial) { + assert(tup.second == (bool)tup.first); + } + + 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; } + + size_t hash() const { + return std::hash<u64a>()(serial); + } + +private: + edge_node *raw(void) { return p; } + edge_node *p; + u64a serial; + friend Graph; +}; + +} // namespace graph_detail + +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 being 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 vertex_descriptor = graph_detail::vertex_descriptor<ue2_graph>; - using edge_descriptor = graph_detail::edge_descriptor<ue2_graph>; - friend vertex_descriptor; - friend edge_descriptor; - - 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; - -private: - /* 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_impl(*main); - while (aux == aux_end) { - ++main; - if (main == main_end) { - break; - } - std::tie(aux, aux_end) = out_edges_impl(*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_impl(*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; - }; - -public: - static - vertex_descriptor null_vertex() { return vertex_descriptor(); } - - 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); - } - - void remove_vertex_impl(vertex_descriptor v) { - vertex_node *vv = v.raw(); - assert(vv->in_edge_list.empty()); - assert(vv->out_edge_list.empty()); - vertices_list.erase_and_dispose(vertices_list.iterator_to(*vv), - delete_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()); - } - - 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 */ - - static - vertex_descriptor source_impl(edge_descriptor e) { - return vertex_descriptor(e.raw()->source); - } - - static - vertex_descriptor target_impl(edge_descriptor e) { - return vertex_descriptor(e.raw()->target); - } - - static - degree_size_type out_degree_impl(vertex_descriptor v) { - return v.raw()->out_edge_list.size(); - } - - static - std::pair<out_edge_iterator, out_edge_iterator> - 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 */ - - static - degree_size_type in_degree_impl(vertex_descriptor v) { - return v.raw()->in_edge_list.size(); - } - - static - std::pair<in_edge_iterator, in_edge_iterator> - 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. */ - static - degree_size_type degree_impl(vertex_descriptor v) { - return in_degree_impl(v) + out_degree_impl(v); - } - - /* AdjacencyList concept functions */ - - static - std::pair<adjacency_iterator, adjacency_iterator> - 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)}; - } - - /* AdjacencyMatrix concept functions - * (Note: complexity guarantee is not met) */ - - std::pair<edge_descriptor, bool> 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, *this)) { - if (target_impl(e) == 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(); } - - static - std::pair<inv_adjacency_iterator, inv_adjacency_iterator> - 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 */ - - std::pair<edge_descriptor, bool> - add_edge_impl(vertex_descriptor u, vertex_descriptor v) { - bool added = true; /* we always allow parallel edges */ - edge_node *e = new edge_node(new_serial()); - e->source = u.raw(); - e->target = v.raw(); - e->props.index = next_edge_index++; - - u.raw()->out_edge_list.push_back(*e); - v.raw()->in_edge_list.push_back(*e); - - graph_edge_count++; - return {edge_descriptor(e), added}; - } - - void remove_edge_impl(edge_descriptor e) { - graph_edge_count--; - - vertex_node *u = e.raw()->source; - vertex_node *v = e.raw()->target; - - 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 e.raw(); - } - - template<class Predicate> - void remove_out_edge_if_impl(vertex_descriptor v, Predicate pred) { - out_edge_iterator it, ite; - std::tie(it, ite) = out_edges_impl(v); - while (it != ite) { - auto jt = it; - ++it; - if (pred(*jt)) { - this->remove_edge_impl(*jt); - } - } - } - - template<class Predicate> - void remove_in_edge_if_impl(vertex_descriptor v, Predicate pred) { - in_edge_iterator it, ite; - std::tie(it, ite) = in_edges_impl(v); - while (it != ite) { - auto jt = it; - ++it; - if (pred(*jt)) { - remove_edge_impl(*jt); - } - } - } - - template<class Predicate> - void remove_edge_if_impl(Predicate pred) { - edge_iterator it, ite; - std::tie(it, ite) = edges_impl(); - while (it != ite) { - auto jt = it; - ++it; - if (pred(*jt)) { - remove_edge_impl(*jt); - } - } - } - -private: - /* GCC 4.8 has bugs with lambdas in templated friend functions, so: */ - struct source_match { - explicit source_match(const vertex_descriptor &uu) : u(uu) { } - bool operator()(edge_descriptor e) const { return source_impl(e) == u; } - const vertex_descriptor &u; - }; - - struct target_match { - explicit target_match(const vertex_descriptor &vv) : v(vv) { } - bool operator()(edge_descriptor e) const { return target_impl(e) == v; } - const vertex_descriptor &v; - }; -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. - */ - 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_impl(u, target_match(v)); - } - } - - /* VertexListGraph concept functions */ - vertices_size_type num_vertices_impl() const { - return vertices_list.size(); - } - - std::pair<vertex_iterator, vertex_iterator> vertices_impl() const { - return {vertex_iterator(vertices_list.begin()), - vertex_iterator(vertices_list.end())}; - } - - /* EdgeListGraph concept functions (aside from those in IncidenceGraph) */ - - edges_size_type num_edges_impl() const { - return graph_edge_count; - } - - std::pair<edge_iterator, edge_iterator> edges_impl() const { - vertex_iterator vi, ve; - std::tie(vi, ve) = vertices_impl(); - - return {edge_iterator(vi, ve), edge_iterator(ve, ve)}; - } - - /* bundled properties functions */ - - vertex_property_type &operator[](vertex_descriptor v) { - return v.raw()->props; - } - - const vertex_property_type &operator[](vertex_descriptor v) const { - return v.raw()->props; - } - - edge_property_type &operator[](edge_descriptor e) { - return e.raw()->props; - } - - const edge_property_type &operator[](edge_descriptor e) const { - return e.raw()->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 k.raw()->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 k.raw()->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 - */ - 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; - } - - /* 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 - */ - std::pair<edge_descriptor, bool> - 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; - } - - /* End MutablePropertyGraph */ - - /** Pack the edge index into a contiguous range [ 0, num_edges(g) ). */ - 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. - */ - void renumber_vertices_impl() { - DEBUG_PRINTF("renumbering above %zu\n", 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; - } - - (*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). */ - 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). */ - vertices_size_type edge_index_upper_bound_impl() const { - return 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()); - } -}; - + 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 vertex_descriptor = graph_detail::vertex_descriptor<ue2_graph>; + using edge_descriptor = graph_detail::edge_descriptor<ue2_graph>; + friend vertex_descriptor; + friend edge_descriptor; + + 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; + +private: + /* 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_impl(*main); + while (aux == aux_end) { + ++main; + if (main == main_end) { + break; + } + std::tie(aux, aux_end) = out_edges_impl(*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_impl(*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; + }; + +public: + static + vertex_descriptor null_vertex() { return vertex_descriptor(); } + + 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); + } + + void remove_vertex_impl(vertex_descriptor v) { + vertex_node *vv = v.raw(); + assert(vv->in_edge_list.empty()); + assert(vv->out_edge_list.empty()); + vertices_list.erase_and_dispose(vertices_list.iterator_to(*vv), + delete_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()); + } + + 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 */ + + static + vertex_descriptor source_impl(edge_descriptor e) { + return vertex_descriptor(e.raw()->source); + } + + static + vertex_descriptor target_impl(edge_descriptor e) { + return vertex_descriptor(e.raw()->target); + } + + static + degree_size_type out_degree_impl(vertex_descriptor v) { + return v.raw()->out_edge_list.size(); + } + + static + std::pair<out_edge_iterator, out_edge_iterator> + 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 */ + + static + degree_size_type in_degree_impl(vertex_descriptor v) { + return v.raw()->in_edge_list.size(); + } + + static + std::pair<in_edge_iterator, in_edge_iterator> + 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. */ + static + degree_size_type degree_impl(vertex_descriptor v) { + return in_degree_impl(v) + out_degree_impl(v); + } + + /* AdjacencyList concept functions */ + + static + std::pair<adjacency_iterator, adjacency_iterator> + 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)}; + } + + /* AdjacencyMatrix concept functions + * (Note: complexity guarantee is not met) */ + + std::pair<edge_descriptor, bool> 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, *this)) { + if (target_impl(e) == 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(); } + + static + std::pair<inv_adjacency_iterator, inv_adjacency_iterator> + 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 */ + + std::pair<edge_descriptor, bool> + add_edge_impl(vertex_descriptor u, vertex_descriptor v) { + bool added = true; /* we always allow parallel edges */ + edge_node *e = new edge_node(new_serial()); + e->source = u.raw(); + e->target = v.raw(); + e->props.index = next_edge_index++; + + u.raw()->out_edge_list.push_back(*e); + v.raw()->in_edge_list.push_back(*e); + + graph_edge_count++; + return {edge_descriptor(e), added}; + } + + void remove_edge_impl(edge_descriptor e) { + graph_edge_count--; + + vertex_node *u = e.raw()->source; + vertex_node *v = e.raw()->target; + + 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 e.raw(); + } + + template<class Predicate> + void remove_out_edge_if_impl(vertex_descriptor v, Predicate pred) { + out_edge_iterator it, ite; + std::tie(it, ite) = out_edges_impl(v); + while (it != ite) { + auto jt = it; + ++it; + if (pred(*jt)) { + this->remove_edge_impl(*jt); + } + } + } + + template<class Predicate> + void remove_in_edge_if_impl(vertex_descriptor v, Predicate pred) { + in_edge_iterator it, ite; + std::tie(it, ite) = in_edges_impl(v); + while (it != ite) { + auto jt = it; + ++it; + if (pred(*jt)) { + remove_edge_impl(*jt); + } + } + } + + template<class Predicate> + void remove_edge_if_impl(Predicate pred) { + edge_iterator it, ite; + std::tie(it, ite) = edges_impl(); + while (it != ite) { + auto jt = it; + ++it; + if (pred(*jt)) { + remove_edge_impl(*jt); + } + } + } + +private: + /* GCC 4.8 has bugs with lambdas in templated friend functions, so: */ + struct source_match { + explicit source_match(const vertex_descriptor &uu) : u(uu) { } + bool operator()(edge_descriptor e) const { return source_impl(e) == u; } + const vertex_descriptor &u; + }; + + struct target_match { + explicit target_match(const vertex_descriptor &vv) : v(vv) { } + bool operator()(edge_descriptor e) const { return target_impl(e) == v; } + const vertex_descriptor &v; + }; +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. + */ + 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_impl(u, target_match(v)); + } + } + + /* VertexListGraph concept functions */ + vertices_size_type num_vertices_impl() const { + return vertices_list.size(); + } + + std::pair<vertex_iterator, vertex_iterator> vertices_impl() const { + return {vertex_iterator(vertices_list.begin()), + vertex_iterator(vertices_list.end())}; + } + + /* EdgeListGraph concept functions (aside from those in IncidenceGraph) */ + + edges_size_type num_edges_impl() const { + return graph_edge_count; + } + + std::pair<edge_iterator, edge_iterator> edges_impl() const { + vertex_iterator vi, ve; + std::tie(vi, ve) = vertices_impl(); + + return {edge_iterator(vi, ve), edge_iterator(ve, ve)}; + } + + /* bundled properties functions */ + + vertex_property_type &operator[](vertex_descriptor v) { + return v.raw()->props; + } + + const vertex_property_type &operator[](vertex_descriptor v) const { + return v.raw()->props; + } + + edge_property_type &operator[](edge_descriptor e) { + return e.raw()->props; + } + + const edge_property_type &operator[](edge_descriptor e) const { + return e.raw()->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 k.raw()->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 k.raw()->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 + */ + 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; + } + + /* 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 + */ + std::pair<edge_descriptor, bool> + 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; + } + + /* End MutablePropertyGraph */ + + /** Pack the edge index into a contiguous range [ 0, num_edges(g) ). */ + 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. + */ + void renumber_vertices_impl() { + DEBUG_PRINTF("renumbering above %zu\n", 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; + } + + (*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). */ + 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). */ + vertices_size_type edge_index_upper_bound_impl() const { + return 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()); + } +}; + /** \brief Type trait to enable on whether the Graph is an ue2_graph. */ -template<typename Graph> +template<typename Graph> struct is_ue2_graph : public ::std::integral_constant< bool, std::is_base_of<graph_detail::graph_base, Graph>::value> {}; @@ -1034,231 +1034,231 @@ struct is_ue2_graph template<typename Graph> typename std::enable_if<is_ue2_graph<Graph>::value, typename Graph::vertex_descriptor>::type -add_vertex(Graph &g) { - return g.add_vertex_impl(); -} - -template<typename Graph> +add_vertex(Graph &g) { + return g.add_vertex_impl(); +} + +template<typename Graph> typename std::enable_if<is_ue2_graph<Graph>::value>::type -remove_vertex(typename Graph::vertex_descriptor v, Graph &g) { - g.remove_vertex_impl(v); -} - -template<typename Graph> +remove_vertex(typename Graph::vertex_descriptor v, Graph &g) { + g.remove_vertex_impl(v); +} + +template<typename Graph> typename std::enable_if<is_ue2_graph<Graph>::value>::type -clear_in_edges(typename Graph::vertex_descriptor v, Graph &g) { - g.clear_in_edges_impl(v); -} - -template<typename Graph> +clear_in_edges(typename Graph::vertex_descriptor v, Graph &g) { + g.clear_in_edges_impl(v); +} + +template<typename Graph> typename std::enable_if<is_ue2_graph<Graph>::value>::type -clear_out_edges(typename Graph::vertex_descriptor v, Graph &g) { - g.clear_out_edges_impl(v); -} - -template<typename Graph> +clear_out_edges(typename Graph::vertex_descriptor v, Graph &g) { + g.clear_out_edges_impl(v); +} + +template<typename Graph> typename std::enable_if<is_ue2_graph<Graph>::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 Graph> +clear_vertex(typename Graph::vertex_descriptor v, Graph &g) { + g.clear_in_edges_impl(v); + g.clear_out_edges_impl(v); +} + +template<typename Graph> typename std::enable_if<is_ue2_graph<Graph>::value, typename Graph::vertex_descriptor>::type -source(typename Graph::edge_descriptor e, const Graph &) { - return Graph::source_impl(e); -} - -template<typename Graph> +source(typename Graph::edge_descriptor e, const Graph &) { + return Graph::source_impl(e); +} + +template<typename Graph> typename std::enable_if<is_ue2_graph<Graph>::value, typename Graph::vertex_descriptor>::type -target(typename Graph::edge_descriptor e, const Graph &) { - return Graph::target_impl(e); -} - -template<typename Graph> +target(typename Graph::edge_descriptor e, const Graph &) { + return Graph::target_impl(e); +} + +template<typename Graph> typename std::enable_if<is_ue2_graph<Graph>::value, typename Graph::degree_size_type>::type -out_degree(typename Graph::vertex_descriptor v, const Graph &) { - return Graph::out_degree_impl(v); -} - -template<typename Graph> +out_degree(typename Graph::vertex_descriptor v, const Graph &) { + return Graph::out_degree_impl(v); +} + +template<typename Graph> typename std::enable_if<is_ue2_graph<Graph>::value, std::pair<typename Graph::out_edge_iterator, typename Graph::out_edge_iterator>>::type -out_edges(typename Graph::vertex_descriptor v, const Graph &) { - return Graph::out_edges_impl(v); -} - -template<typename Graph> +out_edges(typename Graph::vertex_descriptor v, const Graph &) { + return Graph::out_edges_impl(v); +} + +template<typename Graph> typename std::enable_if<is_ue2_graph<Graph>::value, typename Graph::degree_size_type>::type -in_degree(typename Graph::vertex_descriptor v, const Graph &) { - return Graph::in_degree_impl(v); -} - -template<typename Graph> +in_degree(typename Graph::vertex_descriptor v, const Graph &) { + return Graph::in_degree_impl(v); +} + +template<typename Graph> typename std::enable_if<is_ue2_graph<Graph>::value, std::pair<typename Graph::in_edge_iterator, typename Graph::in_edge_iterator>>::type -in_edges(typename Graph::vertex_descriptor v, const Graph &) { - return Graph::in_edges_impl(v); -} - -template<typename Graph> +in_edges(typename Graph::vertex_descriptor v, const Graph &) { + return Graph::in_edges_impl(v); +} + +template<typename Graph> typename std::enable_if<is_ue2_graph<Graph>::value, typename Graph::degree_size_type>::type -degree(typename Graph::vertex_descriptor v, const Graph &) { - return Graph::degree_impl(v); -} - -template<typename Graph> +degree(typename Graph::vertex_descriptor v, const Graph &) { + return Graph::degree_impl(v); +} + +template<typename Graph> typename std::enable_if<is_ue2_graph<Graph>::value, std::pair<typename Graph::adjacency_iterator, typename Graph::adjacency_iterator>>::type -adjacent_vertices(typename Graph::vertex_descriptor v, const Graph &) { - return Graph::adjacent_vertices_impl(v); -} - -template<typename Graph> +adjacent_vertices(typename Graph::vertex_descriptor v, const Graph &) { + return Graph::adjacent_vertices_impl(v); +} + +template<typename Graph> typename std::enable_if<is_ue2_graph<Graph>::value, std::pair<typename Graph::edge_descriptor, bool>>::type -edge(typename Graph::vertex_descriptor u, typename Graph::vertex_descriptor v, - const Graph &g) { - return g.edge_impl(u, v); -} - -template<typename Graph> +edge(typename Graph::vertex_descriptor u, typename Graph::vertex_descriptor v, + const Graph &g) { + return g.edge_impl(u, v); +} + +template<typename Graph> typename std::enable_if<is_ue2_graph<Graph>::value, std::pair<typename Graph::inv_adjacency_iterator, typename Graph::inv_adjacency_iterator>>::type -inv_adjacent_vertices(typename Graph::vertex_descriptor v, const Graph &) { - return Graph::inv_adjacent_vertices_impl(v); -} - -template<typename Graph> +inv_adjacent_vertices(typename Graph::vertex_descriptor v, const Graph &) { + return Graph::inv_adjacent_vertices_impl(v); +} + +template<typename Graph> typename std::enable_if<is_ue2_graph<Graph>::value, std::pair<typename Graph::edge_descriptor, bool>>::type -add_edge(typename Graph::vertex_descriptor u, - typename Graph::vertex_descriptor v, Graph &g) { - return g.add_edge_impl(u, v); -} - -template<typename Graph> +add_edge(typename Graph::vertex_descriptor u, + typename Graph::vertex_descriptor v, Graph &g) { + return g.add_edge_impl(u, v); +} + +template<typename Graph> typename std::enable_if<is_ue2_graph<Graph>::value>::type -remove_edge(typename Graph::edge_descriptor e, Graph &g) { - g.remove_edge_impl(e); -} - -template<typename Graph, typename Iter> -typename std::enable_if< +remove_edge(typename Graph::edge_descriptor e, Graph &g) { + g.remove_edge_impl(e); +} + +template<typename Graph, typename Iter> +typename std::enable_if< !std::is_convertible<Iter, typename Graph::edge_descriptor>::value && is_ue2_graph<Graph>::value>::type -remove_edge(Iter it, Graph &g) { - g.remove_edge_impl(*it); -} - -template<typename Graph, typename Predicate> +remove_edge(Iter it, Graph &g) { + g.remove_edge_impl(*it); +} + +template<typename Graph, typename Predicate> typename std::enable_if<is_ue2_graph<Graph>::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 Graph, typename Predicate> +remove_out_edge_if(typename Graph::vertex_descriptor v, Predicate pred, + Graph &g) { + g.remove_out_edge_if_impl(v, pred); +} + +template<typename Graph, typename Predicate> typename std::enable_if<is_ue2_graph<Graph>::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 Graph, typename Predicate> +remove_in_edge_if(typename Graph::vertex_descriptor v, Predicate pred, + Graph &g) { + g.remove_in_edge_if_impl(v, pred); +} + +template<typename Graph, typename Predicate> typename std::enable_if<is_ue2_graph<Graph>::value>::type -remove_edge_if(Predicate pred, Graph &g) { - g.remove_edge_if_impl(pred); -} - -template<typename Graph> +remove_edge_if(Predicate pred, Graph &g) { + g.remove_edge_if_impl(pred); +} + +template<typename Graph> typename std::enable_if<is_ue2_graph<Graph>::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 Graph> +remove_edge(const typename Graph::vertex_descriptor &u, + const typename Graph::vertex_descriptor &v, Graph &g) { + g.remove_edge_impl(u, v); +} + +template<typename Graph> typename std::enable_if<is_ue2_graph<Graph>::value, typename Graph::vertices_size_type>::type -num_vertices(const Graph &g) { - return g.num_vertices_impl(); -} - -template<typename Graph> +num_vertices(const Graph &g) { + return g.num_vertices_impl(); +} + +template<typename Graph> typename std::enable_if<is_ue2_graph<Graph>::value, std::pair<typename Graph::vertex_iterator, typename Graph::vertex_iterator>>::type -vertices(const Graph &g) { - return g.vertices_impl(); -} - -template<typename Graph> +vertices(const Graph &g) { + return g.vertices_impl(); +} + +template<typename Graph> typename std::enable_if<is_ue2_graph<Graph>::value, typename Graph::edges_size_type>::type -num_edges(const Graph &g) { - return g.num_edges_impl(); -} - -template<typename Graph> +num_edges(const Graph &g) { + return g.num_edges_impl(); +} + +template<typename Graph> typename std::enable_if<is_ue2_graph<Graph>::value, std::pair<typename Graph::edge_iterator, typename Graph::edge_iterator>>::type -edges(const Graph &g) { - return g.edges_impl(); -} - -template<typename Graph> +edges(const Graph &g) { + return g.edges_impl(); +} + +template<typename Graph> typename std::enable_if<is_ue2_graph<Graph>::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 Graph> +add_vertex(const typename Graph::vertex_property_type &vp, Graph &g) { + return g.add_vertex_impl(vp); +} + +template<typename Graph> typename std::enable_if<is_ue2_graph<Graph>::value, std::pair<typename Graph::edge_descriptor, bool>>::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 Graph> +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 Graph> typename std::enable_if<is_ue2_graph<Graph>::value>::type -renumber_edges(Graph &g) { - g.renumber_edges_impl(); -} - -template<typename Graph> +renumber_edges(Graph &g) { + g.renumber_edges_impl(); +} + +template<typename Graph> typename std::enable_if<is_ue2_graph<Graph>::value>::type -renumber_vertices(Graph &g) { - g.renumber_vertices_impl(); -} - -template<typename Graph> +renumber_vertices(Graph &g) { + g.renumber_vertices_impl(); +} + +template<typename Graph> typename std::enable_if<is_ue2_graph<Graph>::value, typename Graph::vertices_size_type>::type -vertex_index_upper_bound(const Graph &g) { - return g.vertex_index_upper_bound_impl(); -} - -template<typename Graph> +vertex_index_upper_bound(const Graph &g) { + return g.vertex_index_upper_bound_impl(); +} + +template<typename Graph> typename std::enable_if<is_ue2_graph<Graph>::value, typename Graph::edges_size_type>::type -edge_index_upper_bound(const Graph &g) { - return g.edge_index_upper_bound_impl(); -} - +edge_index_upper_bound(const Graph &g) { + return g.edge_index_upper_bound_impl(); +} + template<typename T> struct pointer_to_member_traits {}; template<typename Return, typename Class> @@ -1287,17 +1287,17 @@ public: std::is_same<class_type, edge_type>::value; }; -using boost::vertex_index; -using boost::edge_index; - -} // namespace ue2 - -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, +using boost::vertex_index; +using boost::edge_index; + +} // namespace ue2 + +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<ue2::is_ue2_graph<Graph>::value && ue2::is_ue2_vertex_or_edge_property< Graph, Prop>::value>::type> { @@ -1309,8 +1309,8 @@ public: using type = typename Graph::template prop_map<member_type &, class_type>; using const_type = typename Graph::template prop_map<const member_type &, class_type>; -}; - +}; + template<typename Graph> struct property_map<Graph, vertex_index_t, typename std::enable_if<ue2::is_ue2_graph<Graph>::value>::type> { @@ -1347,29 +1347,29 @@ struct property_map<Graph, edge_all_t, typename Graph::template prop_map_all<const e_prop_type &>; }; -} // namespace boost - -namespace std { - -/* Specialization of std::hash so that vertex_descriptor can be used in - * unordered containers. */ -template<typename Graph> -struct hash<ue2::graph_detail::vertex_descriptor<Graph>> { - using vertex_descriptor = ue2::graph_detail::vertex_descriptor<Graph>; - std::size_t operator()(const vertex_descriptor &v) const { - return v.hash(); - } -}; - -/* Specialization of std::hash so that edge_descriptor can be used in - * unordered containers. */ -template<typename Graph> -struct hash<ue2::graph_detail::edge_descriptor<Graph>> { - using edge_descriptor = ue2::graph_detail::edge_descriptor<Graph>; - std::size_t operator()(const edge_descriptor &e) const { - return e.hash(); - } -}; - -} // namespace std -#endif +} // namespace boost + +namespace std { + +/* Specialization of std::hash so that vertex_descriptor can be used in + * unordered containers. */ +template<typename Graph> +struct hash<ue2::graph_detail::vertex_descriptor<Graph>> { + using vertex_descriptor = ue2::graph_detail::vertex_descriptor<Graph>; + std::size_t operator()(const vertex_descriptor &v) const { + return v.hash(); + } +}; + +/* Specialization of std::hash so that edge_descriptor can be used in + * unordered containers. */ +template<typename Graph> +struct hash<ue2::graph_detail::edge_descriptor<Graph>> { + using edge_descriptor = ue2::graph_detail::edge_descriptor<Graph>; + std::size_t operator()(const edge_descriptor &e) const { + return e.hash(); + } +}; + +} // namespace std +#endif |