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}