ktrs_parser/builder/
chameleon_cache.rs1use std::collections::HashMap;
10
11use ktrs_syntax::{SyntaxKind, Tree};
12
13#[derive(Default)]
14pub struct ChameleonCache {
15 subtrees: HashMap<u64, Vec<Tree>>,
17}
18
19impl ChameleonCache {
20 pub fn new() -> ChameleonCache {
21 ChameleonCache::default()
22 }
23
24 pub(super) fn get(&self, kind: SyntaxKind, text: &str) -> Option<&Tree> {
25 let bucket = self.subtrees.get(&hash(kind, text))?;
26 bucket.iter().find(|t| t.kind(Tree::ROOT) == kind && t.text() == text)
27 }
28
29 pub(super) fn insert(&mut self, subtree: Tree) {
30 let key = hash(subtree.kind(Tree::ROOT), subtree.text());
31 self.subtrees.entry(key).or_default().push(subtree);
32 }
33}
34
35fn hash(kind: SyntaxKind, text: &str) -> u64 {
37 let mut h = kind as u64;
38 let mut mix = |word: u64| h = (h.rotate_left(5) ^ word).wrapping_mul(0x517c_c1b7_2722_0a95);
39 let (words, rest) = text.as_bytes().as_chunks::<8>();
40 for &word in words {
41 mix(u64::from_le_bytes(word));
42 }
43 let mut tail = [0u8; 8];
44 tail[..rest.len()].copy_from_slice(rest);
45 mix(u64::from_le_bytes(tail) ^ (text.len() as u64) << 56);
46 h ^ h >> 29
47}