|
|
@@ -3,6 +3,7 @@ use osmpbf::{Blob, BlobDecode, BlobReader, PrimitiveBlock};
|
|
3
|
3
|
use query::{find_query_matches, QueryArgs, QueryKind};
|
|
4
|
4
|
use scoped_threadpool::Pool;
|
|
5
|
5
|
use std::collections::hash_set::HashSet;
|
|
|
6
|
+use std::hash::{Hash, Hasher};
|
|
6
|
7
|
use std::path::{Path, PathBuf};
|
|
7
|
8
|
use std::sync::mpsc::sync_channel;
|
|
8
|
9
|
use std::thread;
|
|
|
@@ -29,6 +30,40 @@ enum WorkerMessage {
|
|
29
|
30
|
DoBlob(Box<Blob>),
|
|
30
|
31
|
}
|
|
31
|
32
|
|
|
|
33
|
+#[derive(Clone, Copy, Debug)]
|
|
|
34
|
+pub enum MatchItem {
|
|
|
35
|
+ Node{id: i64, pos: LatLonDeg},
|
|
|
36
|
+ Way{id: i64, pos: LatLonDeg},
|
|
|
37
|
+}
|
|
|
38
|
+
|
|
|
39
|
+impl Hash for MatchItem {
|
|
|
40
|
+ fn hash<H: Hasher>(&self, state: &mut H) {
|
|
|
41
|
+ match *self {
|
|
|
42
|
+ MatchItem::Node{id, pos: _} => {
|
|
|
43
|
+ 1u64.hash(state);
|
|
|
44
|
+ id.hash(state);
|
|
|
45
|
+ },
|
|
|
46
|
+ MatchItem::Way{id, pos: _} => {
|
|
|
47
|
+ 2u64.hash(state);
|
|
|
48
|
+ id.hash(state);
|
|
|
49
|
+ },
|
|
|
50
|
+ }
|
|
|
51
|
+ }
|
|
|
52
|
+}
|
|
|
53
|
+
|
|
|
54
|
+impl PartialEq for MatchItem {
|
|
|
55
|
+ fn eq(&self, other: &MatchItem) -> bool {
|
|
|
56
|
+ match (*self, *other) {
|
|
|
57
|
+ (MatchItem::Node{id: a, ..}, MatchItem::Node{id: b, ..}) => a == b,
|
|
|
58
|
+ (MatchItem::Way{id: a, ..}, MatchItem::Way{id: b, ..}) => a == b,
|
|
|
59
|
+ _ => false,
|
|
|
60
|
+ }
|
|
|
61
|
+ }
|
|
|
62
|
+}
|
|
|
63
|
+
|
|
|
64
|
+impl Eq for MatchItem {
|
|
|
65
|
+}
|
|
|
66
|
+
|
|
32
|
67
|
pub fn par_search<P, F, G>(
|
|
33
|
68
|
pbf_path: P,
|
|
34
|
69
|
query_args: QueryArgs,
|
|
|
@@ -36,7 +71,7 @@ pub fn par_search<P, F, G>(
|
|
36
|
71
|
finished_func: G,
|
|
37
|
72
|
) -> Result<thread::JoinHandle<()>, String>
|
|
38
|
73
|
where P: AsRef<Path>,
|
|
39
|
|
- F: Fn(Vec<LatLonDeg>) -> ControlFlow + Send + 'static,
|
|
|
74
|
+ F: Fn(HashSet<MatchItem>) -> ControlFlow + Send + 'static,
|
|
40
|
75
|
G: Fn(Result<(), String>) + Send + 'static,
|
|
41
|
76
|
{
|
|
42
|
77
|
let pbf_path = PathBuf::from(pbf_path.as_ref());
|
|
|
@@ -48,45 +83,62 @@ where P: AsRef<Path>,
|
|
48
|
83
|
Ok(handle)
|
|
49
|
84
|
}
|
|
50
|
85
|
|
|
|
86
|
+fn first_query_pass(block: &PrimitiveBlock, query: &QueryKind)
|
|
|
87
|
+ -> (HashSet<MatchItem>, HashSet<i64>)
|
|
|
88
|
+{
|
|
|
89
|
+ let mut matches = HashSet::new();
|
|
|
90
|
+ let mut way_node_ids = HashSet::new();
|
|
|
91
|
+
|
|
|
92
|
+ match query {
|
|
|
93
|
+ &QueryKind::ValuePattern(ref query) => {
|
|
|
94
|
+ find_query_matches(block, query, &mut matches, &mut way_node_ids);
|
|
|
95
|
+ },
|
|
|
96
|
+ &QueryKind::KeyValue(ref query) => {
|
|
|
97
|
+ find_query_matches(block, query, &mut matches, &mut way_node_ids);
|
|
|
98
|
+ },
|
|
|
99
|
+ &QueryKind::Intersection(ref queries) => {
|
|
|
100
|
+ let mut q_iter = queries.iter();
|
|
|
101
|
+
|
|
|
102
|
+ let (mut sub_matches, mut sub_way_node_ids) = q_iter.next()
|
|
|
103
|
+ .map_or_else(
|
|
|
104
|
+ || (HashSet::new(), HashSet::new()),
|
|
|
105
|
+ |q| first_query_pass(block, q),
|
|
|
106
|
+ );
|
|
|
107
|
+
|
|
|
108
|
+ for q in q_iter {
|
|
|
109
|
+ let (m, w) = first_query_pass(block, q);
|
|
|
110
|
+ sub_matches = sub_matches.intersection(&m).cloned().collect();
|
|
|
111
|
+ sub_way_node_ids = sub_way_node_ids.intersection(&w).cloned().collect();
|
|
|
112
|
+ }
|
|
|
113
|
+ matches.extend(sub_matches);
|
|
|
114
|
+ way_node_ids.extend(sub_way_node_ids);
|
|
|
115
|
+ },
|
|
|
116
|
+ }
|
|
|
117
|
+
|
|
|
118
|
+ (matches, way_node_ids)
|
|
|
119
|
+}
|
|
|
120
|
+
|
|
51
|
121
|
pub fn par_search_blocking<P, F>(
|
|
52
|
122
|
pbf_path: P,
|
|
53
|
123
|
query_args: QueryArgs,
|
|
54
|
124
|
found_func: F,
|
|
55
|
125
|
) -> Result<(), String>
|
|
56
|
126
|
where P: AsRef<Path>,
|
|
57
|
|
- F: Fn(Vec<LatLonDeg>) -> ControlFlow + Send + 'static,
|
|
|
127
|
+ F: Fn(HashSet<MatchItem>) -> ControlFlow + Send + 'static,
|
|
58
|
128
|
{
|
|
59
|
129
|
let query = query_args.compile()?;
|
|
60
|
130
|
let query = &query;
|
|
61
|
131
|
|
|
62
|
|
- let first_pass = move |block: &PrimitiveBlock, _: &()| {
|
|
63
|
|
- let mut matches = vec![];
|
|
64
|
|
- let mut way_node_ids = vec![];
|
|
65
|
|
-
|
|
66
|
|
- match query {
|
|
67
|
|
- &QueryKind::ValuePattern(ref query) => {
|
|
68
|
|
- find_query_matches(block, query, &mut matches, &mut way_node_ids);
|
|
69
|
|
- },
|
|
70
|
|
- &QueryKind::KeyValue(ref query) => {
|
|
71
|
|
- find_query_matches(block, query, &mut matches, &mut way_node_ids);
|
|
72
|
|
- },
|
|
73
|
|
- _ => {
|
|
74
|
|
- //TODO implement
|
|
75
|
|
- unimplemented!();
|
|
76
|
|
- },
|
|
77
|
|
- }
|
|
78
|
|
-
|
|
79
|
|
- (matches, way_node_ids)
|
|
80
|
|
- };
|
|
81
|
|
-
|
|
82
|
132
|
let mut way_node_ids: HashSet<i64> = HashSet::new();
|
|
83
|
133
|
|
|
84
|
134
|
par_iter_blobs(
|
|
85
|
135
|
&pbf_path,
|
|
86
|
136
|
|| {},
|
|
87
|
|
- first_pass,
|
|
|
137
|
+ move |block: &PrimitiveBlock, _: &()| {
|
|
|
138
|
+ first_query_pass(block, query)
|
|
|
139
|
+ },
|
|
88
|
140
|
|(matches, node_ids)| {
|
|
89
|
|
- way_node_ids.extend(&node_ids);
|
|
|
141
|
+ way_node_ids.extend(node_ids);
|
|
90
|
142
|
found_func(matches)
|
|
91
|
143
|
},
|
|
92
|
144
|
)?;
|
|
|
@@ -94,19 +146,23 @@ where P: AsRef<Path>,
|
|
94
|
146
|
let way_node_ids = &way_node_ids;
|
|
95
|
147
|
|
|
96
|
148
|
let second_pass = move |block: &PrimitiveBlock, _: &()| {
|
|
97
|
|
- let mut matches = vec![];
|
|
|
149
|
+ let mut matches = HashSet::new();
|
|
98
|
150
|
|
|
99
|
151
|
for node in block.groups().flat_map(|g| g.nodes()) {
|
|
100
|
152
|
if way_node_ids.contains(&node.id()) {
|
|
101
|
|
- let pos = LatLonDeg::new(node.lat(), node.lon());
|
|
102
|
|
- matches.push(pos);
|
|
|
153
|
+ matches.insert(MatchItem::Way{
|
|
|
154
|
+ id: node.id(),
|
|
|
155
|
+ pos: LatLonDeg::new(node.lat(), node.lon()),
|
|
|
156
|
+ });
|
|
103
|
157
|
}
|
|
104
|
158
|
}
|
|
105
|
159
|
|
|
106
|
160
|
for node in block.groups().flat_map(|g| g.dense_nodes()) {
|
|
107
|
161
|
if way_node_ids.contains(&node.id) {
|
|
108
|
|
- let pos = LatLonDeg::new(node.lat(), node.lon());
|
|
109
|
|
- matches.push(pos);
|
|
|
162
|
+ matches.insert(MatchItem::Way{
|
|
|
163
|
+ id: node.id,
|
|
|
164
|
+ pos: LatLonDeg::new(node.lat(), node.lon()),
|
|
|
165
|
+ });
|
|
110
|
166
|
}
|
|
111
|
167
|
}
|
|
112
|
168
|
|