2017-05-02 07:12:28 -04:00
|
|
|
#ifndef OSRM_UTIL_QUERY_HEAP_HPP
|
|
|
|
#define OSRM_UTIL_QUERY_HEAP_HPP
|
2011-01-09 16:42:27 -05:00
|
|
|
|
2013-10-30 13:52:23 -04:00
|
|
|
#include <boost/assert.hpp>
|
2017-05-02 03:10:05 -04:00
|
|
|
#include <boost/heap/d_ary_heap.hpp>
|
2013-06-26 19:48:22 -04:00
|
|
|
|
2024-08-22 16:16:23 -04:00
|
|
|
#include "d_ary_heap.hpp"
|
2011-01-09 16:42:27 -05:00
|
|
|
#include <algorithm>
|
2023-05-31 01:53:04 -04:00
|
|
|
#include <cstdint>
|
2024-08-22 16:16:23 -04:00
|
|
|
#include <cstdlib>
|
2013-06-26 19:48:22 -04:00
|
|
|
#include <limits>
|
2011-01-09 16:42:27 -05:00
|
|
|
#include <map>
|
2024-05-22 08:58:07 -04:00
|
|
|
#include <optional>
|
2014-05-05 10:21:41 -04:00
|
|
|
#include <unordered_map>
|
2013-06-26 19:48:22 -04:00
|
|
|
#include <vector>
|
2011-03-16 16:23:07 -04:00
|
|
|
|
2022-12-11 04:10:26 -05:00
|
|
|
namespace osrm::util
|
2016-01-05 10:51:13 -05:00
|
|
|
{
|
|
|
|
|
2014-05-05 10:21:41 -04:00
|
|
|
template <typename NodeID, typename Key> class ArrayStorage
|
|
|
|
{
|
|
|
|
public:
|
2018-04-09 06:45:53 -04:00
|
|
|
explicit ArrayStorage(std::size_t size) : positions(size, 0) {}
|
2011-01-09 16:42:27 -05:00
|
|
|
|
2014-05-05 10:21:41 -04:00
|
|
|
Key &operator[](NodeID node) { return positions[node]; }
|
2011-01-09 16:42:27 -05:00
|
|
|
|
2015-02-10 05:35:58 -05:00
|
|
|
Key peek_index(const NodeID node) const { return positions[node]; }
|
2015-01-15 05:15:48 -05:00
|
|
|
|
2011-01-09 16:42:27 -05:00
|
|
|
void Clear() {}
|
|
|
|
|
2014-05-05 10:21:41 -04:00
|
|
|
private:
|
2015-01-15 06:59:08 -05:00
|
|
|
std::vector<Key> positions;
|
2011-01-09 16:42:27 -05:00
|
|
|
};
|
|
|
|
|
2014-05-05 10:21:41 -04:00
|
|
|
template <typename NodeID, typename Key> class UnorderedMapStorage
|
|
|
|
{
|
|
|
|
public:
|
2018-04-09 06:45:53 -04:00
|
|
|
explicit UnorderedMapStorage(std::size_t) { nodes.rehash(1000); }
|
2011-01-09 16:42:27 -05:00
|
|
|
|
2014-05-05 10:21:41 -04:00
|
|
|
Key &operator[](const NodeID node) { return nodes[node]; }
|
2011-01-09 16:42:27 -05:00
|
|
|
|
2015-01-15 05:15:48 -05:00
|
|
|
Key peek_index(const NodeID node) const
|
|
|
|
{
|
2015-01-14 11:26:59 -05:00
|
|
|
const auto iter = nodes.find(node);
|
|
|
|
if (std::end(nodes) != iter)
|
|
|
|
{
|
|
|
|
return iter->second;
|
|
|
|
}
|
2015-01-15 06:59:08 -05:00
|
|
|
return std::numeric_limits<Key>::max();
|
2015-01-14 11:26:59 -05:00
|
|
|
}
|
|
|
|
|
2014-05-05 10:21:41 -04:00
|
|
|
Key const &operator[](const NodeID node) const
|
|
|
|
{
|
|
|
|
auto iter = nodes.find(node);
|
2014-02-26 09:55:04 -05:00
|
|
|
return iter->second;
|
|
|
|
}
|
|
|
|
|
2014-05-05 10:21:41 -04:00
|
|
|
void Clear() { nodes.clear(); }
|
2011-01-09 16:42:27 -05:00
|
|
|
|
2014-05-05 10:21:41 -04:00
|
|
|
private:
|
|
|
|
std::unordered_map<NodeID, Key> nodes;
|
2011-03-24 09:32:15 -04:00
|
|
|
};
|
|
|
|
|
2018-04-08 12:37:08 -04:00
|
|
|
template <typename NodeID,
|
|
|
|
typename Key,
|
|
|
|
template <typename N, typename K> class BaseIndexStorage = UnorderedMapStorage,
|
|
|
|
template <typename N, typename K> class OverlayIndexStorage = ArrayStorage>
|
|
|
|
class TwoLevelStorage
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
explicit TwoLevelStorage(std::size_t number_of_nodes, std::size_t number_of_overlay_nodes)
|
2018-04-09 06:45:53 -04:00
|
|
|
: number_of_overlay_nodes(number_of_overlay_nodes), base(number_of_nodes),
|
|
|
|
overlay(number_of_overlay_nodes)
|
2018-04-08 12:37:08 -04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Key &operator[](const NodeID node)
|
|
|
|
{
|
|
|
|
if (node < number_of_overlay_nodes)
|
|
|
|
{
|
|
|
|
return overlay[node];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return base[node];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Key peek_index(const NodeID node) const
|
|
|
|
{
|
|
|
|
if (node < number_of_overlay_nodes)
|
|
|
|
{
|
|
|
|
return overlay.peek_index(node);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return base.peek_index(node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Key const &operator[](const NodeID node) const
|
|
|
|
{
|
|
|
|
if (node < number_of_overlay_nodes)
|
|
|
|
{
|
|
|
|
return overlay[node];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return base[node];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Clear()
|
|
|
|
{
|
|
|
|
base.Clear();
|
|
|
|
overlay.Clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
const std::size_t number_of_overlay_nodes;
|
|
|
|
BaseIndexStorage<NodeID, Key> base;
|
|
|
|
OverlayIndexStorage<NodeID, Key> overlay;
|
|
|
|
};
|
|
|
|
|
2014-05-05 10:21:41 -04:00
|
|
|
template <typename NodeID,
|
|
|
|
typename Key,
|
|
|
|
typename Weight,
|
|
|
|
typename Data,
|
|
|
|
typename IndexStorage = ArrayStorage<NodeID, NodeID>>
|
2017-05-02 07:12:28 -04:00
|
|
|
class QueryHeap
|
2014-05-05 10:21:41 -04:00
|
|
|
{
|
2020-11-23 16:33:08 -05:00
|
|
|
private:
|
2024-05-31 01:06:58 -04:00
|
|
|
struct HeapData
|
|
|
|
{
|
|
|
|
Weight weight;
|
|
|
|
Key index;
|
|
|
|
|
2024-08-22 16:16:23 -04:00
|
|
|
bool operator<(const HeapData &other) const
|
2024-05-31 01:06:58 -04:00
|
|
|
{
|
|
|
|
if (weight == other.weight)
|
|
|
|
{
|
2024-08-22 16:16:23 -04:00
|
|
|
return index < other.index;
|
2024-05-31 01:06:58 -04:00
|
|
|
}
|
2024-08-22 16:16:23 -04:00
|
|
|
return weight < other.weight;
|
2024-05-31 01:06:58 -04:00
|
|
|
}
|
|
|
|
};
|
2024-08-22 16:16:23 -04:00
|
|
|
using HeapContainer = DAryHeap<HeapData, 4>;
|
|
|
|
using HeapHandle = typename HeapContainer::HeapHandle;
|
2020-11-23 16:33:08 -05:00
|
|
|
|
2014-05-05 10:21:41 -04:00
|
|
|
public:
|
2014-08-19 07:01:38 -04:00
|
|
|
using WeightType = Weight;
|
|
|
|
using DataType = Data;
|
2011-01-09 16:42:27 -05:00
|
|
|
|
2020-11-23 16:33:08 -05:00
|
|
|
struct HeapNode
|
|
|
|
{
|
|
|
|
HeapHandle handle;
|
|
|
|
NodeID node;
|
|
|
|
Weight weight;
|
|
|
|
Data data;
|
|
|
|
};
|
|
|
|
|
2018-04-09 06:45:53 -04:00
|
|
|
template <typename... StorageArgs> explicit QueryHeap(StorageArgs... args) : node_index(args...)
|
2018-04-08 12:37:08 -04:00
|
|
|
{
|
|
|
|
Clear();
|
|
|
|
}
|
|
|
|
|
2014-05-05 10:21:41 -04:00
|
|
|
void Clear()
|
|
|
|
{
|
2017-05-02 03:10:05 -04:00
|
|
|
heap.clear();
|
2014-05-05 10:21:41 -04:00
|
|
|
inserted_nodes.clear();
|
|
|
|
node_index.Clear();
|
2011-01-09 16:42:27 -05:00
|
|
|
}
|
|
|
|
|
2017-05-02 03:10:05 -04:00
|
|
|
std::size_t Size() const { return heap.size(); }
|
2011-01-09 16:42:27 -05:00
|
|
|
|
2014-05-05 10:21:41 -04:00
|
|
|
bool Empty() const { return 0 == Size(); }
|
2013-09-21 15:51:07 -04:00
|
|
|
|
2014-05-05 10:21:41 -04:00
|
|
|
void Insert(NodeID node, Weight weight, const Data &data)
|
|
|
|
{
|
2024-08-22 16:16:23 -04:00
|
|
|
checkInvariants();
|
|
|
|
|
2017-08-20 19:24:05 -04:00
|
|
|
BOOST_ASSERT(node < std::numeric_limits<NodeID>::max());
|
2017-05-02 03:10:05 -04:00
|
|
|
const auto index = static_cast<Key>(inserted_nodes.size());
|
2024-08-22 16:16:23 -04:00
|
|
|
inserted_nodes.emplace_back(HeapNode{heap.size(), node, weight, data});
|
|
|
|
|
|
|
|
heap.emplace(HeapData{weight, index},
|
|
|
|
[this](const auto &heapData, auto new_handle)
|
|
|
|
{ inserted_nodes[heapData.index].handle = new_handle; });
|
2017-05-02 03:10:05 -04:00
|
|
|
node_index[node] = index;
|
2024-08-22 16:16:23 -04:00
|
|
|
|
|
|
|
checkInvariants();
|
|
|
|
}
|
|
|
|
|
|
|
|
void checkInvariants()
|
|
|
|
{
|
|
|
|
#ifndef NDEBUG
|
|
|
|
for (size_t handle = 0; handle < heap.size(); ++handle)
|
|
|
|
{
|
|
|
|
auto &in_heap = heap[handle];
|
|
|
|
auto &inserted = inserted_nodes[in_heap.index];
|
|
|
|
BOOST_ASSERT(in_heap.weight == inserted.weight);
|
|
|
|
BOOST_ASSERT(inserted.handle == handle);
|
|
|
|
}
|
|
|
|
#endif // !NDEBUG
|
2011-01-09 16:42:27 -05:00
|
|
|
}
|
|
|
|
|
2014-05-05 10:21:41 -04:00
|
|
|
Data &GetData(NodeID node)
|
|
|
|
{
|
2017-05-02 03:10:05 -04:00
|
|
|
const auto index = node_index.peek_index(node);
|
2018-04-07 22:20:59 -04:00
|
|
|
BOOST_ASSERT((int)index >= 0 && (int)index < (int)inserted_nodes.size());
|
2014-05-05 10:21:41 -04:00
|
|
|
return inserted_nodes[index].data;
|
2011-01-09 16:42:27 -05:00
|
|
|
}
|
|
|
|
|
2020-11-25 06:42:01 -05:00
|
|
|
HeapNode &getHeapNode(NodeID node)
|
2020-11-23 16:33:08 -05:00
|
|
|
{
|
|
|
|
const auto index = node_index.peek_index(node);
|
|
|
|
BOOST_ASSERT((int)index >= 0 && (int)index < (int)inserted_nodes.size());
|
|
|
|
return inserted_nodes[index];
|
|
|
|
}
|
|
|
|
|
2014-05-05 10:21:41 -04:00
|
|
|
Data const &GetData(NodeID node) const
|
|
|
|
{
|
2017-05-02 03:10:05 -04:00
|
|
|
const auto index = node_index.peek_index(node);
|
2018-04-07 22:20:59 -04:00
|
|
|
BOOST_ASSERT((int)index >= 0 && (int)index < (int)inserted_nodes.size());
|
2014-05-05 10:21:41 -04:00
|
|
|
return inserted_nodes[index].data;
|
2014-02-26 09:55:04 -05:00
|
|
|
}
|
|
|
|
|
2017-03-01 15:17:34 -05:00
|
|
|
const Weight &GetKey(NodeID node) const
|
|
|
|
{
|
2017-05-02 03:10:05 -04:00
|
|
|
const auto index = node_index.peek_index(node);
|
2017-03-01 15:17:34 -05:00
|
|
|
return inserted_nodes[index].weight;
|
|
|
|
}
|
|
|
|
|
2015-01-14 11:26:59 -05:00
|
|
|
bool WasRemoved(const NodeID node) const
|
2014-05-05 10:21:41 -04:00
|
|
|
{
|
|
|
|
BOOST_ASSERT(WasInserted(node));
|
2015-01-14 11:26:59 -05:00
|
|
|
const Key index = node_index.peek_index(node);
|
2024-08-22 16:16:23 -04:00
|
|
|
return inserted_nodes[index].handle == HeapContainer::INVALID_HANDLE;
|
2011-01-09 16:42:27 -05:00
|
|
|
}
|
|
|
|
|
2015-01-15 06:59:08 -05:00
|
|
|
bool WasInserted(const NodeID node) const
|
2014-05-05 10:21:41 -04:00
|
|
|
{
|
2015-01-15 06:59:08 -05:00
|
|
|
const auto index = node_index.peek_index(node);
|
2015-01-15 07:11:25 -05:00
|
|
|
if (index >= static_cast<decltype(index)>(inserted_nodes.size()))
|
2014-05-05 10:21:41 -04:00
|
|
|
{
|
2011-01-09 16:42:27 -05:00
|
|
|
return false;
|
2014-05-05 10:21:41 -04:00
|
|
|
}
|
|
|
|
return inserted_nodes[index].node == node;
|
2011-01-09 16:42:27 -05:00
|
|
|
}
|
|
|
|
|
2024-05-22 08:58:07 -04:00
|
|
|
HeapNode *GetHeapNodeIfWasInserted(const NodeID node)
|
2020-11-23 16:33:08 -05:00
|
|
|
{
|
|
|
|
const auto index = node_index.peek_index(node);
|
2020-11-25 06:42:01 -05:00
|
|
|
if (index >= static_cast<decltype(index)>(inserted_nodes.size()) ||
|
|
|
|
inserted_nodes[index].node != node)
|
2020-11-23 16:33:08 -05:00
|
|
|
{
|
2024-05-22 08:58:07 -04:00
|
|
|
return nullptr;
|
2020-11-23 16:33:08 -05:00
|
|
|
}
|
2024-05-22 08:58:07 -04:00
|
|
|
return &inserted_nodes[index];
|
2020-11-23 16:33:08 -05:00
|
|
|
}
|
|
|
|
|
2024-05-22 08:58:07 -04:00
|
|
|
const HeapNode *GetHeapNodeIfWasInserted(const NodeID node) const
|
2020-11-23 16:33:08 -05:00
|
|
|
{
|
|
|
|
const auto index = node_index.peek_index(node);
|
2020-11-25 06:42:01 -05:00
|
|
|
if (index >= static_cast<decltype(index)>(inserted_nodes.size()) ||
|
|
|
|
inserted_nodes[index].node != node)
|
2020-11-23 16:33:08 -05:00
|
|
|
{
|
2024-05-22 08:58:07 -04:00
|
|
|
return nullptr;
|
2020-11-23 16:33:08 -05:00
|
|
|
}
|
2024-05-22 08:58:07 -04:00
|
|
|
return &inserted_nodes[index];
|
2020-11-23 16:33:08 -05:00
|
|
|
}
|
|
|
|
|
2014-05-05 10:21:41 -04:00
|
|
|
NodeID Min() const
|
|
|
|
{
|
2017-05-02 03:10:05 -04:00
|
|
|
BOOST_ASSERT(!heap.empty());
|
2024-05-31 01:06:58 -04:00
|
|
|
return inserted_nodes[heap.top().index].node;
|
2011-01-09 16:42:27 -05:00
|
|
|
}
|
|
|
|
|
2016-01-05 06:04:04 -05:00
|
|
|
Weight MinKey() const
|
|
|
|
{
|
2017-05-02 03:10:05 -04:00
|
|
|
BOOST_ASSERT(!heap.empty());
|
2024-05-31 01:06:58 -04:00
|
|
|
return heap.top().weight;
|
2015-07-13 15:09:19 -04:00
|
|
|
}
|
|
|
|
|
2014-05-05 10:21:41 -04:00
|
|
|
NodeID DeleteMin()
|
|
|
|
{
|
2017-05-02 03:10:05 -04:00
|
|
|
BOOST_ASSERT(!heap.empty());
|
2024-05-31 01:06:58 -04:00
|
|
|
const Key removedIndex = heap.top().index;
|
2024-08-22 16:16:23 -04:00
|
|
|
inserted_nodes[removedIndex].handle = HeapContainer::INVALID_HANDLE;
|
|
|
|
|
|
|
|
heap.pop([this](const auto &heapData, auto new_handle)
|
|
|
|
{ inserted_nodes[heapData.index].handle = new_handle; });
|
2014-05-05 10:21:41 -04:00
|
|
|
return inserted_nodes[removedIndex].node;
|
2011-01-09 16:42:27 -05:00
|
|
|
}
|
|
|
|
|
2020-11-25 06:42:01 -05:00
|
|
|
HeapNode &DeleteMinGetHeapNode()
|
2020-11-23 16:33:08 -05:00
|
|
|
{
|
|
|
|
BOOST_ASSERT(!heap.empty());
|
2024-08-22 16:16:23 -04:00
|
|
|
checkInvariants();
|
2024-05-31 01:06:58 -04:00
|
|
|
const Key removedIndex = heap.top().index;
|
2024-08-22 16:16:23 -04:00
|
|
|
inserted_nodes[removedIndex].handle = HeapContainer::INVALID_HANDLE;
|
|
|
|
heap.pop([this](const auto &heapData, auto new_handle)
|
|
|
|
{ inserted_nodes[heapData.index].handle = new_handle; });
|
|
|
|
checkInvariants();
|
2020-11-23 16:33:08 -05:00
|
|
|
return inserted_nodes[removedIndex];
|
|
|
|
}
|
|
|
|
|
2014-05-05 10:21:41 -04:00
|
|
|
void DeleteAll()
|
|
|
|
{
|
2024-05-06 03:14:46 -04:00
|
|
|
std::for_each(inserted_nodes.begin(),
|
|
|
|
inserted_nodes.end(),
|
2024-08-22 16:16:23 -04:00
|
|
|
[&](auto &node) { node.handle = HeapContainer::INVALID_HANDLE; });
|
2017-05-02 03:10:05 -04:00
|
|
|
heap.clear();
|
2011-01-09 16:42:27 -05:00
|
|
|
}
|
|
|
|
|
2014-05-05 10:21:41 -04:00
|
|
|
void DecreaseKey(NodeID node, Weight weight)
|
|
|
|
{
|
2017-05-02 03:10:05 -04:00
|
|
|
BOOST_ASSERT(!WasRemoved(node));
|
|
|
|
const auto index = node_index.peek_index(node);
|
|
|
|
auto &reference = inserted_nodes[index];
|
|
|
|
reference.weight = weight;
|
2024-08-22 16:16:23 -04:00
|
|
|
heap.decrease(reference.handle,
|
|
|
|
HeapData{weight, static_cast<Key>(index)},
|
|
|
|
[this](const auto &heapData, auto new_handle)
|
|
|
|
{ inserted_nodes[heapData.index].handle = new_handle; });
|
2011-01-09 16:42:27 -05:00
|
|
|
}
|
|
|
|
|
2020-11-25 06:42:01 -05:00
|
|
|
void DecreaseKey(const HeapNode &heapNode)
|
2014-05-05 10:21:41 -04:00
|
|
|
{
|
2020-11-23 16:33:08 -05:00
|
|
|
BOOST_ASSERT(!WasRemoved(heapNode.node));
|
2024-08-22 16:16:23 -04:00
|
|
|
heap.decrease(heapNode.handle,
|
|
|
|
HeapData{heapNode.weight, heap[heapNode.handle].index},
|
|
|
|
[this](const auto &heapData, auto new_handle)
|
|
|
|
{ inserted_nodes[heapData.index].handle = new_handle; });
|
2020-11-23 16:33:08 -05:00
|
|
|
}
|
2011-01-09 16:42:27 -05:00
|
|
|
|
2020-11-23 16:33:08 -05:00
|
|
|
private:
|
2014-05-05 10:21:41 -04:00
|
|
|
std::vector<HeapNode> inserted_nodes;
|
2017-05-02 03:10:05 -04:00
|
|
|
HeapContainer heap;
|
2014-05-05 10:21:41 -04:00
|
|
|
IndexStorage node_index;
|
2011-01-09 16:42:27 -05:00
|
|
|
};
|
2024-08-22 16:16:23 -04:00
|
|
|
|
2022-12-20 12:00:11 -05:00
|
|
|
} // namespace osrm::util
|
2016-01-05 10:51:13 -05:00
|
|
|
|
2017-05-02 07:12:28 -04:00
|
|
|
#endif // OSRM_UTIL_QUERY_HEAP_HPP
|