/root/doris/be/src/util/interval_tree-inl.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | // |
18 | | // This file is copied from |
19 | | // https://github.com/apache/kudu/blob/master/src/kudu/util/interval_tree-inl.h |
20 | | // and modified by Doris |
21 | | // |
22 | | |
23 | | #pragma once |
24 | | |
25 | | #include <algorithm> |
26 | | #include <vector> |
27 | | |
28 | | #include "util/interval_tree.h" |
29 | | |
30 | | namespace doris { |
31 | | |
32 | | template <class Traits> |
33 | 4 | IntervalTree<Traits>::IntervalTree(const IntervalVector& intervals) : root_(NULL) { |
34 | 4 | if (!intervals.empty()) { |
35 | 3 | root_ = CreateNode(intervals); |
36 | 3 | } |
37 | 4 | } |
38 | | |
39 | | template <class Traits> |
40 | 4 | IntervalTree<Traits>::~IntervalTree() { |
41 | 4 | delete root_; |
42 | 4 | } |
43 | | |
44 | | template <class Traits> |
45 | | template <class QueryPointType> |
46 | | void IntervalTree<Traits>::FindContainingPoint(const QueryPointType& query, |
47 | 210 | IntervalVector* results) const { |
48 | 210 | if (root_) { |
49 | 209 | root_->FindContainingPoint(query, results); |
50 | 209 | } |
51 | 210 | } _ZNK5doris12IntervalTreeINS_9IntTraitsEE19FindContainingPointIiEEvRKT_PSt6vectorINS_11IntIntervalESaIS8_EE Line | Count | Source | 47 | 210 | IntervalVector* results) const { | 48 | 210 | if (root_) { | 49 | 209 | root_->FindContainingPoint(query, results); | 50 | 209 | } | 51 | 210 | } |
Unexecuted instantiation: _ZNK5doris12IntervalTreeINS_9IntTraitsEE19FindContainingPointINS_18CountingQueryPointEEEvRKT_PSt6vectorINS_11IntIntervalESaIS9_EE |
52 | | |
53 | | template <class Traits> |
54 | | template <class Callback, class QueryContainer> |
55 | | void IntervalTree<Traits>::ForEachIntervalContainingPoints(const QueryContainer& queries, |
56 | 1 | const Callback& cb) const { |
57 | 1 | if (root_) { |
58 | 1 | root_->ForEachIntervalContainingPoints(queries.begin(), queries.end(), cb); |
59 | 1 | } |
60 | 1 | } interval_tree_test.cpp:_ZNK5doris12IntervalTreeINS_9IntTraitsEE31ForEachIntervalContainingPointsIZNS_36TestIntervalTree_TestMultiQuery_Test8TestBodyEvE3$_0St6vectorIiSaIiEEEEvRKT0_RKT_ Line | Count | Source | 56 | 1 | const Callback& cb) const { | 57 | 1 | if (root_) { | 58 | 1 | root_->ForEachIntervalContainingPoints(queries.begin(), queries.end(), cb); | 59 | 1 | } | 60 | 1 | } |
Unexecuted instantiation: interval_tree_test.cpp:_ZNK5doris12IntervalTreeINS_9IntTraitsEE31ForEachIntervalContainingPointsIZNS_30TestIntervalTree_TestBigO_Test8TestBodyEvE3$_1St6vectorINS_18CountingQueryPointESaIS7_EEEEvRKT0_RKT_ |
61 | | |
62 | | template <class Traits> |
63 | | template <class QueryPointType> |
64 | | void IntervalTree<Traits>::FindIntersectingInterval(const QueryPointType& lower_bound, |
65 | | const QueryPointType& upper_bound, |
66 | 488 | IntervalVector* results) const { |
67 | 488 | if (root_) { |
68 | 484 | root_->FindIntersectingInterval(lower_bound, upper_bound, results); |
69 | 484 | } |
70 | 488 | } |
71 | | |
72 | | template <class Traits> |
73 | 3.95k | bool LessThan(const typename Traits::point_type& a, const typename Traits::point_type& b) { |
74 | 3.95k | return Traits::compare(a, b) < 0; |
75 | 3.95k | } |
76 | | |
77 | | // Select a split point which attempts to evenly divide 'in' into three groups: |
78 | | // (a) those that are fully left of the split point |
79 | | // (b) those that overlap the split point. |
80 | | // (c) those that are fully right of the split point |
81 | | // These three groups are stored in the output parameters '*left', '*overlapping', |
82 | | // and '*right', respectively. The selected split point is stored in *split_point. |
83 | | // |
84 | | // For example, the input interval set: |
85 | | // |
86 | | // |------1-------| |-----2-----| |
87 | | // |--3--| |---4--| |----5----| |
88 | | // | |
89 | | // Resulting split: | Partition point |
90 | | // | |
91 | | // |
92 | | // *left: intervals 1 and 3 |
93 | | // *overlapping: interval 4 |
94 | | // *right: intervals 2 and 5 |
95 | | template <class Traits> |
96 | | void IntervalTree<Traits>::Partition(const IntervalVector& in, point_type* split_point, |
97 | | IntervalVector* left, IntervalVector* overlapping, |
98 | 27 | IntervalVector* right) { |
99 | 27 | CHECK(!in.empty()); |
100 | | |
101 | | // Pick a split point which is the median of all of the interval boundaries. |
102 | 27 | std::vector<point_type> endpoints; |
103 | 27 | endpoints.reserve(in.size() * 2); |
104 | 299 | for (const interval_type& interval : in) { |
105 | 299 | endpoints.push_back(Traits::get_left(interval)); |
106 | 299 | endpoints.push_back(Traits::get_right(interval)); |
107 | 299 | } |
108 | 27 | std::sort(endpoints.begin(), endpoints.end(), LessThan<Traits>); |
109 | 27 | *split_point = endpoints[endpoints.size() / 2]; |
110 | | |
111 | | // Partition into the groups based on the determined split point. |
112 | 299 | for (const interval_type& interval : in) { |
113 | 299 | if (Traits::compare(Traits::get_right(interval), *split_point) < 0) { |
114 | | // | split point |
115 | | // |------------| | |
116 | | // interval |
117 | 95 | left->push_back(interval); |
118 | 204 | } else if (Traits::compare(Traits::get_left(interval), *split_point) > 0) { |
119 | | // | split point |
120 | | // | |------------| |
121 | | // interval |
122 | 91 | right->push_back(interval); |
123 | 113 | } else { |
124 | | // | split point |
125 | | // | |
126 | | // |------------| |
127 | | // interval |
128 | 113 | overlapping->push_back(interval); |
129 | 113 | } |
130 | 299 | } |
131 | 27 | } |
132 | | |
133 | | template <class Traits> |
134 | | typename IntervalTree<Traits>::node_type* IntervalTree<Traits>::CreateNode( |
135 | 27 | const IntervalVector& intervals) { |
136 | 27 | IntervalVector left, right, overlap; |
137 | 27 | point_type split_point; |
138 | | |
139 | | // First partition the input intervals and select a split point |
140 | 27 | Partition(intervals, &split_point, &left, &overlap, &right); |
141 | | |
142 | | // Recursively subdivide the intervals which are fully left or fully |
143 | | // right of the split point into subtree nodes. |
144 | 27 | node_type* left_node = !left.empty() ? CreateNode(left) : NULL; |
145 | 27 | node_type* right_node = !right.empty() ? CreateNode(right) : NULL; |
146 | | |
147 | 27 | return new node_type(split_point, left_node, overlap, right_node); |
148 | 27 | } |
149 | | |
150 | | namespace interval_tree_internal { |
151 | | |
152 | | // Node in the interval tree. |
153 | | template <typename Traits> |
154 | | class ITNode { |
155 | | private: |
156 | | // Import types. |
157 | | typedef std::vector<typename Traits::interval_type> IntervalVector; |
158 | | typedef typename Traits::interval_type interval_type; |
159 | | typedef typename Traits::point_type point_type; |
160 | | |
161 | | public: |
162 | | ITNode(point_type split_point, ITNode<Traits>* left, const IntervalVector& overlap, |
163 | | ITNode<Traits>* right); |
164 | | ~ITNode(); |
165 | | |
166 | | // See IntervalTree::FindContainingPoint(...) |
167 | | template <class QueryPointType> |
168 | | void FindContainingPoint(const QueryPointType& query, IntervalVector* results) const; |
169 | | |
170 | | // See IntervalTree::ForEachIntervalContainingPoints(). |
171 | | // We use iterators here since as recursion progresses down the tree, we |
172 | | // process sub-sequences of the original set of query points. |
173 | | template <class Callback, class ItType> |
174 | | void ForEachIntervalContainingPoints(ItType begin_queries, ItType end_queries, |
175 | | const Callback& cb) const; |
176 | | |
177 | | // See IntervalTree::FindIntersectingInterval(...) |
178 | | template <class QueryPointType> |
179 | | void FindIntersectingInterval(const QueryPointType& lower_bound, |
180 | | const QueryPointType& upper_bound, IntervalVector* results) const; |
181 | | |
182 | | private: |
183 | | // Comparators for sorting lists of intervals. |
184 | | static bool SortByAscLeft(const interval_type& a, const interval_type& b); |
185 | | static bool SortByDescRight(const interval_type& a, const interval_type& b); |
186 | | |
187 | | // Partition point of this node. |
188 | | point_type split_point_; |
189 | | |
190 | | // Those nodes that overlap with split_point_, in ascending order by their left side. |
191 | | IntervalVector overlapping_by_asc_left_; |
192 | | |
193 | | // Those nodes that overlap with split_point_, in descending order by their right side. |
194 | | IntervalVector overlapping_by_desc_right_; |
195 | | |
196 | | // Tree node for intervals fully left of split_point_, or NULL. |
197 | | ITNode* left_ = nullptr; |
198 | | |
199 | | // Tree node for intervals fully right of split_point_, or NULL. |
200 | | ITNode* right_ = nullptr; |
201 | | |
202 | | DISALLOW_COPY_AND_ASSIGN(ITNode); |
203 | | }; |
204 | | |
205 | | template <class Traits> |
206 | 276 | bool ITNode<Traits>::SortByAscLeft(const interval_type& a, const interval_type& b) { |
207 | 276 | return Traits::compare(Traits::get_left(a), Traits::get_left(b)) < 0; |
208 | 276 | } |
209 | | |
210 | | template <class Traits> |
211 | 291 | bool ITNode<Traits>::SortByDescRight(const interval_type& a, const interval_type& b) { |
212 | 291 | return Traits::compare(Traits::get_right(a), Traits::get_right(b)) > 0; |
213 | 291 | } |
214 | | |
215 | | template <class Traits> |
216 | | ITNode<Traits>::ITNode(typename Traits::point_type split_point, ITNode<Traits>* left, |
217 | | const IntervalVector& overlap, ITNode<Traits>* right) |
218 | 27 | : split_point_(std::move(split_point)), left_(left), right_(right) { |
219 | | // Store two copies of the set of intervals which overlap the split point: |
220 | | // 1) Sorted by ascending left boundary |
221 | 27 | overlapping_by_asc_left_.assign(overlap.begin(), overlap.end()); |
222 | 27 | std::sort(overlapping_by_asc_left_.begin(), overlapping_by_asc_left_.end(), SortByAscLeft); |
223 | | // 2) Sorted by descending right boundary |
224 | 27 | overlapping_by_desc_right_.assign(overlap.begin(), overlap.end()); |
225 | 27 | std::sort(overlapping_by_desc_right_.begin(), overlapping_by_desc_right_.end(), |
226 | 27 | SortByDescRight); |
227 | 27 | } |
228 | | |
229 | | template <class Traits> |
230 | 27 | ITNode<Traits>::~ITNode() { |
231 | 27 | if (left_) delete left_; |
232 | 27 | if (right_) delete right_; |
233 | 27 | } |
234 | | |
235 | | template <class Traits> |
236 | | template <class Callback, class ItType> |
237 | | void ITNode<Traits>::ForEachIntervalContainingPoints(ItType begin_queries, ItType end_queries, |
238 | 6 | const Callback& cb) const { |
239 | 6 | if (begin_queries == end_queries) return; |
240 | | |
241 | 3 | typedef decltype(*begin_queries) QueryPointType; |
242 | 6 | const auto& partitioner = [&](const QueryPointType& query_point) { |
243 | 6 | return Traits::compare(query_point, split_point_) < 0; |
244 | 6 | }; |
245 | | |
246 | | // Partition the query points into those less than the split_point_ and those greater |
247 | | // than or equal to the split_point_. Because the input queries are already sorted, we |
248 | | // can use 'std::partition_point' instead of 'std::partition'. |
249 | | // |
250 | | // The resulting 'partition_point' is the first query point in the second group. |
251 | | // |
252 | | // Complexity: O(log(number of query points)) |
253 | 3 | DCHECK(std::is_partitioned(begin_queries, end_queries, partitioner)); |
254 | 3 | auto partition_point = std::partition_point(begin_queries, end_queries, partitioner); |
255 | | |
256 | | // Recurse left: any query points left of the split point may intersect |
257 | | // with non-overlapping intervals fully-left of our split point. |
258 | 3 | if (left_ != NULL) { |
259 | 3 | left_->ForEachIntervalContainingPoints(begin_queries, partition_point, cb); |
260 | 3 | } |
261 | | |
262 | | // Handle the query points < split_point / |
263 | | // / |
264 | | // split_point_ / |
265 | | // | / |
266 | | // [------] \ / |
267 | | // [-------] | overlapping_by_asc_left_ / |
268 | | // [--------] / / |
269 | | // Q Q Q / |
270 | | // ^ ^ \___ not handled (right of split_point_) / |
271 | | // | | / |
272 | | // \___\___ these points will be handled here / |
273 | | // |
274 | | |
275 | | // Lower bound of query points still relevant. |
276 | 3 | auto rem_queries = begin_queries; |
277 | 4 | for (const interval_type& interval : overlapping_by_asc_left_) { |
278 | 4 | const auto& interval_left = Traits::get_left(interval); |
279 | | // Find those query points which are right of the left side of the interval. |
280 | | // 'first_match' here is the first query point >= interval_left. |
281 | | // Complexity: O(log(num_queries)) |
282 | | // |
283 | | // TODO(todd): The non-batched implementation is O(log(num_intervals) * num_queries) |
284 | | // whereas this loop ends up O(num_intervals * log(num_queries)). So, for |
285 | | // small numbers of queries this is not the fastest way to structure these loops. |
286 | 4 | auto first_match = std::partition_point( |
287 | 4 | rem_queries, partition_point, [&](const QueryPointType& query_point) { |
288 | 2 | return Traits::compare(query_point, interval_left) < 0; |
289 | 2 | }); |
290 | 4 | for (auto it = first_match; it != partition_point; ++it) { |
291 | 0 | cb(*it, interval); |
292 | 0 | } |
293 | | // Since the intervals are sorted in ascending-left order, we can start |
294 | | // the search for the next interval at the first match in this interval. |
295 | | // (any query point which was left of the current interval will also be left |
296 | | // of all future intervals). |
297 | 4 | rem_queries = std::move(first_match); |
298 | 4 | } |
299 | | |
300 | | // Handle the query points >= split_point / |
301 | | // / |
302 | | // split_point_ / |
303 | | // | / |
304 | | // [--------] \ / |
305 | | // [-------] | overlapping_by_desc_right_ / |
306 | | // [------] / / |
307 | | // Q Q Q / |
308 | | // | \______\___ these points will be handled here / |
309 | | // | / |
310 | | // \___ not handled (left of split_point_) / |
311 | | |
312 | | // Upper bound of query points still relevant. |
313 | 3 | rem_queries = end_queries; |
314 | 4 | for (const interval_type& interval : overlapping_by_desc_right_) { |
315 | 4 | const auto& interval_right = Traits::get_right(interval); |
316 | | // Find the first query point which is > the right side of the interval. |
317 | 4 | auto first_non_match = std::partition_point( |
318 | 4 | partition_point, rem_queries, [&](const QueryPointType& query_point) { |
319 | 1 | return Traits::compare(query_point, interval_right) <= 0; |
320 | 1 | }); |
321 | 5 | for (auto it = partition_point; it != first_non_match; ++it) { |
322 | 1 | cb(*it, interval); |
323 | 1 | } |
324 | | // Same logic as above: if a query point was fully right of 'interval', |
325 | | // then it will be fully right of all following intervals because they are |
326 | | // sorted by descending-right. |
327 | 4 | rem_queries = std::move(first_non_match); |
328 | 4 | } |
329 | | |
330 | 3 | if (right_ != NULL) { |
331 | 2 | while (partition_point != end_queries && |
332 | 2 | Traits::compare(*partition_point, split_point_) == 0) { |
333 | 0 | ++partition_point; |
334 | 0 | } |
335 | 2 | right_->ForEachIntervalContainingPoints(partition_point, end_queries, cb); |
336 | 2 | } |
337 | 3 | } interval_tree_test.cpp:_ZNK5doris22interval_tree_internal6ITNodeINS_9IntTraitsEE31ForEachIntervalContainingPointsIZNS_36TestIntervalTree_TestMultiQuery_Test8TestBodyEvE3$_0N9__gnu_cxx17__normal_iteratorIPKiSt6vectorIiSaIiEEEEEEvT0_SF_RKT_ Line | Count | Source | 238 | 6 | const Callback& cb) const { | 239 | 6 | if (begin_queries == end_queries) return; | 240 | | | 241 | 3 | typedef decltype(*begin_queries) QueryPointType; | 242 | 3 | const auto& partitioner = [&](const QueryPointType& query_point) { | 243 | 3 | return Traits::compare(query_point, split_point_) < 0; | 244 | 3 | }; | 245 | | | 246 | | // Partition the query points into those less than the split_point_ and those greater | 247 | | // than or equal to the split_point_. Because the input queries are already sorted, we | 248 | | // can use 'std::partition_point' instead of 'std::partition'. | 249 | | // | 250 | | // The resulting 'partition_point' is the first query point in the second group. | 251 | | // | 252 | | // Complexity: O(log(number of query points)) | 253 | 3 | DCHECK(std::is_partitioned(begin_queries, end_queries, partitioner)); | 254 | 3 | auto partition_point = std::partition_point(begin_queries, end_queries, partitioner); | 255 | | | 256 | | // Recurse left: any query points left of the split point may intersect | 257 | | // with non-overlapping intervals fully-left of our split point. | 258 | 3 | if (left_ != NULL) { | 259 | 3 | left_->ForEachIntervalContainingPoints(begin_queries, partition_point, cb); | 260 | 3 | } | 261 | | | 262 | | // Handle the query points < split_point / | 263 | | // / | 264 | | // split_point_ / | 265 | | // | / | 266 | | // [------] \ / | 267 | | // [-------] | overlapping_by_asc_left_ / | 268 | | // [--------] / / | 269 | | // Q Q Q / | 270 | | // ^ ^ \___ not handled (right of split_point_) / | 271 | | // | | / | 272 | | // \___\___ these points will be handled here / | 273 | | // | 274 | | | 275 | | // Lower bound of query points still relevant. | 276 | 3 | auto rem_queries = begin_queries; | 277 | 4 | for (const interval_type& interval : overlapping_by_asc_left_) { | 278 | 4 | const auto& interval_left = Traits::get_left(interval); | 279 | | // Find those query points which are right of the left side of the interval. | 280 | | // 'first_match' here is the first query point >= interval_left. | 281 | | // Complexity: O(log(num_queries)) | 282 | | // | 283 | | // TODO(todd): The non-batched implementation is O(log(num_intervals) * num_queries) | 284 | | // whereas this loop ends up O(num_intervals * log(num_queries)). So, for | 285 | | // small numbers of queries this is not the fastest way to structure these loops. | 286 | 4 | auto first_match = std::partition_point( | 287 | 4 | rem_queries, partition_point, [&](const QueryPointType& query_point) { | 288 | 4 | return Traits::compare(query_point, interval_left) < 0; | 289 | 4 | }); | 290 | 4 | for (auto it = first_match; it != partition_point; ++it) { | 291 | 0 | cb(*it, interval); | 292 | 0 | } | 293 | | // Since the intervals are sorted in ascending-left order, we can start | 294 | | // the search for the next interval at the first match in this interval. | 295 | | // (any query point which was left of the current interval will also be left | 296 | | // of all future intervals). | 297 | 4 | rem_queries = std::move(first_match); | 298 | 4 | } | 299 | | | 300 | | // Handle the query points >= split_point / | 301 | | // / | 302 | | // split_point_ / | 303 | | // | / | 304 | | // [--------] \ / | 305 | | // [-------] | overlapping_by_desc_right_ / | 306 | | // [------] / / | 307 | | // Q Q Q / | 308 | | // | \______\___ these points will be handled here / | 309 | | // | / | 310 | | // \___ not handled (left of split_point_) / | 311 | | | 312 | | // Upper bound of query points still relevant. | 313 | 3 | rem_queries = end_queries; | 314 | 4 | for (const interval_type& interval : overlapping_by_desc_right_) { | 315 | 4 | const auto& interval_right = Traits::get_right(interval); | 316 | | // Find the first query point which is > the right side of the interval. | 317 | 4 | auto first_non_match = std::partition_point( | 318 | 4 | partition_point, rem_queries, [&](const QueryPointType& query_point) { | 319 | 4 | return Traits::compare(query_point, interval_right) <= 0; | 320 | 4 | }); | 321 | 5 | for (auto it = partition_point; it != first_non_match; ++it) { | 322 | 1 | cb(*it, interval); | 323 | 1 | } | 324 | | // Same logic as above: if a query point was fully right of 'interval', | 325 | | // then it will be fully right of all following intervals because they are | 326 | | // sorted by descending-right. | 327 | 4 | rem_queries = std::move(first_non_match); | 328 | 4 | } | 329 | | | 330 | 3 | if (right_ != NULL) { | 331 | 2 | while (partition_point != end_queries && | 332 | 2 | Traits::compare(*partition_point, split_point_) == 0) { | 333 | 0 | ++partition_point; | 334 | 0 | } | 335 | 2 | right_->ForEachIntervalContainingPoints(partition_point, end_queries, cb); | 336 | 2 | } | 337 | 3 | } |
Unexecuted instantiation: interval_tree_test.cpp:_ZNK5doris22interval_tree_internal6ITNodeINS_9IntTraitsEE31ForEachIntervalContainingPointsIZNS_30TestIntervalTree_TestBigO_Test8TestBodyEvE3$_1N9__gnu_cxx17__normal_iteratorIPKNS_18CountingQueryPointESt6vectorIS9_SaIS9_EEEEEEvT0_SG_RKT_ |
338 | | |
339 | | template <class Traits> |
340 | | template <class QueryPointType> |
341 | | void ITNode<Traits>::FindContainingPoint(const QueryPointType& query, |
342 | 839 | IntervalVector* results) const { |
343 | 839 | int cmp = Traits::compare(query, split_point_); |
344 | 839 | if (cmp < 0) { |
345 | | // None of the intervals in right_ may intersect this. |
346 | 240 | if (left_ != NULL) { |
347 | 199 | left_->FindContainingPoint(query, results); |
348 | 199 | } |
349 | | |
350 | | // Any intervals which start before the query point and overlap the split point |
351 | | // must therefore contain the query point. |
352 | 240 | auto p = std::partition_point( |
353 | 240 | overlapping_by_asc_left_.cbegin(), overlapping_by_asc_left_.cend(), |
354 | 785 | [&](const interval_type& interval) { |
355 | 785 | return Traits::compare(Traits::get_left(interval), query) <= 0; |
356 | 785 | }); |
357 | 240 | results->insert(results->end(), overlapping_by_asc_left_.cbegin(), p); |
358 | 599 | } else if (cmp > 0) { |
359 | | // None of the intervals in left_ may intersect this. |
360 | 579 | if (right_ != NULL) { |
361 | 431 | right_->FindContainingPoint(query, results); |
362 | 431 | } |
363 | | |
364 | | // Any intervals which end after the query point and overlap the split point |
365 | | // must therefore contain the query point. |
366 | 579 | auto p = std::partition_point( |
367 | 579 | overlapping_by_desc_right_.cbegin(), overlapping_by_desc_right_.cend(), |
368 | 2.10k | [&](const interval_type& interval) { |
369 | 2.10k | return Traits::compare(Traits::get_right(interval), query) >= 0; |
370 | 2.10k | }); |
371 | 579 | results->insert(results->end(), overlapping_by_desc_right_.cbegin(), p); |
372 | 579 | } else { |
373 | 20 | DCHECK_EQ(cmp, 0); |
374 | | // The query is exactly our split point -- in this case we've already got |
375 | | // the computed list of overlapping intervals. |
376 | 20 | results->insert(results->end(), overlapping_by_asc_left_.begin(), |
377 | 20 | overlapping_by_asc_left_.end()); |
378 | 20 | } |
379 | 839 | } _ZNK5doris22interval_tree_internal6ITNodeINS_9IntTraitsEE19FindContainingPointIiEEvRKT_PSt6vectorINS_11IntIntervalESaIS9_EE Line | Count | Source | 342 | 839 | IntervalVector* results) const { | 343 | 839 | int cmp = Traits::compare(query, split_point_); | 344 | 839 | if (cmp < 0) { | 345 | | // None of the intervals in right_ may intersect this. | 346 | 240 | if (left_ != NULL) { | 347 | 199 | left_->FindContainingPoint(query, results); | 348 | 199 | } | 349 | | | 350 | | // Any intervals which start before the query point and overlap the split point | 351 | | // must therefore contain the query point. | 352 | 240 | auto p = std::partition_point( | 353 | 240 | overlapping_by_asc_left_.cbegin(), overlapping_by_asc_left_.cend(), | 354 | 240 | [&](const interval_type& interval) { | 355 | 240 | return Traits::compare(Traits::get_left(interval), query) <= 0; | 356 | 240 | }); | 357 | 240 | results->insert(results->end(), overlapping_by_asc_left_.cbegin(), p); | 358 | 599 | } else if (cmp > 0) { | 359 | | // None of the intervals in left_ may intersect this. | 360 | 579 | if (right_ != NULL) { | 361 | 431 | right_->FindContainingPoint(query, results); | 362 | 431 | } | 363 | | | 364 | | // Any intervals which end after the query point and overlap the split point | 365 | | // must therefore contain the query point. | 366 | 579 | auto p = std::partition_point( | 367 | 579 | overlapping_by_desc_right_.cbegin(), overlapping_by_desc_right_.cend(), | 368 | 579 | [&](const interval_type& interval) { | 369 | 579 | return Traits::compare(Traits::get_right(interval), query) >= 0; | 370 | 579 | }); | 371 | 579 | results->insert(results->end(), overlapping_by_desc_right_.cbegin(), p); | 372 | 579 | } else { | 373 | 20 | DCHECK_EQ(cmp, 0); | 374 | | // The query is exactly our split point -- in this case we've already got | 375 | | // the computed list of overlapping intervals. | 376 | 20 | results->insert(results->end(), overlapping_by_asc_left_.begin(), | 377 | 20 | overlapping_by_asc_left_.end()); | 378 | 20 | } | 379 | 839 | } |
Unexecuted instantiation: _ZNK5doris22interval_tree_internal6ITNodeINS_9IntTraitsEE19FindContainingPointINS_18CountingQueryPointEEEvRKT_PSt6vectorINS_11IntIntervalESaISA_EE |
380 | | |
381 | | template <class Traits> |
382 | | template <class QueryPointType> |
383 | | void ITNode<Traits>::FindIntersectingInterval(const QueryPointType& lower_bound, |
384 | | const QueryPointType& upper_bound, |
385 | 5.07k | IntervalVector* results) const { |
386 | 5.07k | if (Traits::compare(upper_bound, split_point_, POSITIVE_INFINITY) <= 0) { |
387 | | // The interval is fully left of the split point and with split point. |
388 | | // So, it may not overlap with any in 'right_' |
389 | 236 | if (left_ != NULL) { |
390 | 176 | left_->FindIntersectingInterval(lower_bound, upper_bound, results); |
391 | 176 | } |
392 | | |
393 | | // Any interval whose left edge is < the query interval's right edge |
394 | | // intersect the query interval. 'std::partition_point' returns the first |
395 | | // such interval which does not meet that criterion, so we insert all |
396 | | // up to that point. |
397 | 236 | auto first_greater = std::partition_point( |
398 | 236 | overlapping_by_asc_left_.cbegin(), overlapping_by_asc_left_.cend(), |
399 | 688 | [&](const interval_type& interval) { |
400 | 688 | return Traits::compare(Traits::get_left(interval), upper_bound, |
401 | 688 | POSITIVE_INFINITY) < 0; |
402 | 688 | }); |
403 | 236 | results->insert(results->end(), overlapping_by_asc_left_.cbegin(), first_greater); |
404 | 4.83k | } else if (Traits::compare(lower_bound, split_point_, NEGATIVE_INFINITY) > 0) { |
405 | | // The interval is fully right of the split point. So, it may not overlap |
406 | | // with any in 'left_'. |
407 | 564 | if (right_ != NULL) { |
408 | 384 | right_->FindIntersectingInterval(lower_bound, upper_bound, results); |
409 | 384 | } |
410 | | |
411 | | // Any interval whose right edge is >= the query interval's left edge |
412 | | // intersect the query interval. 'std::partition_point' returns the first |
413 | | // such interval which does not meet that criterion, so we insert all |
414 | | // up to that point. |
415 | 564 | auto first_lesser = std::partition_point( |
416 | 564 | overlapping_by_desc_right_.cbegin(), overlapping_by_desc_right_.cend(), |
417 | 1.81k | [&](const interval_type& interval) { |
418 | 1.81k | return Traits::compare(Traits::get_right(interval), lower_bound, |
419 | 1.81k | NEGATIVE_INFINITY) >= 0; |
420 | 1.81k | }); |
421 | 564 | results->insert(results->end(), overlapping_by_desc_right_.cbegin(), first_lesser); |
422 | 4.27k | } else { |
423 | | // The query interval contains the split point. Therefore all other intervals |
424 | | // which also contain the split point are intersecting. |
425 | 4.27k | results->insert(results->end(), overlapping_by_asc_left_.begin(), |
426 | 4.27k | overlapping_by_asc_left_.end()); |
427 | | |
428 | | // The query interval may _also_ intersect some in either child. |
429 | 4.27k | if (left_ != NULL) { |
430 | 2.34k | left_->FindIntersectingInterval(lower_bound, upper_bound, results); |
431 | 2.34k | } |
432 | 4.27k | if (right_ != NULL) { |
433 | 1.68k | right_->FindIntersectingInterval(lower_bound, upper_bound, results); |
434 | 1.68k | } |
435 | 4.27k | } |
436 | 5.07k | } |
437 | | |
438 | | } // namespace interval_tree_internal |
439 | | |
440 | | } // namespace doris |