160 lines
5.5 KiB
C++
160 lines
5.5 KiB
C++
#ifndef OSRM_PARTITIONER_GRAPH_HPP_
|
|
#define OSRM_PARTITIONER_GRAPH_HPP_
|
|
|
|
#include <algorithm>
|
|
#include <cstddef>
|
|
#include <functional>
|
|
#include <iterator>
|
|
#include <vector>
|
|
|
|
#include "util/typedefs.hpp"
|
|
#include <boost/range/iterator_range.hpp>
|
|
|
|
namespace osrm::partitioner
|
|
{
|
|
|
|
// forward declaration to allow finding friends
|
|
template <typename NodeEntryT, typename EdgeEntryT> class RemappableGraph;
|
|
|
|
// wrapper for nodes to augment with a tag storing first edge id
|
|
template <typename Base> class NodeEntryWrapper : public Base
|
|
{
|
|
public:
|
|
template <typename... Args>
|
|
NodeEntryWrapper(std::size_t edges_begin_, std::size_t edges_end_, Args &&...args)
|
|
: Base(std::forward<Args>(args)...), edges_begin(edges_begin_), edges_end(edges_end_)
|
|
{
|
|
}
|
|
|
|
private:
|
|
// only to be modified by the graph itself
|
|
std::size_t edges_begin;
|
|
std::size_t edges_end;
|
|
|
|
// give the graph access to the node data wrapper
|
|
template <typename NodeEntryT, typename EdgeEntryT> friend class RemappableGraph;
|
|
};
|
|
|
|
using RemappableGraphNode = NodeEntryWrapper<struct zero_base_class>;
|
|
|
|
template <typename Base> class GraphConstructionWrapper : public Base
|
|
{
|
|
public:
|
|
template <typename... Args>
|
|
GraphConstructionWrapper(const NodeID source_, Args &&...args)
|
|
: Base(std::forward<Args>(args)...), source(source_)
|
|
{
|
|
}
|
|
|
|
NodeID source;
|
|
|
|
Base Reduce() const { return *this; }
|
|
};
|
|
|
|
template <typename RandomIt> void groupEdgesBySource(RandomIt first, RandomIt last)
|
|
{
|
|
std::sort(
|
|
first, last, [](const auto &lhs, const auto &rhs) { return lhs.source < rhs.source; });
|
|
}
|
|
|
|
template <typename NodeEntryT, typename EdgeEntryT> class RemappableGraph
|
|
{
|
|
public:
|
|
using NodeT = NodeEntryT;
|
|
using EdgeT = EdgeEntryT;
|
|
|
|
using NodeIterator = typename std::vector<NodeT>::iterator;
|
|
using ConstNodeIterator = typename std::vector<NodeT>::const_iterator;
|
|
using EdgeIterator = typename std::vector<EdgeT>::iterator;
|
|
using ConstEdgeIterator = typename std::vector<EdgeT>::const_iterator;
|
|
|
|
// Constructs an empty graph with a given number of nodes.
|
|
explicit RemappableGraph(std::vector<NodeT> nodes_, std::vector<EdgeT> edges_)
|
|
: nodes(std::move(nodes_)), edges(std::move(edges_))
|
|
{
|
|
}
|
|
|
|
unsigned NumberOfNodes() const { return nodes.size(); }
|
|
|
|
auto &Node(const NodeID nid) { return nodes[nid]; }
|
|
auto &Node(const NodeID nid) const { return nodes[nid]; }
|
|
|
|
auto &Edge(const EdgeID eid) { return edges[eid]; }
|
|
auto &Edge(const EdgeID eid) const { return edges[eid]; }
|
|
|
|
auto Edges(const NodeID nid)
|
|
{
|
|
return boost::make_iterator_range(edges.begin() + nodes[nid].edges_begin,
|
|
edges.begin() + nodes[nid].edges_end);
|
|
}
|
|
|
|
auto Edges(const NodeID nid) const
|
|
{
|
|
return boost::make_iterator_range(edges.begin() + nodes[nid].edges_begin,
|
|
edges.begin() + nodes[nid].edges_end);
|
|
}
|
|
|
|
auto Edges(const NodeT &node)
|
|
{
|
|
return boost::make_iterator_range(edges.begin() + node.edges_begin,
|
|
edges.begin() + node.edges_end);
|
|
}
|
|
|
|
auto Edges(const NodeT &node) const
|
|
{
|
|
return boost::make_iterator_range(edges.begin() + node.edges_begin,
|
|
edges.begin() + node.edges_end);
|
|
}
|
|
|
|
auto BeginEdges(const NodeID nid) const { return edges.begin() + nodes[nid].edges_begin; }
|
|
auto EndEdges(const NodeID nid) const { return edges.begin() + nodes[nid].edges_end; }
|
|
|
|
auto BeginEdges(const NodeT &node) const { return edges.begin() + node.edges_begin; }
|
|
auto EndEdges(const NodeT &node) const { return edges.begin() + node.edges_end; }
|
|
auto BeginEdges(const NodeT &node) { return edges.begin() + node.edges_begin; }
|
|
auto EndEdges(const NodeT &node) { return edges.begin() + node.edges_end; }
|
|
|
|
EdgeID BeginEdgeID(const NodeID nid) const { return nodes[nid].edges_begin; }
|
|
EdgeID EndEdgeID(const NodeID nid) const { return nodes[nid].edges_end; }
|
|
|
|
// iterate over all nodes
|
|
auto Nodes() { return boost::make_iterator_range(nodes.begin(), nodes.end()); }
|
|
auto Nodes() const { return boost::make_iterator_range(nodes.begin(), nodes.end()); }
|
|
|
|
NodeID GetID(const NodeT &node) const
|
|
{
|
|
BOOST_ASSERT(&node >= nodes.data() && &node <= &nodes.back());
|
|
return (&node - nodes.data());
|
|
}
|
|
EdgeID GetID(const EdgeT &edge) const
|
|
{
|
|
BOOST_ASSERT(&edge >= edges.data() && &edge <= &edges.back());
|
|
return (&edge - edges.data());
|
|
}
|
|
|
|
NodeIterator Begin() { return nodes.begin(); }
|
|
NodeIterator End() { return nodes.end(); }
|
|
ConstNodeIterator CBegin() const { return nodes.cbegin(); }
|
|
ConstNodeIterator CEnd() const { return nodes.cend(); }
|
|
|
|
// removes the edges from the graph that return true for the filter, returns new end
|
|
template <typename FilterT> auto RemoveEdges(NodeT &node, FilterT filter)
|
|
{
|
|
BOOST_ASSERT(&node >= nodes.data() && &node <= &nodes.back());
|
|
// required since we are not on std++17 yet, otherwise we are missing an argument_type
|
|
const auto negate_filter = [&](const EdgeT &edge) { return !filter(edge); };
|
|
const auto center = std::stable_partition(BeginEdges(node), EndEdges(node), negate_filter);
|
|
const auto remaining_edges = std::distance(BeginEdges(node), center);
|
|
node.edges_end = node.edges_begin + remaining_edges;
|
|
return center;
|
|
}
|
|
|
|
protected:
|
|
std::vector<NodeT> nodes;
|
|
std::vector<EdgeT> edges;
|
|
};
|
|
|
|
} // namespace osrm::partitioner
|
|
|
|
#endif // OSRM_PARTITIONER_GRAPH_HPP_
|