Coverage Report

Created: 2024-11-21 16:04

/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
4.20k
bool LessThan(const typename Traits::point_type& a, const typename Traits::point_type& b) {
74
4.20k
    return Traits::compare(a, b) < 0;
75
4.20k
}
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
29
                                     IntervalVector* right) {
99
29
    CHECK(!in.empty());
100
101
    // Pick a split point which is the median of all of the interval boundaries.
102
29
    std::vector<point_type> endpoints;
103
29
    endpoints.reserve(in.size() * 2);
104
325
    for (const interval_type& interval : in) {
105
325
        endpoints.push_back(Traits::get_left(interval));
106
325
        endpoints.push_back(Traits::get_right(interval));
107
325
    }
108
29
    std::sort(endpoints.begin(), endpoints.end(), LessThan<Traits>);
109
29
    *split_point = endpoints[endpoints.size() / 2];
110
111
    // Partition into the groups based on the determined split point.
112
325
    for (const interval_type& interval : in) {
113
325
        if (Traits::compare(Traits::get_right(interval), *split_point) < 0) {
114
            //                 | split point
115
            // |------------|  |
116
            //    interval
117
112
            left->push_back(interval);
118
213
        } else if (Traits::compare(Traits::get_left(interval), *split_point) > 0) {
119
            //                 | split point
120
            //                 |    |------------|
121
            //                         interval
122
100
            right->push_back(interval);
123
113
        } else {
124
            //                 | split point
125
            //                 |
126
            //          |------------|
127
            //             interval
128
113
            overlapping->push_back(interval);
129
113
        }
130
325
    }
131
29
}
132
133
template <class Traits>
134
typename IntervalTree<Traits>::node_type* IntervalTree<Traits>::CreateNode(
135
29
        const IntervalVector& intervals) {
136
29
    IntervalVector left, right, overlap;
137
29
    point_type split_point;
138
139
    // First partition the input intervals and select a split point
140
29
    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
29
    node_type* left_node = !left.empty() ? CreateNode(left) : NULL;
145
29
    node_type* right_node = !right.empty() ? CreateNode(right) : NULL;
146
147
29
    return new node_type(split_point, left_node, overlap, right_node);
148
29
}
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
281
bool ITNode<Traits>::SortByAscLeft(const interval_type& a, const interval_type& b) {
207
281
    return Traits::compare(Traits::get_left(a), Traits::get_left(b)) < 0;
208
281
}
209
210
template <class Traits>
211
259
bool ITNode<Traits>::SortByDescRight(const interval_type& a, const interval_type& b) {
212
259
    return Traits::compare(Traits::get_right(a), Traits::get_right(b)) > 0;
213
259
}
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
29
        : 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
29
    overlapping_by_asc_left_.assign(overlap.begin(), overlap.end());
222
29
    std::sort(overlapping_by_asc_left_.begin(), overlapping_by_asc_left_.end(), SortByAscLeft);
223
    // 2) Sorted by descending right boundary
224
29
    overlapping_by_desc_right_.assign(overlap.begin(), overlap.end());
225
29
    std::sort(overlapping_by_desc_right_.begin(), overlapping_by_desc_right_.end(),
226
29
              SortByDescRight);
227
29
}
228
229
template <class Traits>
230
29
ITNode<Traits>::~ITNode() {
231
29
    if (left_) delete left_;
232
29
    if (right_) delete right_;
233
29
}
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
5
    for (const interval_type& interval : overlapping_by_asc_left_) {
278
5
        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
5
        auto first_match = std::partition_point(
287
5
                rem_queries, partition_point, [&](const QueryPointType& query_point) {
288
2
                    return Traits::compare(query_point, interval_left) < 0;
289
2
                });
290
5
        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
5
        rem_queries = std::move(first_match);
298
5
    }
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
5
    for (const interval_type& interval : overlapping_by_desc_right_) {
315
5
        const auto& interval_right = Traits::get_right(interval);
316
        // Find the first query point which is > the right side of the interval.
317
5
        auto first_non_match = std::partition_point(
318
5
                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
0
            cb(*it, interval);
323
0
        }
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
5
        rem_queries = std::move(first_non_match);
328
5
    }
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
5
    for (const interval_type& interval : overlapping_by_asc_left_) {
278
5
        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
5
        auto first_match = std::partition_point(
287
5
                rem_queries, partition_point, [&](const QueryPointType& query_point) {
288
5
                    return Traits::compare(query_point, interval_left) < 0;
289
5
                });
290
5
        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
5
        rem_queries = std::move(first_match);
298
5
    }
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
5
    for (const interval_type& interval : overlapping_by_desc_right_) {
315
5
        const auto& interval_right = Traits::get_right(interval);
316
        // Find the first query point which is > the right side of the interval.
317
5
        auto first_non_match = std::partition_point(
318
5
                partition_point, rem_queries, [&](const QueryPointType& query_point) {
319
5
                    return Traits::compare(query_point, interval_right) <= 0;
320
5
                });
321
5
        for (auto it = partition_point; it != first_non_match; ++it) {
322
0
            cb(*it, interval);
323
0
        }
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
5
        rem_queries = std::move(first_non_match);
328
5
    }
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
846
                                         IntervalVector* results) const {
343
846
    int cmp = Traits::compare(query, split_point_);
344
846
    if (cmp < 0) {
345
        // None of the intervals in right_ may intersect this.
346
266
        if (left_ != NULL) {
347
215
            left_->FindContainingPoint(query, results);
348
215
        }
349
350
        // Any intervals which start before the query point and overlap the split point
351
        // must therefore contain the query point.
352
266
        auto p = std::partition_point(
353
266
                overlapping_by_asc_left_.cbegin(), overlapping_by_asc_left_.cend(),
354
780
                [&](const interval_type& interval) {
355
780
                    return Traits::compare(Traits::get_left(interval), query) <= 0;
356
780
                });
357
266
        results->insert(results->end(), overlapping_by_asc_left_.cbegin(), p);
358
580
    } else if (cmp > 0) {
359
        // None of the intervals in left_ may intersect this.
360
558
        if (right_ != NULL) {
361
422
            right_->FindContainingPoint(query, results);
362
422
        }
363
364
        // Any intervals which end after the query point and overlap the split point
365
        // must therefore contain the query point.
366
558
        auto p = std::partition_point(
367
558
                overlapping_by_desc_right_.cbegin(), overlapping_by_desc_right_.cend(),
368
1.77k
                [&](const interval_type& interval) {
369
1.77k
                    return Traits::compare(Traits::get_right(interval), query) >= 0;
370
1.77k
                });
371
558
        results->insert(results->end(), overlapping_by_desc_right_.cbegin(), p);
372
558
    } else {
373
22
        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
22
        results->insert(results->end(), overlapping_by_asc_left_.begin(),
377
22
                        overlapping_by_asc_left_.end());
378
22
    }
379
846
}
_ZNK5doris22interval_tree_internal6ITNodeINS_9IntTraitsEE19FindContainingPointIiEEvRKT_PSt6vectorINS_11IntIntervalESaIS9_EE
Line
Count
Source
342
846
                                         IntervalVector* results) const {
343
846
    int cmp = Traits::compare(query, split_point_);
344
846
    if (cmp < 0) {
345
        // None of the intervals in right_ may intersect this.
346
266
        if (left_ != NULL) {
347
215
            left_->FindContainingPoint(query, results);
348
215
        }
349
350
        // Any intervals which start before the query point and overlap the split point
351
        // must therefore contain the query point.
352
266
        auto p = std::partition_point(
353
266
                overlapping_by_asc_left_.cbegin(), overlapping_by_asc_left_.cend(),
354
266
                [&](const interval_type& interval) {
355
266
                    return Traits::compare(Traits::get_left(interval), query) <= 0;
356
266
                });
357
266
        results->insert(results->end(), overlapping_by_asc_left_.cbegin(), p);
358
580
    } else if (cmp > 0) {
359
        // None of the intervals in left_ may intersect this.
360
558
        if (right_ != NULL) {
361
422
            right_->FindContainingPoint(query, results);
362
422
        }
363
364
        // Any intervals which end after the query point and overlap the split point
365
        // must therefore contain the query point.
366
558
        auto p = std::partition_point(
367
558
                overlapping_by_desc_right_.cbegin(), overlapping_by_desc_right_.cend(),
368
558
                [&](const interval_type& interval) {
369
558
                    return Traits::compare(Traits::get_right(interval), query) >= 0;
370
558
                });
371
558
        results->insert(results->end(), overlapping_by_desc_right_.cbegin(), p);
372
558
    } else {
373
22
        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
22
        results->insert(results->end(), overlapping_by_asc_left_.begin(),
377
22
                        overlapping_by_asc_left_.end());
378
22
    }
379
846
}
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.18k
                                              IntervalVector* results) const {
386
5.18k
    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
256
        if (left_ != NULL) {
390
200
            left_->FindIntersectingInterval(lower_bound, upper_bound, results);
391
200
        }
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
256
        auto first_greater = std::partition_point(
398
256
                overlapping_by_asc_left_.cbegin(), overlapping_by_asc_left_.cend(),
399
714
                [&](const interval_type& interval) {
400
714
                    return Traits::compare(Traits::get_left(interval), upper_bound,
401
714
                                           POSITIVE_INFINITY) < 0;
402
714
                });
403
256
        results->insert(results->end(), overlapping_by_asc_left_.cbegin(), first_greater);
404
4.93k
    } 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
627
        if (right_ != NULL) {
408
420
            right_->FindIntersectingInterval(lower_bound, upper_bound, results);
409
420
        }
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
627
        auto first_lesser = std::partition_point(
416
627
                overlapping_by_desc_right_.cbegin(), overlapping_by_desc_right_.cend(),
417
1.78k
                [&](const interval_type& interval) {
418
1.78k
                    return Traits::compare(Traits::get_right(interval), lower_bound,
419
1.78k
                                           NEGATIVE_INFINITY) >= 0;
420
1.78k
                });
421
627
        results->insert(results->end(), overlapping_by_desc_right_.cbegin(), first_lesser);
422
4.30k
    } else {
423
        // The query interval contains the split point. Therefore all other intervals
424
        // which also contain the split point are intersecting.
425
4.30k
        results->insert(results->end(), overlapping_by_asc_left_.begin(),
426
4.30k
                        overlapping_by_asc_left_.end());
427
428
        // The query interval may _also_ intersect some in either child.
429
4.30k
        if (left_ != NULL) {
430
2.33k
            left_->FindIntersectingInterval(lower_bound, upper_bound, results);
431
2.33k
        }
432
4.30k
        if (right_ != NULL) {
433
1.74k
            right_->FindIntersectingInterval(lower_bound, upper_bound, results);
434
1.74k
        }
435
4.30k
    }
436
5.18k
}
437
438
} // namespace interval_tree_internal
439
440
} // namespace doris