simd_intervaltree/
mutable.rs

1//! Mutable interval collection with stable identifiers.
2//!
3//! This module provides a dynamic interval collection that supports
4//! insertion and removal while returning stable identifiers that can
5//! be used to map to external resources.
6
7use alloc::vec::Vec;
8
9use crate::builder::IntervalTreeBuilder;
10use crate::tree::IntervalTree;
11use crate::Interval;
12
13/// A stable identifier for an interval in the collection.
14///
15/// These identifiers remain valid across insertions and removals,
16/// making them suitable for mapping to external resources.
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
18pub struct IntervalId(u64);
19
20impl IntervalId {
21    /// Returns the raw identifier value.
22    #[inline]
23    #[must_use]
24    pub fn as_u64(self) -> u64 {
25        self.0
26    }
27}
28
29/// Entry in the mutable collection.
30#[derive(Debug, Clone)]
31struct Entry<T, V> {
32    interval: Interval<T>,
33    value: V,
34    generation: u32,
35}
36
37/// A mutable interval collection with stable identifiers.
38///
39/// Unlike [`IntervalTree`], this collection supports dynamic insertion
40/// and removal. Each inserted interval receives a stable [`IntervalId`]
41/// that remains valid until the interval is removed.
42///
43/// Internally maintains a pending buffer that gets merged into an
44/// optimized tree structure on query.
45///
46/// # Example
47///
48/// ```
49/// use simd_intervaltree::IntervalSet;
50///
51/// let mut set = IntervalSet::new();
52///
53/// // Insert returns stable IDs
54/// let id1 = set.insert(0..10, "first");
55/// let id2 = set.insert(5..15, "second");
56///
57/// // Query overlapping intervals with IDs
58/// for (id, interval, value) in set.query(3..12) {
59///     println!("{id:?}: {interval:?} => {value}");
60/// }
61///
62/// // Remove by ID
63/// set.remove(id1);
64/// ```
65#[derive(Debug, Clone)]
66pub struct IntervalSet<T, V> {
67    /// Active entries indexed by slot.
68    entries: Vec<Option<Entry<T, V>>>,
69    /// Free slot indices for reuse.
70    free_slots: Vec<usize>,
71    /// Next generation counter for ID uniqueness.
72    next_generation: u32,
73    /// Count of active intervals.
74    count: usize,
75    /// Cached tree storing slot indices (invalidated on mutation).
76    cached_tree: Option<IntervalTree<T, usize>>,
77}
78
79impl<T, V> Default for IntervalSet<T, V> {
80    fn default() -> Self {
81        Self::new()
82    }
83}
84
85impl<T, V> IntervalSet<T, V> {
86    /// Creates a new empty interval set.
87    #[must_use]
88    pub fn new() -> Self {
89        Self {
90            entries: Vec::new(),
91            free_slots: Vec::new(),
92            next_generation: 0,
93            count: 0,
94            cached_tree: None,
95        }
96    }
97
98    /// Creates a new interval set with the specified capacity.
99    #[must_use]
100    pub fn with_capacity(capacity: usize) -> Self {
101        Self {
102            entries: Vec::with_capacity(capacity),
103            free_slots: Vec::new(),
104            next_generation: 0,
105            count: 0,
106            cached_tree: None,
107        }
108    }
109
110    /// Returns the number of intervals in the set.
111    #[inline]
112    #[must_use]
113    pub fn len(&self) -> usize {
114        self.count
115    }
116
117    /// Returns true if the set is empty.
118    #[inline]
119    #[must_use]
120    pub fn is_empty(&self) -> bool {
121        self.count == 0
122    }
123
124    /// Clears all intervals from the set.
125    pub fn clear(&mut self) {
126        self.entries.clear();
127        self.free_slots.clear();
128        self.count = 0;
129        self.cached_tree = None;
130    }
131}
132
133impl<T: Ord + Copy, V> IntervalSet<T, V> {
134    /// Inserts an interval with its associated value.
135    ///
136    /// Returns a stable [`IntervalId`] that can be used for removal
137    /// or mapping to external resources.
138    pub fn insert<R: Into<Interval<T>>>(&mut self, range: R, value: V) -> IntervalId {
139        let interval = range.into();
140        let generation = self.next_generation;
141        self.next_generation = self.next_generation.wrapping_add(1);
142
143        let entry = Entry {
144            interval,
145            value,
146            generation,
147        };
148
149        let slot = if let Some(slot) = self.free_slots.pop() {
150            self.entries[slot] = Some(entry);
151            slot
152        } else {
153            let slot = self.entries.len();
154            self.entries.push(Some(entry));
155            slot
156        };
157
158        self.count += 1;
159        self.cached_tree = None; // Invalidate cache
160
161        // Encode slot and generation into ID
162        IntervalId(((generation as u64) << 32) | (slot as u64))
163    }
164
165    /// Removes an interval by its ID.
166    ///
167    /// Returns `true` if the interval was found and removed.
168    pub fn remove(&mut self, id: IntervalId) -> bool {
169        let slot = (id.0 & 0xFFFF_FFFF) as usize;
170        let generation = (id.0 >> 32) as u32;
171
172        if slot >= self.entries.len() {
173            return false;
174        }
175
176        if let Some(entry) = &self.entries[slot] {
177            if entry.generation == generation {
178                self.entries[slot] = None;
179                self.free_slots.push(slot);
180                self.count -= 1;
181                self.cached_tree = None; // Invalidate cache
182                return true;
183            }
184        }
185
186        false
187    }
188
189    /// Returns the value associated with an interval ID, if it exists.
190    #[must_use]
191    pub fn get(&self, id: IntervalId) -> Option<&V> {
192        let slot = (id.0 & 0xFFFF_FFFF) as usize;
193        let generation = (id.0 >> 32) as u32;
194
195        self.entries.get(slot).and_then(|e| {
196            e.as_ref()
197                .filter(|entry| entry.generation == generation)
198                .map(|entry| &entry.value)
199        })
200    }
201
202    /// Returns the interval associated with an ID, if it exists.
203    #[must_use]
204    pub fn get_interval(&self, id: IntervalId) -> Option<Interval<T>> {
205        let slot = (id.0 & 0xFFFF_FFFF) as usize;
206        let generation = (id.0 >> 32) as u32;
207
208        self.entries.get(slot).and_then(|e| {
209            e.as_ref()
210                .filter(|entry| entry.generation == generation)
211                .map(|entry| entry.interval)
212        })
213    }
214
215    /// Rebuilds the internal tree if needed.
216    fn ensure_tree(&mut self) {
217        if self.cached_tree.is_some() {
218            return;
219        }
220
221        let mut builder = IntervalTreeBuilder::with_capacity(self.count);
222
223        for (slot, entry) in self.entries.iter().enumerate() {
224            if let Some(e) = entry {
225                builder = builder.insert(e.interval, slot);
226            }
227        }
228
229        self.cached_tree = Some(builder.build());
230    }
231
232    /// Queries for all intervals overlapping the given range.
233    ///
234    /// Returns an iterator yielding `(IntervalId, Interval<T>, &V)` tuples.
235    /// This may trigger an internal rebuild if the collection has been modified.
236    pub fn query<R: Into<Interval<T>>>(
237        &mut self,
238        range: R,
239    ) -> impl Iterator<Item = (IntervalId, Interval<T>, &V)> {
240        self.ensure_tree();
241        let entries = &self.entries;
242        self.cached_tree
243            .as_ref()
244            .unwrap()
245            .query(range)
246            .filter_map(move |entry| {
247                let slot = *entry.value;
248                entries.get(slot).and_then(|e| {
249                    e.as_ref().map(|ent| {
250                        let id = IntervalId(((ent.generation as u64) << 32) | (slot as u64));
251                        (id, ent.interval, &ent.value)
252                    })
253                })
254            })
255    }
256
257    /// Returns an iterator over all intervals and their IDs.
258    pub fn iter(&self) -> impl Iterator<Item = (IntervalId, Interval<T>, &V)> {
259        self.entries.iter().enumerate().filter_map(|(slot, entry)| {
260            entry.as_ref().map(|e| {
261                let id = IntervalId(((e.generation as u64) << 32) | (slot as u64));
262                (id, e.interval, &e.value)
263            })
264        })
265    }
266}
267
268#[cfg(test)]
269mod tests {
270    use super::*;
271
272    #[test]
273    fn insert_and_query() {
274        let mut set = IntervalSet::new();
275
276        let id1 = set.insert(0..10, "first");
277        let id2 = set.insert(5..15, "second");
278        let _id3 = set.insert(20..30, "third");
279
280        assert_eq!(set.len(), 3);
281
282        let results: Vec<_> = set.query(3..12).collect();
283        assert_eq!(results.len(), 2);
284
285        // Verify IDs are returned with query results
286        let ids: Vec<_> = results.iter().map(|(id, _, _)| *id).collect();
287        assert!(ids.contains(&id1) || ids.contains(&id2));
288
289        assert_eq!(set.get(id1), Some(&"first"));
290        assert_eq!(set.get(id2), Some(&"second"));
291    }
292
293    #[test]
294    fn remove_by_id() {
295        let mut set = IntervalSet::new();
296
297        let id1 = set.insert(0..10, "first");
298        let id2 = set.insert(5..15, "second");
299
300        assert!(set.remove(id1));
301        assert_eq!(set.len(), 1);
302        assert_eq!(set.get(id1), None);
303        assert_eq!(set.get(id2), Some(&"second"));
304
305        // Double remove returns false
306        assert!(!set.remove(id1));
307    }
308
309    #[test]
310    fn slot_reuse() {
311        let mut set = IntervalSet::new();
312
313        let id1 = set.insert(0..10, "first");
314        set.remove(id1);
315
316        let id2 = set.insert(20..30, "second");
317
318        // Same slot, different generation - old ID invalid
319        assert_eq!(set.get(id1), None);
320        assert_eq!(set.get(id2), Some(&"second"));
321    }
322
323    #[test]
324    fn iter_all() {
325        let mut set: IntervalSet<i32, &str> = IntervalSet::new();
326
327        set.insert(0..10, "a");
328        set.insert(5..15, "b");
329        set.insert(20..30, "c");
330
331        let items: Vec<_> = set.iter().collect();
332        assert_eq!(items.len(), 3);
333    }
334
335    #[test]
336    fn query_returns_ids() {
337        let mut set = IntervalSet::new();
338
339        let id1 = set.insert(0..10, "first");
340        let _id2 = set.insert(100..200, "second");
341
342        let results: Vec<_> = set.query(5..8).collect();
343        assert_eq!(results.len(), 1);
344
345        let (returned_id, interval, value) = &results[0];
346        assert_eq!(*returned_id, id1);
347        assert_eq!(interval.start, 0);
348        assert_eq!(interval.end, 10);
349        assert_eq!(*value, &"first");
350    }
351}