44#include < boost/assert.hpp>
55#include < boost/heap/d_ary_heap.hpp>
66
7+ #include " d_ary_heap.hpp"
78#include < algorithm>
89#include < cstdint>
10+ #include < cstdlib>
911#include < limits>
1012#include < map>
1113#include < optional>
@@ -133,20 +135,17 @@ class QueryHeap
133135 Weight weight;
134136 Key index;
135137
136- bool operator > (const HeapData &other) const
138+ bool operator < (const HeapData &other) const
137139 {
138140 if (weight == other.weight )
139141 {
140- return index > other.index ;
142+ return index < other.index ;
141143 }
142- return weight > other.weight ;
144+ return weight < other.weight ;
143145 }
144146 };
145- using HeapContainer = boost::heap::d_ary_heap<HeapData,
146- boost::heap::arity<4 >,
147- boost::heap::mutable_<true >,
148- boost::heap::compare<std::greater<HeapData>>>;
149- using HeapHandle = typename HeapContainer::handle_type;
147+ using HeapContainer = DAryHeap<HeapData, 4 >;
148+ using HeapHandle = typename HeapContainer::HeapHandle;
150149
151150 public:
152151 using WeightType = Weight;
@@ -178,11 +177,31 @@ class QueryHeap
178177
179178 void Insert (NodeID node, Weight weight, const Data &data)
180179 {
180+ checkInvariants ();
181+
181182 BOOST_ASSERT (node < std::numeric_limits<NodeID>::max ());
182183 const auto index = static_cast <Key>(inserted_nodes.size ());
183- const auto handle = heap.emplace (HeapData{weight, index});
184- inserted_nodes.emplace_back (HeapNode{handle, node, weight, data});
184+ inserted_nodes.emplace_back (HeapNode{heap.size (), node, weight, data});
185+
186+ heap.emplace (HeapData{weight, index},
187+ [this ](const auto &heapData, auto new_handle)
188+ { inserted_nodes[heapData.index ].handle = new_handle; });
185189 node_index[node] = index;
190+
191+ checkInvariants ();
192+ }
193+
194+ void checkInvariants ()
195+ {
196+ #ifndef NDEBUG
197+ for (size_t handle = 0 ; handle < heap.size (); ++handle)
198+ {
199+ auto &in_heap = heap[handle];
200+ auto &inserted = inserted_nodes[in_heap.index ];
201+ BOOST_ASSERT (in_heap.weight == inserted.weight );
202+ BOOST_ASSERT (inserted.handle == handle);
203+ }
204+ #endif // !NDEBUG
186205 }
187206
188207 Data &GetData (NodeID node)
@@ -216,16 +235,7 @@ class QueryHeap
216235 {
217236 BOOST_ASSERT (WasInserted (node));
218237 const Key index = node_index.peek_index (node);
219-
220- // Use end iterator as a reliable "non-existent" handle.
221- // Default-constructed handles are singular and
222- // can only be checked-compared to another singular instance.
223- // Behaviour investigated at https://lists.boost.org/boost-users/2017/08/87787.php,
224- // eventually confirmation at https://stackoverflow.com/a/45622940/151641.
225- // Corrected in https://github.com/Project-OSRM/osrm-backend/pull/4396
226- auto const end_it = const_cast <HeapContainer &>(heap).end (); // non-const iterator
227- auto const none_handle = heap.s_handle_from_iterator (end_it); // from non-const iterator
228- return inserted_nodes[index].handle == none_handle;
238+ return inserted_nodes[index].handle == HeapContainer::INVALID_HANDLE;
229239 }
230240
231241 bool WasInserted (const NodeID node) const
@@ -276,26 +286,30 @@ class QueryHeap
276286 {
277287 BOOST_ASSERT (!heap.empty ());
278288 const Key removedIndex = heap.top ().index ;
279- heap.pop ();
280- inserted_nodes[removedIndex].handle = heap.s_handle_from_iterator (heap.end ());
289+ inserted_nodes[removedIndex].handle = HeapContainer::INVALID_HANDLE;
290+
291+ heap.pop ([this ](const auto &heapData, auto new_handle)
292+ { inserted_nodes[heapData.index ].handle = new_handle; });
281293 return inserted_nodes[removedIndex].node ;
282294 }
283295
284296 HeapNode &DeleteMinGetHeapNode ()
285297 {
286298 BOOST_ASSERT (!heap.empty ());
299+ checkInvariants ();
287300 const Key removedIndex = heap.top ().index ;
288- heap.pop ();
289- inserted_nodes[removedIndex].handle = heap.s_handle_from_iterator (heap.end ());
301+ inserted_nodes[removedIndex].handle = HeapContainer::INVALID_HANDLE;
302+ heap.pop ([this ](const auto &heapData, auto new_handle)
303+ { inserted_nodes[heapData.index ].handle = new_handle; });
304+ checkInvariants ();
290305 return inserted_nodes[removedIndex];
291306 }
292307
293308 void DeleteAll ()
294309 {
295- auto const none_handle = heap.s_handle_from_iterator (heap.end ());
296310 std::for_each (inserted_nodes.begin (),
297311 inserted_nodes.end (),
298- [&none_handle ](auto &node) { node.handle = none_handle ; });
312+ [&](auto &node) { node.handle = HeapContainer::INVALID_HANDLE ; });
299313 heap.clear ();
300314 }
301315
@@ -305,20 +319,27 @@ class QueryHeap
305319 const auto index = node_index.peek_index (node);
306320 auto &reference = inserted_nodes[index];
307321 reference.weight = weight;
308- heap.increase (reference.handle , HeapData{weight, static_cast <Key>(index)});
322+ heap.decrease (reference.handle ,
323+ HeapData{weight, static_cast <Key>(index)},
324+ [this ](const auto &heapData, auto new_handle)
325+ { inserted_nodes[heapData.index ].handle = new_handle; });
309326 }
310327
311328 void DecreaseKey (const HeapNode &heapNode)
312329 {
313330 BOOST_ASSERT (!WasRemoved (heapNode.node ));
314- heap.increase (heapNode.handle , HeapData{heapNode.weight , (*heapNode.handle ).index });
331+ heap.decrease (heapNode.handle ,
332+ HeapData{heapNode.weight , heap[heapNode.handle ].index },
333+ [this ](const auto &heapData, auto new_handle)
334+ { inserted_nodes[heapData.index ].handle = new_handle; });
315335 }
316336
317337 private:
318338 std::vector<HeapNode> inserted_nodes;
319339 HeapContainer heap;
320340 IndexStorage node_index;
321341};
342+
322343} // namespace osrm::util
323344
324345#endif // OSRM_UTIL_QUERY_HEAP_HPP
0 commit comments