171 lines
6.1 KiB
C++
171 lines
6.1 KiB
C++
#ifndef OSRM_CONTRACTOR_CONTRACTED_EDGE_CONTAINER_HPP
|
|
#define OSRM_CONTRACTOR_CONTRACTED_EDGE_CONTAINER_HPP
|
|
|
|
#include "contractor/query_edge.hpp"
|
|
|
|
#include "util/integer_range.hpp"
|
|
#include "util/permutation.hpp"
|
|
|
|
#include <tbb/parallel_sort.h>
|
|
|
|
#include <algorithm>
|
|
#include <climits>
|
|
#include <cstdint>
|
|
#include <numeric>
|
|
#include <vector>
|
|
|
|
namespace osrm::contractor
|
|
{
|
|
|
|
struct ContractedEdgeContainer
|
|
{
|
|
private:
|
|
using MergedFlags = std::uint8_t;
|
|
static constexpr auto ALL_FLAGS = 0xFF;
|
|
|
|
static bool mergeCompare(const QueryEdge &lhs, const QueryEdge &rhs)
|
|
{
|
|
return std::tie(lhs.source,
|
|
lhs.target,
|
|
lhs.data.shortcut,
|
|
lhs.data.turn_id,
|
|
lhs.data.weight,
|
|
lhs.data.duration,
|
|
lhs.data.forward,
|
|
lhs.data.backward) < std::tie(rhs.source,
|
|
rhs.target,
|
|
rhs.data.shortcut,
|
|
rhs.data.turn_id,
|
|
rhs.data.weight,
|
|
rhs.data.duration,
|
|
rhs.data.forward,
|
|
rhs.data.backward);
|
|
}
|
|
|
|
static bool mergable(const QueryEdge &lhs, const QueryEdge &rhs)
|
|
{
|
|
// only true if both are equal
|
|
return !mergeCompare(lhs, rhs) && !mergeCompare(rhs, lhs);
|
|
}
|
|
|
|
public:
|
|
void Insert(std::vector<QueryEdge> new_edges)
|
|
{
|
|
BOOST_ASSERT(edges.size() == 0);
|
|
BOOST_ASSERT(flags.empty());
|
|
|
|
edges = std::move(new_edges);
|
|
flags.resize(edges.size(), ALL_FLAGS);
|
|
}
|
|
|
|
void Filter(const std::vector<bool> &filter, std::size_t index)
|
|
{
|
|
BOOST_ASSERT(index < sizeof(MergedFlags) * CHAR_BIT);
|
|
const MergedFlags flag = 1 << index;
|
|
|
|
for (auto edge_index : util::irange<std::size_t>(0, edges.size()))
|
|
{
|
|
auto allowed = filter[edges[edge_index].source] && filter[edges[edge_index].target];
|
|
if (allowed)
|
|
{
|
|
flags[edge_index] |= flag;
|
|
}
|
|
else
|
|
{
|
|
flags[edge_index] &= ~flag;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Merge(std::vector<QueryEdge> new_edges)
|
|
{
|
|
BOOST_ASSERT(index < sizeof(MergedFlags) * CHAR_BIT);
|
|
|
|
const MergedFlags flag = 1 << index++;
|
|
|
|
auto edge_iter = edges.cbegin();
|
|
auto edge_end = edges.cend();
|
|
auto flags_iter = flags.begin();
|
|
|
|
// Remove all edges that are contained in the old set of edges and set the appropriate flag.
|
|
auto new_end =
|
|
std::remove_if(new_edges.begin(),
|
|
new_edges.end(),
|
|
[&](const QueryEdge &edge)
|
|
{
|
|
// check if the new edge would be sorted before the currend old edge
|
|
// if so it is not contained yet in the set of old edges
|
|
if (edge_iter == edge_end || mergeCompare(edge, *edge_iter))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// find the first old edge that is equal or greater then the new edge
|
|
while (edge_iter != edge_end && mergeCompare(*edge_iter, edge))
|
|
{
|
|
BOOST_ASSERT(flags_iter != flags.end());
|
|
edge_iter++;
|
|
flags_iter++;
|
|
}
|
|
|
|
// all new edges will be sorted after the old edges
|
|
if (edge_iter == edge_end)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
BOOST_ASSERT(edge_iter != edge_end);
|
|
if (mergable(edge, *edge_iter))
|
|
{
|
|
*flags_iter = *flags_iter | flag;
|
|
return true;
|
|
}
|
|
BOOST_ASSERT(mergeCompare(edge, *edge_iter));
|
|
return false;
|
|
});
|
|
|
|
// append new edges
|
|
edges.insert(edges.end(), new_edges.begin(), new_end);
|
|
auto edges_size = edges.size();
|
|
auto new_edges_size = std::distance(new_edges.begin(), new_end);
|
|
BOOST_ASSERT(static_cast<int>(edges_size) >= new_edges_size);
|
|
flags.resize(edges_size);
|
|
std::fill(flags.begin() + edges_size - new_edges_size, flags.end(), flag);
|
|
|
|
// enforce sorting for next merge step
|
|
std::vector<unsigned> ordering(edges_size);
|
|
std::iota(ordering.begin(), ordering.end(), 0);
|
|
tbb::parallel_sort(ordering.begin(),
|
|
ordering.end(),
|
|
[&](const auto lhs_idx, const auto rhs_idx)
|
|
{ return mergeCompare(edges[lhs_idx], edges[rhs_idx]); });
|
|
auto permutation = util::orderingToPermutation(ordering);
|
|
|
|
util::inplacePermutation(edges.begin(), edges.end(), permutation);
|
|
util::inplacePermutation(flags.begin(), flags.end(), permutation);
|
|
BOOST_ASSERT(std::is_sorted(edges.begin(), edges.end(), mergeCompare));
|
|
}
|
|
|
|
auto MakeEdgeFilters() const
|
|
{
|
|
std::vector<std::vector<bool>> filters(index);
|
|
for (const auto flag_index : util::irange<std::size_t>(0, index))
|
|
{
|
|
MergedFlags mask = 1 << flag_index;
|
|
for (const auto flag : flags)
|
|
{
|
|
filters[flag_index].push_back(flag & mask);
|
|
}
|
|
}
|
|
|
|
return filters;
|
|
}
|
|
|
|
std::size_t index = 0;
|
|
std::vector<MergedFlags> flags;
|
|
std::vector<QueryEdge> edges;
|
|
};
|
|
} // namespace osrm::contractor
|
|
|
|
#endif
|