simd_intervaltree/query.rs
1//! Query iterators for zero-allocation traversal.
2
3use crate::tree::{IntervalTree, Node};
4use crate::Interval;
5
6/// An entry returned by query iteration.
7#[derive(Debug, Clone, Copy)]
8pub struct QueryEntry<'a, T, V> {
9 /// The interval.
10 pub interval: Interval<T>,
11 /// Reference to the associated value.
12 pub value: &'a V,
13}
14
15/// Iterator over intervals overlapping a query range.
16///
17/// This iterator does not allocate. It maintains a stack on the stack
18/// for tree traversal (bounded by tree depth).
19pub struct QueryIter<'a, T, V> {
20 tree: &'a IntervalTree<T, V>,
21 query: Interval<T>,
22 /// Stack of (node_index, phase) for traversal.
23 /// Phase: 0 = process node, 1 = process right child
24 stack: [(usize, u8); 64], // Max depth of 64 should be plenty
25 stack_len: usize,
26 /// Current position within a node's interval list.
27 current_node: usize,
28 current_pos: usize,
29 current_end: usize,
30 /// Which list we're iterating: 0 = by_start (data array), 1 = by_end (indirect)
31 current_list: u8,
32}
33
34impl<'a, T: Ord + Copy, V> QueryIter<'a, T, V> {
35 pub(crate) fn new(tree: &'a IntervalTree<T, V>, query: Interval<T>) -> Self {
36 let mut iter = Self {
37 tree,
38 query,
39 stack: [(0, 0); 64],
40 stack_len: 0,
41 current_node: Node::NULL,
42 current_pos: 0,
43 current_end: 0,
44 current_list: 0,
45 };
46
47 if !tree.nodes.is_empty() {
48 iter.stack[0] = (0, 0);
49 iter.stack_len = 1;
50 }
51
52 iter
53 }
54
55 fn advance_to_next(&mut self) -> Option<QueryEntry<'a, T, V>> {
56 loop {
57 // First, try to yield from current node's interval list
58 while self.current_pos < self.current_end {
59 let pos = self.current_pos;
60 self.current_pos += 1;
61
62 // Get the actual index
63 let idx = if self.current_list == 0 {
64 // Direct access - data is contiguous per node
65 pos
66 } else {
67 // Indirect access through by_end_indices
68 self.tree.by_end_indices[pos]
69 };
70
71 let start = self.tree.starts[idx];
72 let end = self.tree.ends[idx];
73
74 // Check early termination based on which list we're in
75 if self.current_list == 0 {
76 // Sorted by start ascending
77 if start >= self.query.end {
78 self.current_pos = self.current_end; // Skip rest
79 break;
80 }
81 } else {
82 // Sorted by end descending
83 if end <= self.query.start {
84 self.current_pos = self.current_end; // Skip rest
85 break;
86 }
87 }
88
89 // This interval overlaps
90 return Some(QueryEntry {
91 interval: Interval { start, end },
92 value: &self.tree.values[idx],
93 });
94 }
95
96 // Pop from stack
97 if self.stack_len == 0 {
98 return None;
99 }
100
101 self.stack_len -= 1;
102 let (node_idx, phase) = self.stack[self.stack_len];
103
104 if node_idx >= self.tree.nodes.len() {
105 continue;
106 }
107
108 let node = &self.tree.nodes[node_idx];
109 let pivot = self.tree.starts[node.pivot_idx];
110
111 match phase {
112 0 => {
113 // Determine which case we're in
114 if self.query.start <= pivot && pivot < self.query.end {
115 // Case 1: Query contains pivot - yield all, search both
116 self.current_node = node_idx;
117 self.current_pos = node.data_begin;
118 self.current_end = node.data_end;
119 self.current_list = 0;
120
121 // Push children for later
122 if node.has_right() {
123 self.stack[self.stack_len] = (node.right, 0);
124 self.stack_len += 1;
125 }
126 if node.has_left() {
127 self.stack[self.stack_len] = (node.left, 0);
128 self.stack_len += 1;
129 }
130 } else if pivot < self.query.start {
131 // Case 2: Pivot left of query - scan by end, go right
132 self.current_node = node_idx;
133 self.current_pos = node.by_end_begin;
134 self.current_end = node.by_end_end;
135 self.current_list = 1;
136
137 if node.has_right() {
138 self.stack[self.stack_len] = (node.right, 0);
139 self.stack_len += 1;
140 }
141 } else {
142 // Case 3: Pivot right of query - scan by start, go left
143 self.current_node = node_idx;
144 self.current_pos = node.data_begin;
145 self.current_end = node.data_end;
146 self.current_list = 0;
147
148 if node.has_left() {
149 self.stack[self.stack_len] = (node.left, 0);
150 self.stack_len += 1;
151 }
152 }
153 }
154 _ => continue,
155 }
156 }
157 }
158}
159
160impl<'a, T: Ord + Copy, V> Iterator for QueryIter<'a, T, V> {
161 type Item = QueryEntry<'a, T, V>;
162
163 fn next(&mut self) -> Option<Self::Item> {
164 self.advance_to_next()
165 }
166}