Skip to content

Commit 0e17869

Browse files
Re-use priority queue in StaticRTree (#6952)
1 parent 5a48ce8 commit 0e17869

File tree

4 files changed

+186
-9
lines changed

4 files changed

+186
-9
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
- NodeJS:
2525
- CHANGED: Use node-api instead of NAN. [#6452](https://github.com/Project-OSRM/osrm-backend/pull/6452)
2626
- Misc:
27+
- CHANGED: Re-use priority queue in StaticRTree. [#6952](https://github.com/Project-OSRM/osrm-backend/pull/6952)
2728
- CHANGED: Optimise encodePolyline function. [#6940](https://github.com/Project-OSRM/osrm-backend/pull/6940)
2829
- CHANGED: Avoid reallocations in base64 encoding. [#6951](https://github.com/Project-OSRM/osrm-backend/pull/6951)
2930
- CHANGED: Get rid of unused Boost dependencies. [#6960](https://github.com/Project-OSRM/osrm-backend/pull/6960)

include/util/binary_heap.hpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#pragma once
2+
#include <algorithm>
3+
#include <boost/assert.hpp>
4+
#include <vector>
5+
6+
namespace osrm::util
7+
{
8+
9+
// in its essence it is std::priority_queue, but with `clear` method
10+
template <typename T> class BinaryHeap
11+
{
12+
public:
13+
bool empty() const { return heap_.empty(); }
14+
15+
const T &top() const
16+
{
17+
BOOST_ASSERT(!heap_.empty());
18+
return heap_.front();
19+
}
20+
21+
void pop()
22+
{
23+
BOOST_ASSERT(!heap_.empty());
24+
std::pop_heap(heap_.begin(), heap_.end());
25+
heap_.pop_back();
26+
}
27+
28+
template <typename... Args> void emplace(Args &&...args)
29+
{
30+
heap_.emplace_back(std::forward<Args>(args)...);
31+
std::push_heap(heap_.begin(), heap_.end());
32+
}
33+
34+
void clear() { heap_.clear(); }
35+
36+
private:
37+
std::vector<T> heap_;
38+
};
39+
40+
} // namespace osrm::util

include/util/static_rtree.hpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
#define STATIC_RTREE_HPP
33

44
#include "storage/tar_fwd.hpp"
5+
#include "osrm/coordinate.hpp"
56
#include "util/bearing.hpp"
7+
#include "util/binary_heap.hpp"
68
#include "util/coordinate_calculation.hpp"
79
#include "util/deallocating_vector.hpp"
810
#include "util/exception.hpp"
@@ -15,8 +17,6 @@
1517
#include "util/vector_view.hpp"
1618
#include "util/web_mercator.hpp"
1719

18-
#include "osrm/coordinate.hpp"
19-
2020
#include "storage/shared_memory_ownership.hpp"
2121

2222
#include <boost/assert.hpp>
@@ -554,9 +554,12 @@ class StaticRTree
554554
auto projected_coordinate = web_mercator::fromWGS84(input_coordinate);
555555
Coordinate fixed_projected_coordinate{projected_coordinate};
556556

557+
// we re-use queue for each query to avoid re-allocating memory
558+
static thread_local util::BinaryHeap<QueryCandidate> traversal_queue;
559+
560+
traversal_queue.clear();
557561
// initialize queue with root element
558-
std::priority_queue<QueryCandidate> traversal_queue;
559-
traversal_queue.push(QueryCandidate{0, TreeIndex{}});
562+
traversal_queue.emplace(QueryCandidate{0, TreeIndex{}});
560563

561564
while (!traversal_queue.empty())
562565
{
@@ -710,10 +713,11 @@ class StaticRTree
710713
// distance must be non-negative
711714
BOOST_ASSERT(0. <= squared_distance);
712715
BOOST_ASSERT(i < std::numeric_limits<std::uint32_t>::max());
713-
traversal_queue.push(QueryCandidate{squared_distance,
714-
leaf_id,
715-
static_cast<std::uint32_t>(i),
716-
Coordinate{projected_nearest}});
716+
717+
traversal_queue.emplace(QueryCandidate{squared_distance,
718+
leaf_id,
719+
static_cast<std::uint32_t>(i),
720+
Coordinate{projected_nearest}});
717721
}
718722
}
719723

@@ -742,7 +746,7 @@ class StaticRTree
742746
child.minimum_bounding_rectangle.GetMinSquaredDist(
743747
fixed_projected_input_coordinate);
744748

745-
traversal_queue.push(QueryCandidate{
749+
traversal_queue.emplace(QueryCandidate{
746750
squared_lower_bound_to_element,
747751
TreeIndex(parent.level + 1, child_index - m_tree_level_starts[parent.level + 1])});
748752
}

unit_tests/util/binary_heap.cpp

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
#include "util/binary_heap.hpp"
2+
3+
#include <boost/test/unit_test.hpp>
4+
#include <string>
5+
6+
BOOST_AUTO_TEST_SUITE(binary_heap_test)
7+
8+
BOOST_AUTO_TEST_CASE(empty_heap)
9+
{
10+
osrm::util::BinaryHeap<int> heap;
11+
BOOST_CHECK(heap.empty());
12+
}
13+
14+
BOOST_AUTO_TEST_CASE(push_and_top)
15+
{
16+
osrm::util::BinaryHeap<int> heap;
17+
heap.emplace(5);
18+
BOOST_CHECK_EQUAL(heap.top(), 5);
19+
BOOST_CHECK(!heap.empty());
20+
}
21+
22+
BOOST_AUTO_TEST_CASE(push_multiple_and_order)
23+
{
24+
osrm::util::BinaryHeap<int> heap;
25+
heap.emplace(5);
26+
heap.emplace(10);
27+
heap.emplace(3);
28+
heap.emplace(8);
29+
BOOST_CHECK_EQUAL(heap.top(), 10);
30+
}
31+
32+
BOOST_AUTO_TEST_CASE(pop_and_order)
33+
{
34+
osrm::util::BinaryHeap<int> heap;
35+
heap.emplace(5);
36+
heap.emplace(10);
37+
heap.emplace(3);
38+
heap.emplace(8);
39+
40+
BOOST_CHECK_EQUAL(heap.top(), 10);
41+
heap.pop();
42+
BOOST_CHECK_EQUAL(heap.top(), 8);
43+
heap.pop();
44+
BOOST_CHECK_EQUAL(heap.top(), 5);
45+
heap.pop();
46+
BOOST_CHECK_EQUAL(heap.top(), 3);
47+
heap.pop();
48+
BOOST_CHECK(heap.empty());
49+
}
50+
51+
BOOST_AUTO_TEST_CASE(clear_heap)
52+
{
53+
osrm::util::BinaryHeap<int> heap;
54+
heap.emplace(5);
55+
heap.emplace(10);
56+
heap.clear();
57+
BOOST_CHECK(heap.empty());
58+
}
59+
60+
BOOST_AUTO_TEST_CASE(emplace_with_custom_type)
61+
{
62+
struct CustomType
63+
{
64+
int value;
65+
CustomType(int v) : value(v) {}
66+
bool operator<(const CustomType &other) const { return value < other.value; }
67+
};
68+
69+
osrm::util::BinaryHeap<CustomType> heap;
70+
heap.emplace(5);
71+
heap.emplace(10);
72+
heap.emplace(3);
73+
BOOST_CHECK_EQUAL(heap.top().value, 10);
74+
}
75+
76+
BOOST_AUTO_TEST_CASE(large_number_of_elements)
77+
{
78+
osrm::util::BinaryHeap<int> heap;
79+
for (int i = 0; i < 1000; ++i)
80+
{
81+
heap.emplace(i);
82+
}
83+
BOOST_CHECK_EQUAL(heap.top(), 999);
84+
85+
for (int i = 999; i >= 0; --i)
86+
{
87+
BOOST_CHECK_EQUAL(heap.top(), i);
88+
heap.pop();
89+
}
90+
BOOST_CHECK(heap.empty());
91+
}
92+
93+
BOOST_AUTO_TEST_CASE(duplicate_values)
94+
{
95+
osrm::util::BinaryHeap<int> heap;
96+
heap.emplace(5);
97+
heap.emplace(5);
98+
heap.emplace(5);
99+
100+
BOOST_CHECK_EQUAL(heap.top(), 5);
101+
heap.pop();
102+
BOOST_CHECK_EQUAL(heap.top(), 5);
103+
heap.pop();
104+
BOOST_CHECK_EQUAL(heap.top(), 5);
105+
heap.pop();
106+
BOOST_CHECK(heap.empty());
107+
}
108+
109+
BOOST_AUTO_TEST_CASE(string_type)
110+
{
111+
osrm::util::BinaryHeap<std::string> heap;
112+
heap.emplace("apple");
113+
heap.emplace("banana");
114+
heap.emplace("cherry");
115+
116+
BOOST_CHECK_EQUAL(heap.top(), "cherry");
117+
heap.pop();
118+
BOOST_CHECK_EQUAL(heap.top(), "banana");
119+
heap.pop();
120+
BOOST_CHECK_EQUAL(heap.top(), "apple");
121+
}
122+
123+
BOOST_AUTO_TEST_CASE(emplace_after_clear)
124+
{
125+
osrm::util::BinaryHeap<int> heap;
126+
heap.emplace(5);
127+
heap.clear();
128+
heap.emplace(10);
129+
BOOST_CHECK_EQUAL(heap.top(), 10);
130+
}
131+
132+
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)