36 bool afterBegin = (line > beginLine) ||
37 (line == beginLine && column >= beginColumn);
40 bool beforeEnd = (line < endLine) || (line == endLine && column <= endColumn);
42 return afterBegin && beforeEnd;
46 if (beginLine != other.beginLine) {
47 return beginLine < other.beginLine;
49 return beginColumn < other.beginColumn;
56IntervalTree::SourcePoint IntervalTree::beginPoint(
const Interval &interval) {
57 return {interval.beginLine, interval.beginColumn};
60IntervalTree::SourcePoint IntervalTree::endPoint(
const Interval &interval) {
61 return {interval.endLine, interval.endColumn};
64bool IntervalTree::pointLess(SourcePoint lhs, SourcePoint rhs) {
65 if (lhs.line != rhs.line) {
66 return lhs.line < rhs.line;
68 return lhs.column < rhs.column;
71bool IntervalTree::startsAfter(
const Interval &interval, SourcePoint point) {
72 return pointLess(point, beginPoint(interval));
75bool IntervalTree::endsBefore(
const Interval &interval, SourcePoint point) {
76 return pointLess(endPoint(interval), point);
79bool IntervalTree::intervalEndGreater(
const Interval &lhs,
81 SourcePoint lhsEnd = endPoint(lhs);
82 SourcePoint rhsEnd = endPoint(rhs);
83 if (lhsEnd.line != rhsEnd.line) {
84 return lhsEnd.line > rhsEnd.line;
86 if (lhsEnd.column != rhsEnd.column) {
87 return lhsEnd.column > rhsEnd.column;
89 return pointLess(beginPoint(rhs), beginPoint(lhs));
93 intervals_.push_back(interval);
102 std::sort(intervals_.begin(), intervals_.end());
103 queryRoot_ = buildQueryTree(intervals_);
108 unsigned column)
const {
109 std::vector<AstViewNode *> results;
111 queryPoint(queryRoot_.get(), SourcePoint{line, column}, results);
114 std::sort(results.begin(), results.end(),
116 return getDepth(a) > getDepth(b);
122std::unique_ptr<IntervalTree::QueryNode>
123IntervalTree::buildQueryTree(std::vector<Interval> intervals) {
124 if (intervals.empty()) {
128 SourcePoint center = beginPoint(intervals[intervals.size() / 2]);
129 std::vector<Interval> left;
130 std::vector<Interval> right;
131 std::vector<Interval> crossing;
132 left.reserve(intervals.size() / 2);
133 right.reserve(intervals.size() / 2);
134 crossing.reserve(intervals.size());
136 for (
const Interval &interval : intervals) {
137 if (endsBefore(interval, center)) {
138 left.push_back(interval);
139 }
else if (startsAfter(interval, center)) {
140 right.push_back(interval);
142 crossing.push_back(interval);
146 auto node = std::make_unique<QueryNode>();
147 node->center = center;
148 node->byBegin = std::move(crossing);
149 node->byEndDescending = node->byBegin;
150 std::sort(node->byEndDescending.begin(), node->byEndDescending.end(),
152 node->left = buildQueryTree(std::move(left));
153 node->right = buildQueryTree(std::move(right));
157void IntervalTree::queryPoint(
const QueryNode *node, SourcePoint point,
158 std::vector<AstViewNode *> &results) {
163 if (pointLess(point, node->center)) {
164 for (
const Interval &interval : node->byBegin) {
165 if (startsAfter(interval, point)) {
168 results.push_back(interval.node);
170 queryPoint(node->left.get(), point, results);
174 if (pointLess(node->center, point)) {
175 for (
const Interval &interval : node->byEndDescending) {
176 if (endsBefore(interval, point)) {
179 results.push_back(interval.node);
181 queryPoint(node->right.get(), point, results);
185 for (
const Interval &interval : node->byBegin) {
186 results.push_back(interval.node);
191 unsigned beginColumn,
193 unsigned endColumn)
const {
195 Interval searchKey{beginLine, beginColumn, 0, 0,
nullptr};
196 auto it = std::lower_bound(intervals_.begin(), intervals_.end(), searchKey);
198 for (; it != intervals_.end(); ++it) {
200 if (it->beginLine > endLine ||
201 (it->beginLine == endLine && it->beginColumn > endColumn)) {
206 bool startsInRange = it->beginLine > beginLine ||
207 (it->beginLine == beginLine && it->beginColumn >= beginColumn);
208 bool endsInRange = it->endLine < endLine ||
209 (it->endLine == endLine && it->endColumn <= endColumn);
211 if (startsInRange && endsInRange) {
219unsigned IntervalTree::getDepth(
AstViewNode *node)
const {
225 AstViewNode *current = node;
226 while (current->getParent()) {
228 current = current->getParent();
243 FileID fileId = range.begin().fileID();
250 bool endsBeforeStart =
251 range.end().line() < range.begin().line() ||
252 (range.end().line() == range.begin().line() &&
253 range.end().column() < range.begin().column());
254 if (endsBeforeStart) {
259 Interval interval{range.begin().line(), range.begin().column(),
260 range.end().line(), range.end().column(), node};
263 trees_[fileId].insert(interval);
268 for (
auto &[fileId, tree] : trees_) {
275 unsigned column)
const {
276 auto it = trees_.find(fileId);
277 if (it == trees_.end()) {
281 return it->second.query(line, column);
285 FileID fileId,
unsigned beginLine,
unsigned beginColumn,
unsigned endLine,
286 unsigned endColumn)
const {
287 auto it = trees_.find(fileId);
288 if (it == trees_.end()) {
292 return it->second.queryFirstContained(beginLine, beginColumn, endLine,
297 std::size_t total = 0;
298 for (
const auto &[fileId, tree] : trees_) {
299 total += tree.size();
305 return trees_.find(fileId) != trees_.end();
AST data structures and memory management.
std::size_t FileID
Type-safe identifier for registered files. 0 is reserved for invalid.
Source-to-AST node lookup index.
Represents node in AST tree hierarchy.
const SourceRange & getSourceRange() const
Get source range (delegates to data node).
static constexpr FileID InvalidFileID
Reserved invalid FileID.
AstViewNode * queryFirstContained(unsigned beginLine, unsigned beginColumn, unsigned endLine, unsigned endColumn) const
Find first interval fully contained within a range.
void finalize()
Sort intervals by start position (call once after all inserts).
std::vector< AstViewNode * > query(unsigned line, unsigned column) const
Find all intervals containing a point.
void insert(Interval interval)
Add interval to collection (not sorted yet).
void finalize()
Finalize all interval trees (call after all nodes added).
void addNode(AstViewNode *node)
Add node to index.
std::vector< AstViewNode * > getNodesAt(FileID fileId, unsigned line, unsigned column) const
Query nodes at specific source position.
bool hasFile(FileID fileId) const
Check whether the current TU AST contains any indexed nodes for a file.
std::size_t getTotalIntervals() const
Get total number of intervals across all files.
AstViewNode * getFirstNodeContainedInRange(FileID fileId, unsigned beginLine, unsigned beginColumn, unsigned endLine, unsigned endColumn) const
Query first node fully contained within a range.
Represents a span of source code (begin to end).
Represents an interval in source code with associated AST node.
bool operator<(const Interval &other) const
Compare intervals by start position for sorting.
bool contains(unsigned line, unsigned column) const
Check if interval contains a point.