|  | /* | 
|  | * Copyright (C) 2024 The Android Open Source Project | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  |  | 
|  | #ifndef SRC_TRACE_PROCESSOR_CONTAINERS_INTERVAL_TREE_H_ | 
|  | #define SRC_TRACE_PROCESSOR_CONTAINERS_INTERVAL_TREE_H_ | 
|  |  | 
|  | #include <cstdint> | 
|  | #include <limits> | 
|  | #include <memory> | 
|  | #include <vector> | 
|  |  | 
|  | namespace perfetto::trace_processor { | 
|  |  | 
|  | // An implementation of an interval tree data structure, designed to efficiently | 
|  | // perform overlap queries on a set of intervals. Used by `interval_intersect`, | 
|  | // where one set of intervals (generally the bigger one) has interval tree | 
|  | // created based on it, as another queries `FindOverlaps` function for each | 
|  | // interval. | 
|  | // As interval tree is build on sorted (by `start`) set of N intervals, the | 
|  | // complexity of creating a tree goes down from O(N*logN) to O(N) and the | 
|  | // created tree is optimally balanced. Each call to `FindOverlaps` is O(logN). | 
|  | class IntervalTree { | 
|  | public: | 
|  | struct Interval { | 
|  | uint32_t start; | 
|  | uint32_t end; | 
|  | uint32_t id; | 
|  | }; | 
|  |  | 
|  | // Takes vector of sorted intervals. | 
|  | explicit IntervalTree(std::vector<Interval>& sorted_intervals) { | 
|  | tree_root_ = BuildFromSortedIntervals( | 
|  | sorted_intervals, 0, static_cast<int32_t>(sorted_intervals.size() - 1)); | 
|  | } | 
|  |  | 
|  | // Modifies |overlaps| to contain ids of all intervals in the interval tree | 
|  | // that overlap with |interval|. | 
|  | void FindOverlaps(Interval interval, std::vector<uint32_t>& overlaps) const { | 
|  | if (tree_root_) { | 
|  | FindOverlaps(*tree_root_, interval, overlaps); | 
|  | } | 
|  | } | 
|  |  | 
|  | private: | 
|  | struct Node { | 
|  | Interval interval; | 
|  | uint32_t max; | 
|  | std::unique_ptr<Node> left; | 
|  | std::unique_ptr<Node> right; | 
|  |  | 
|  | explicit Node(Interval i) : interval(i), max(i.end) {} | 
|  | }; | 
|  |  | 
|  | static std::unique_ptr<Node> Insert(std::unique_ptr<Node> root, Interval i) { | 
|  | if (root == nullptr) { | 
|  | return std::make_unique<Node>(i); | 
|  | } | 
|  |  | 
|  | if (i.start < root->interval.start) { | 
|  | root->left = Insert(std::move(root->left), i); | 
|  | } else { | 
|  | root->right = Insert(std::move(root->right), i); | 
|  | } | 
|  |  | 
|  | if (root->max < i.end) { | 
|  | root->max = i.end; | 
|  | } | 
|  |  | 
|  | return root; | 
|  | } | 
|  |  | 
|  | static std::unique_ptr<Node> BuildFromSortedIntervals( | 
|  | const std::vector<Interval>& is, | 
|  | int32_t start, | 
|  | int32_t end) { | 
|  | // |start == end| happens if there is one element so we need to check for | 
|  | // |start > end| that happens in the next recursive call. | 
|  | if (start > end) { | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | int32_t mid = start + (end - start) / 2; | 
|  | auto node = std::make_unique<Node>(is[static_cast<uint32_t>(mid)]); | 
|  |  | 
|  | node->left = BuildFromSortedIntervals(is, start, mid - 1); | 
|  | node->right = BuildFromSortedIntervals(is, mid + 1, end); | 
|  |  | 
|  | uint32_t max_from_children = std::max( | 
|  | node->left ? node->left->max : std::numeric_limits<uint32_t>::min(), | 
|  | node->right ? node->right->max : std::numeric_limits<uint32_t>::min()); | 
|  |  | 
|  | node->max = std::max(node->interval.end, max_from_children); | 
|  |  | 
|  | return node; | 
|  | } | 
|  |  | 
|  | static void FindOverlaps(const Node& node, | 
|  | const Interval& i, | 
|  | std::vector<uint32_t>& overlaps) { | 
|  | // Intervals overlap if one starts before the other ends and ends after it | 
|  | // starts. | 
|  | if (node.interval.start < i.end && node.interval.end > i.start) { | 
|  | overlaps.push_back(node.interval.id); | 
|  | } | 
|  |  | 
|  | // Try to find overlaps with left. | 
|  | if (i.start <= node.interval.start && node.left) { | 
|  | FindOverlaps(*node.left, i, overlaps); | 
|  | } | 
|  |  | 
|  | // Try to find overlaps with right. | 
|  | if (i.start < node.max && node.right) { | 
|  | FindOverlaps(*node.right, i, overlaps); | 
|  | } | 
|  | } | 
|  |  | 
|  | std::unique_ptr<Node> tree_root_; | 
|  | }; | 
|  |  | 
|  | }  // namespace perfetto::trace_processor | 
|  |  | 
|  | #endif  // SRC_TRACE_PROCESSOR_CONTAINERS_INTERVAL_TREE_H_ |