ruvector_graph/optimization/
adaptive_radix.rs

1//! Adaptive Radix Tree (ART) for property indexes
2//!
3//! ART provides space-efficient indexing with excellent cache performance
4//! through adaptive node sizes and path compression.
5
6use std::cmp::Ordering;
7use std::mem;
8
9/// Adaptive Radix Tree for property indexing
10pub struct AdaptiveRadixTree<V: Clone> {
11    root: Option<Box<ArtNode<V>>>,
12    size: usize,
13}
14
15impl<V: Clone> AdaptiveRadixTree<V> {
16    pub fn new() -> Self {
17        Self {
18            root: None,
19            size: 0,
20        }
21    }
22
23    /// Insert a key-value pair
24    pub fn insert(&mut self, key: &[u8], value: V) {
25        if self.root.is_none() {
26            self.root = Some(Box::new(ArtNode::Leaf {
27                key: key.to_vec(),
28                value,
29            }));
30            self.size += 1;
31            return;
32        }
33
34        let root = self.root.take().unwrap();
35        self.root = Some(Self::insert_recursive(root, key, 0, value));
36        self.size += 1;
37    }
38
39    fn insert_recursive(
40        mut node: Box<ArtNode<V>>,
41        key: &[u8],
42        depth: usize,
43        value: V,
44    ) -> Box<ArtNode<V>> {
45        match node.as_mut() {
46            ArtNode::Leaf {
47                key: leaf_key,
48                value: leaf_value,
49            } => {
50                // Check if keys are identical
51                if *leaf_key == key {
52                    // Replace value
53                    *leaf_value = value;
54                    return node;
55                }
56
57                // Find common prefix length starting from depth
58                let common_prefix_len = Self::common_prefix_len(leaf_key, key, depth);
59                let prefix = if depth + common_prefix_len <= leaf_key.len()
60                    && depth + common_prefix_len <= key.len()
61                {
62                    key[depth..depth + common_prefix_len].to_vec()
63                } else {
64                    vec![]
65                };
66
67                // Create a new Node4 to hold both leaves
68                let mut children: [Option<Box<ArtNode<V>>>; 4] = [None, None, None, None];
69                let mut keys_arr = [0u8; 4];
70                let mut num_children = 0u8;
71
72                let next_depth = depth + common_prefix_len;
73
74                // Get the distinguishing bytes for old and new keys
75                let old_byte = if next_depth < leaf_key.len() {
76                    Some(leaf_key[next_depth])
77                } else {
78                    None
79                };
80
81                let new_byte = if next_depth < key.len() {
82                    Some(key[next_depth])
83                } else {
84                    None
85                };
86
87                // Take ownership of old leaf's data
88                let old_key = std::mem::take(leaf_key);
89                let old_value = unsafe { std::ptr::read(leaf_value) };
90
91                // Add old leaf
92                if let Some(byte) = old_byte {
93                    keys_arr[num_children as usize] = byte;
94                    children[num_children as usize] = Some(Box::new(ArtNode::Leaf {
95                        key: old_key,
96                        value: old_value,
97                    }));
98                    num_children += 1;
99                }
100
101                // Add new leaf
102                if let Some(byte) = new_byte {
103                    // Find insertion position (keep sorted for efficiency)
104                    let mut insert_idx = num_children as usize;
105                    for i in 0..num_children as usize {
106                        if byte < keys_arr[i] {
107                            insert_idx = i;
108                            break;
109                        }
110                    }
111
112                    // Shift existing entries if needed
113                    for i in (insert_idx..num_children as usize).rev() {
114                        keys_arr[i + 1] = keys_arr[i];
115                        children[i + 1] = children[i].take();
116                    }
117
118                    keys_arr[insert_idx] = byte;
119                    children[insert_idx] = Some(Box::new(ArtNode::Leaf {
120                        key: key.to_vec(),
121                        value,
122                    }));
123                    num_children += 1;
124                }
125
126                Box::new(ArtNode::Node4 {
127                    prefix,
128                    children,
129                    keys: keys_arr,
130                    num_children,
131                })
132            }
133            ArtNode::Node4 {
134                prefix,
135                children,
136                keys,
137                num_children,
138            } => {
139                // Check prefix match
140                let prefix_match = Self::check_prefix(prefix, key, depth);
141
142                if prefix_match < prefix.len() {
143                    // Prefix mismatch - need to split the node
144                    let common = prefix[..prefix_match].to_vec();
145                    let remaining = prefix[prefix_match..].to_vec();
146                    let old_byte = remaining[0];
147
148                    // Create new inner node with remaining prefix
149                    let old_children = std::mem::replace(children, [None, None, None, None]);
150                    let old_keys = *keys;
151                    let old_num = *num_children;
152
153                    let inner_node = Box::new(ArtNode::Node4 {
154                        prefix: remaining[1..].to_vec(),
155                        children: old_children,
156                        keys: old_keys,
157                        num_children: old_num,
158                    });
159
160                    // Create new leaf for the inserted key
161                    let next_depth = depth + prefix_match;
162                    let new_byte = if next_depth < key.len() {
163                        key[next_depth]
164                    } else {
165                        0
166                    };
167                    let new_leaf = Box::new(ArtNode::Leaf {
168                        key: key.to_vec(),
169                        value,
170                    });
171
172                    // Set up new node
173                    let mut new_children: [Option<Box<ArtNode<V>>>; 4] = [None, None, None, None];
174                    let mut new_keys = [0u8; 4];
175
176                    if old_byte < new_byte {
177                        new_keys[0] = old_byte;
178                        new_children[0] = Some(inner_node);
179                        new_keys[1] = new_byte;
180                        new_children[1] = Some(new_leaf);
181                    } else {
182                        new_keys[0] = new_byte;
183                        new_children[0] = Some(new_leaf);
184                        new_keys[1] = old_byte;
185                        new_children[1] = Some(inner_node);
186                    }
187
188                    return Box::new(ArtNode::Node4 {
189                        prefix: common,
190                        children: new_children,
191                        keys: new_keys,
192                        num_children: 2,
193                    });
194                }
195
196                // Full prefix match - traverse to child
197                let next_depth = depth + prefix.len();
198                if next_depth < key.len() {
199                    let key_byte = key[next_depth];
200
201                    // Find existing child
202                    for i in 0..(*num_children as usize) {
203                        if keys[i] == key_byte {
204                            let child = children[i].take().unwrap();
205                            children[i] =
206                                Some(Self::insert_recursive(child, key, next_depth + 1, value));
207                            return node;
208                        }
209                    }
210
211                    // No matching child - add new one
212                    if (*num_children as usize) < 4 {
213                        let idx = *num_children as usize;
214                        keys[idx] = key_byte;
215                        children[idx] = Some(Box::new(ArtNode::Leaf {
216                            key: key.to_vec(),
217                            value,
218                        }));
219                        *num_children += 1;
220                    }
221                    // TODO: Handle node growth to Node16 when full
222                }
223
224                node
225            }
226            _ => {
227                // Handle other node types (Node16, Node48, Node256)
228                node
229            }
230        }
231    }
232
233    /// Search for a value by key
234    pub fn get(&self, key: &[u8]) -> Option<&V> {
235        let mut current = self.root.as_ref()?;
236        let mut depth = 0;
237
238        loop {
239            match current.as_ref() {
240                ArtNode::Leaf {
241                    key: leaf_key,
242                    value,
243                } => {
244                    if leaf_key == key {
245                        return Some(value);
246                    } else {
247                        return None;
248                    }
249                }
250                ArtNode::Node4 {
251                    prefix,
252                    children,
253                    keys,
254                    num_children,
255                } => {
256                    if !Self::match_prefix(prefix, key, depth) {
257                        return None;
258                    }
259
260                    depth += prefix.len();
261                    if depth >= key.len() {
262                        return None;
263                    }
264
265                    let key_byte = key[depth];
266                    let mut found = false;
267
268                    for i in 0..*num_children as usize {
269                        if keys[i] == key_byte {
270                            current = children[i].as_ref()?;
271                            depth += 1;
272                            found = true;
273                            break;
274                        }
275                    }
276
277                    if !found {
278                        return None;
279                    }
280                }
281                _ => return None,
282            }
283        }
284    }
285
286    /// Check if tree contains key
287    pub fn contains_key(&self, key: &[u8]) -> bool {
288        self.get(key).is_some()
289    }
290
291    /// Get number of entries
292    pub fn len(&self) -> usize {
293        self.size
294    }
295
296    /// Check if tree is empty
297    pub fn is_empty(&self) -> bool {
298        self.size == 0
299    }
300
301    /// Find common prefix length
302    fn common_prefix_len(a: &[u8], b: &[u8], start: usize) -> usize {
303        let mut len = 0;
304        let max = a.len().min(b.len()) - start;
305
306        for i in 0..max {
307            if a[start + i] == b[start + i] {
308                len += 1;
309            } else {
310                break;
311            }
312        }
313
314        len
315    }
316
317    /// Check prefix match
318    fn check_prefix(prefix: &[u8], key: &[u8], depth: usize) -> usize {
319        let max = prefix.len().min(key.len() - depth);
320        let mut matched = 0;
321
322        for i in 0..max {
323            if prefix[i] == key[depth + i] {
324                matched += 1;
325            } else {
326                break;
327            }
328        }
329
330        matched
331    }
332
333    /// Check if prefix matches
334    fn match_prefix(prefix: &[u8], key: &[u8], depth: usize) -> bool {
335        if depth + prefix.len() > key.len() {
336            return false;
337        }
338
339        for i in 0..prefix.len() {
340            if prefix[i] != key[depth + i] {
341                return false;
342            }
343        }
344
345        true
346    }
347}
348
349impl<V: Clone> Default for AdaptiveRadixTree<V> {
350    fn default() -> Self {
351        Self::new()
352    }
353}
354
355/// ART node types with adaptive sizing
356pub enum ArtNode<V> {
357    /// Leaf node containing value
358    Leaf { key: Vec<u8>, value: V },
359
360    /// Node with 4 children (smallest)
361    Node4 {
362        prefix: Vec<u8>,
363        children: [Option<Box<ArtNode<V>>>; 4],
364        keys: [u8; 4],
365        num_children: u8,
366    },
367
368    /// Node with 16 children
369    Node16 {
370        prefix: Vec<u8>,
371        children: [Option<Box<ArtNode<V>>>; 16],
372        keys: [u8; 16],
373        num_children: u8,
374    },
375
376    /// Node with 48 children (using index array)
377    Node48 {
378        prefix: Vec<u8>,
379        children: [Option<Box<ArtNode<V>>>; 48],
380        index: [u8; 256], // Maps key byte to child index
381        num_children: u8,
382    },
383
384    /// Node with 256 children (full array)
385    Node256 {
386        prefix: Vec<u8>,
387        children: [Option<Box<ArtNode<V>>>; 256],
388        num_children: u16,
389    },
390}
391
392impl<V> ArtNode<V> {
393    /// Check if node is a leaf
394    pub fn is_leaf(&self) -> bool {
395        matches!(self, ArtNode::Leaf { .. })
396    }
397
398    /// Get node type name
399    pub fn node_type(&self) -> &str {
400        match self {
401            ArtNode::Leaf { .. } => "Leaf",
402            ArtNode::Node4 { .. } => "Node4",
403            ArtNode::Node16 { .. } => "Node16",
404            ArtNode::Node48 { .. } => "Node48",
405            ArtNode::Node256 { .. } => "Node256",
406        }
407    }
408}
409
410/// Iterator over ART entries
411pub struct ArtIter<'a, V> {
412    stack: Vec<&'a ArtNode<V>>,
413}
414
415impl<'a, V> Iterator for ArtIter<'a, V> {
416    type Item = (&'a [u8], &'a V);
417
418    fn next(&mut self) -> Option<Self::Item> {
419        while let Some(node) = self.stack.pop() {
420            match node {
421                ArtNode::Leaf { key, value } => {
422                    return Some((key.as_slice(), value));
423                }
424                ArtNode::Node4 {
425                    children,
426                    num_children,
427                    ..
428                } => {
429                    for i in (0..*num_children as usize).rev() {
430                        if let Some(child) = &children[i] {
431                            self.stack.push(child);
432                        }
433                    }
434                }
435                _ => {
436                    // Handle other node types
437                }
438            }
439        }
440        None
441    }
442}
443
444#[cfg(test)]
445mod tests {
446    use super::*;
447
448    #[test]
449    fn test_art_basic() {
450        let mut tree = AdaptiveRadixTree::new();
451
452        tree.insert(b"hello", 1);
453        tree.insert(b"world", 2);
454        tree.insert(b"help", 3);
455
456        assert_eq!(tree.get(b"hello"), Some(&1));
457        assert_eq!(tree.get(b"world"), Some(&2));
458        assert_eq!(tree.get(b"help"), Some(&3));
459        assert_eq!(tree.get(b"nonexistent"), None);
460    }
461
462    #[test]
463    fn test_art_contains() {
464        let mut tree = AdaptiveRadixTree::new();
465
466        tree.insert(b"test", 42);
467
468        assert!(tree.contains_key(b"test"));
469        assert!(!tree.contains_key(b"other"));
470    }
471
472    #[test]
473    fn test_art_len() {
474        let mut tree = AdaptiveRadixTree::new();
475
476        assert_eq!(tree.len(), 0);
477        assert!(tree.is_empty());
478
479        tree.insert(b"a", 1);
480        tree.insert(b"b", 2);
481
482        assert_eq!(tree.len(), 2);
483        assert!(!tree.is_empty());
484    }
485
486    #[test]
487    fn test_art_common_prefix() {
488        let mut tree = AdaptiveRadixTree::new();
489
490        tree.insert(b"prefix_one", 1);
491        tree.insert(b"prefix_two", 2);
492        tree.insert(b"other", 3);
493
494        assert_eq!(tree.get(b"prefix_one"), Some(&1));
495        assert_eq!(tree.get(b"prefix_two"), Some(&2));
496        assert_eq!(tree.get(b"other"), Some(&3));
497    }
498}