4
4
#include < boost/assert.hpp>
5
5
#include < boost/heap/d_ary_heap.hpp>
6
6
7
+ #include " d_ary_heap.hpp"
7
8
#include < algorithm>
8
9
#include < cstdint>
10
+ #include < cstdlib>
9
11
#include < limits>
10
12
#include < map>
11
13
#include < optional>
@@ -133,20 +135,17 @@ class QueryHeap
133
135
Weight weight;
134
136
Key index;
135
137
136
- bool operator > (const HeapData &other) const
138
+ bool operator < (const HeapData &other) const
137
139
{
138
140
if (weight == other.weight )
139
141
{
140
- return index > other.index ;
142
+ return index < other.index ;
141
143
}
142
- return weight > other.weight ;
144
+ return weight < other.weight ;
143
145
}
144
146
};
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;
150
149
151
150
public:
152
151
using WeightType = Weight;
@@ -178,11 +177,31 @@ class QueryHeap
178
177
179
178
void Insert (NodeID node, Weight weight, const Data &data)
180
179
{
180
+ checkInvariants ();
181
+
181
182
BOOST_ASSERT (node < std::numeric_limits<NodeID>::max ());
182
183
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; });
185
189
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
186
205
}
187
206
188
207
Data &GetData (NodeID node)
@@ -216,16 +235,7 @@ class QueryHeap
216
235
{
217
236
BOOST_ASSERT (WasInserted (node));
218
237
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;
229
239
}
230
240
231
241
bool WasInserted (const NodeID node) const
@@ -276,26 +286,30 @@ class QueryHeap
276
286
{
277
287
BOOST_ASSERT (!heap.empty ());
278
288
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; });
281
293
return inserted_nodes[removedIndex].node ;
282
294
}
283
295
284
296
HeapNode &DeleteMinGetHeapNode ()
285
297
{
286
298
BOOST_ASSERT (!heap.empty ());
299
+ checkInvariants ();
287
300
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 ();
290
305
return inserted_nodes[removedIndex];
291
306
}
292
307
293
308
void DeleteAll ()
294
309
{
295
- auto const none_handle = heap.s_handle_from_iterator (heap.end ());
296
310
std::for_each (inserted_nodes.begin (),
297
311
inserted_nodes.end (),
298
- [&none_handle ](auto &node) { node.handle = none_handle ; });
312
+ [&](auto &node) { node.handle = HeapContainer::INVALID_HANDLE ; });
299
313
heap.clear ();
300
314
}
301
315
@@ -305,20 +319,27 @@ class QueryHeap
305
319
const auto index = node_index.peek_index (node);
306
320
auto &reference = inserted_nodes[index];
307
321
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; });
309
326
}
310
327
311
328
void DecreaseKey (const HeapNode &heapNode)
312
329
{
313
330
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; });
315
335
}
316
336
317
337
private:
318
338
std::vector<HeapNode> inserted_nodes;
319
339
HeapContainer heap;
320
340
IndexStorage node_index;
321
341
};
342
+
322
343
} // namespace osrm::util
323
344
324
345
#endif // OSRM_UTIL_QUERY_HEAP_HPP
0 commit comments