osrm-backend/include/util/static_graph.hpp
2017-03-08 00:56:50 +00:00

270 lines
8.0 KiB
C++

#ifndef STATIC_GRAPH_HPP
#define STATIC_GRAPH_HPP
#include "util/graph_traits.hpp"
#include "util/integer_range.hpp"
#include "util/percent.hpp"
#include "util/shared_memory_vector_wrapper.hpp"
#include "util/typedefs.hpp"
#include <boost/assert.hpp>
#include <algorithm>
#include <limits>
#include <type_traits>
#include <utility>
#include <vector>
namespace osrm
{
namespace util
{
namespace static_graph_details
{
using NodeIterator = NodeID;
using EdgeIterator = NodeID;
struct NodeArrayEntry
{
// index of the first edge
EdgeIterator first_edge;
};
template <typename EdgeDataT> struct EdgeArrayEntry;
template <typename EdgeDataT> struct EdgeArrayEntry
{
NodeID target;
EdgeDataT data;
};
template <> struct EdgeArrayEntry<void>
{
NodeID target;
};
template <typename EdgeDataT> struct SortableEdgeWithData;
template <> struct SortableEdgeWithData<void>
{
NodeIterator source;
NodeIterator target;
SortableEdgeWithData(NodeIterator source, NodeIterator target) : source(source), target(target)
{
}
bool operator<(const SortableEdgeWithData &right) const
{
return std::tie(source, target) < std::tie(right.source, right.target);
}
bool operator==(const SortableEdgeWithData &right) const
{
return std::tie(source, target) == std::tie(right.source, right.target);
}
};
template <typename EdgeDataT> struct SortableEdgeWithData : SortableEdgeWithData<void>
{
using Base = SortableEdgeWithData<void>;
EdgeDataT data;
template <typename... Ts>
SortableEdgeWithData(NodeIterator source, NodeIterator target, Ts &&... data)
: Base{source, target}, data{std::forward<Ts>(data)...}
{
}
};
} // namespace static_graph_details
template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
{
public:
using NodeIterator = static_graph_details::NodeIterator;
using EdgeIterator = static_graph_details::EdgeIterator;
using EdgeRange = range<EdgeIterator>;
using NodeArrayEntry = static_graph_details::NodeArrayEntry;
using EdgeArrayEntry = static_graph_details::EdgeArrayEntry<EdgeDataT>;
EdgeRange GetAdjacentEdgeRange(const NodeID node) const
{
return irange(BeginEdges(node), EndEdges(node));
}
template <typename ContainerT> StaticGraph(const int nodes, const ContainerT &graph)
{
BOOST_ASSERT(std::is_sorted(const_cast<ContainerT &>(graph).begin(),
const_cast<ContainerT &>(graph).end()));
number_of_nodes = nodes;
number_of_edges = static_cast<EdgeIterator>(graph.size());
node_array.resize(number_of_nodes + 1);
EdgeIterator edge = 0;
EdgeIterator position = 0;
for (const auto node : irange(0u, number_of_nodes + 1))
{
EdgeIterator last_edge = edge;
while (edge < number_of_edges && graph[edge].source == node)
{
++edge;
}
node_array[node].first_edge = position; //=edge
position += edge - last_edge; // remove
}
edge_array.resize(position); //(edge)
edge = 0;
for (const auto node : irange(0u, number_of_nodes))
{
EdgeIterator e = node_array[node + 1].first_edge;
for (const auto i : irange(node_array[node].first_edge, e))
{
edge_array[i].target = graph[edge].target;
CopyDataIfAvailable(
edge_array[i], graph[edge], traits::HasDataMember<EdgeArrayEntry>{});
edge++;
}
}
}
StaticGraph(typename ShM<NodeArrayEntry, UseSharedMemory>::vector &nodes,
typename ShM<EdgeArrayEntry, UseSharedMemory>::vector &edges)
{
BOOST_ASSERT(!nodes.empty());
number_of_nodes = static_cast<decltype(number_of_nodes)>(nodes.size() - 1);
number_of_edges = static_cast<decltype(number_of_edges)>(nodes.back().first_edge);
BOOST_ASSERT(number_of_edges <= edges.size());
using std::swap;
swap(node_array, nodes);
swap(edge_array, edges);
}
unsigned GetNumberOfNodes() const { return number_of_nodes; }
unsigned GetNumberOfEdges() const { return number_of_edges; }
unsigned GetOutDegree(const NodeIterator n) const { return EndEdges(n) - BeginEdges(n); }
inline NodeIterator GetTarget(const EdgeIterator e) const
{
return NodeIterator(edge_array[e].target);
}
auto &GetEdgeData(const EdgeIterator e) { return edge_array[e].data; }
const auto &GetEdgeData(const EdgeIterator e) const { return edge_array[e].data; }
EdgeIterator BeginEdges(const NodeIterator n) const
{
return EdgeIterator(node_array.at(n).first_edge);
}
EdgeIterator EndEdges(const NodeIterator n) const
{
return EdgeIterator(node_array.at(n + 1).first_edge);
}
// searches for a specific edge
EdgeIterator FindEdge(const NodeIterator from, const NodeIterator to) const
{
for (const auto i : irange(BeginEdges(from), EndEdges(from)))
{
if (to == edge_array[i].target)
{
return i;
}
}
return SPECIAL_EDGEID;
}
/**
* Finds the edge with the smallest `.weight` going from `from` to `to`
* @param from the source node ID
* @param to the target node ID
* @param filter a functor that returns a `bool` that determines whether an edge should be
* tested or not.
* Takes `EdgeData` as a parameter.
* @return the ID of the smallest edge if any were found that satisfied *filter*, or
* `SPECIAL_EDGEID` if no
* matching edge is found.
*/
template <typename FilterFunction>
EdgeIterator
FindSmallestEdge(const NodeIterator from, const NodeIterator to, FilterFunction &&filter) const
{
static_assert(traits::HasDataMember<EdgeArrayEntry>::value,
"Filtering on .data not possible without .data member attribute");
EdgeIterator smallest_edge = SPECIAL_EDGEID;
EdgeWeight smallest_weight = INVALID_EDGE_WEIGHT;
for (auto edge : GetAdjacentEdgeRange(from))
{
const NodeID target = GetTarget(edge);
const auto &data = GetEdgeData(edge);
if (target == to && data.weight < smallest_weight &&
std::forward<FilterFunction>(filter)(data))
{
smallest_edge = edge;
smallest_weight = data.weight;
}
}
return smallest_edge;
}
EdgeIterator FindEdgeInEitherDirection(const NodeIterator from, const NodeIterator to) const
{
EdgeIterator tmp = FindEdge(from, to);
return (SPECIAL_NODEID != tmp ? tmp : FindEdge(to, from));
}
EdgeIterator
FindEdgeIndicateIfReverse(const NodeIterator from, const NodeIterator to, bool &result) const
{
EdgeIterator current_iterator = FindEdge(from, to);
if (SPECIAL_NODEID == current_iterator)
{
current_iterator = FindEdge(to, from);
if (SPECIAL_NODEID != current_iterator)
{
result = true;
}
}
return current_iterator;
}
const NodeArrayEntry &GetNode(const NodeID nid) const { return node_array[nid]; }
const EdgeArrayEntry &GetEdge(const EdgeID eid) const { return edge_array[eid]; }
private:
template <typename OtherEdge>
void CopyDataIfAvailable(EdgeArrayEntry &into, const OtherEdge &from, std::true_type)
{
into.data = from.data;
}
template <typename OtherEdge>
void CopyDataIfAvailable(EdgeArrayEntry &into, const OtherEdge &from, std::false_type)
{
// Graph has no .data member, never copy even if `from` has a .data member.
(void)into;
(void)from;
}
NodeIterator number_of_nodes;
EdgeIterator number_of_edges;
typename ShM<NodeArrayEntry, UseSharedMemory>::vector node_array;
typename ShM<EdgeArrayEntry, UseSharedMemory>::vector edge_array;
};
} // namespace util
} // namespace osrm
#endif // STATIC_GRAPH_HPP