kanata_parser/
trie.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
//! Wrapper around a trie type for (hopefully) easier swapping of libraries if desired.

use bytemuck::cast_slice;
use patricia_tree::map::PatriciaMap;

pub type TrieKeyElement = u16;
pub type TrieKey = Vec<TrieKeyElement>;
pub type TrieVal = (u8, u16);

#[derive(Debug, Clone)]
pub struct Trie {
    inner: patricia_tree::map::PatriciaMap<TrieVal>,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum GetOrDescendentExistsResult {
    NotInTrie,
    InTrie,
    HasValue(TrieVal),
}

use GetOrDescendentExistsResult::*;

impl Default for Trie {
    fn default() -> Self {
        Self::new()
    }
}

fn key_len(k: &TrieKey) -> usize {
    debug_assert!(std::mem::size_of::<TrieKeyElement>() == 2 * std::mem::size_of::<u8>());
    k.len() * 2
}

impl Trie {
    pub fn new() -> Self {
        Self {
            inner: PatriciaMap::new(),
        }
    }

    pub fn ancestor_exists(&self, key: &TrieKey) -> bool {
        self.inner
            .get_longest_common_prefix(cast_slice(key))
            .is_some()
    }

    pub fn descendant_exists(&self, key: &TrieKey) -> bool {
        // Length of the [u8] interpretation of the [u16] key is doubled.
        self.inner.longest_common_prefix_len(cast_slice(key)) == key_len(key)
    }

    pub fn insert(&mut self, key: TrieKey, val: TrieVal) {
        self.inner.insert(cast_slice(&key), val);
    }

    pub fn get_or_descendant_exists(&self, key: &TrieKey) -> GetOrDescendentExistsResult {
        let mut descendants = self.inner.iter_prefix(cast_slice(key));
        match descendants.next() {
            None => NotInTrie,
            Some(descendant) => {
                if descendant.0.len() == key_len(key) {
                    HasValue(*descendant.1)
                } else {
                    InTrie
                }
            }
        }
    }
}