blob: c083da053ad47973db9437aebe7bb87372167b30 [file] [log] [blame]
/*
* 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_