1use std::collections::HashMap;
3use std::hash::{Hash, Hasher};
4
5pub struct MergeCache {
21 entries: HashMap<(u64, u64, u64), String>,
22 max_entries: usize,
23}
24
25impl MergeCache {
26 pub fn new(max_entries: usize) -> Self {
27 Self {
28 entries: HashMap::new(),
29 max_entries,
30 }
31 }
32
33 pub fn get(&self, base: &str, ours: &str, theirs: &str) -> Option<&str> {
34 let key = (hash(base), hash(ours), hash(theirs));
35 self.entries.get(&key).map(|s| s.as_str())
36 }
37
38 pub fn insert(&mut self, base: &str, ours: &str, theirs: &str, result: String) {
39 if self.entries.len() >= self.max_entries {
40 if let Some(first_key) = self.entries.keys().next().copied() {
41 self.entries.remove(&first_key);
42 }
43 }
44 let key = (hash(base), hash(ours), hash(theirs));
45 self.entries.insert(key, result);
46 }
47
48 pub fn len(&self) -> usize {
49 self.entries.len()
50 }
51
52 pub fn is_empty(&self) -> bool {
53 self.entries.is_empty()
54 }
55
56 pub fn clear(&mut self) {
57 self.entries.clear();
58 }
59}
60
61fn hash(s: &str) -> u64 {
62 let mut hasher = std::collections::hash_map::DefaultHasher::new();
63 s.hash(&mut hasher);
64 hasher.finish()
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn test_cache_hit() {
73 let mut cache = MergeCache::new(16);
74 cache.insert("b", "o", "t", "result".to_string());
75 assert_eq!(cache.get("b", "o", "t"), Some("result"));
76 }
77
78 #[test]
79 fn test_cache_miss() {
80 let cache = MergeCache::new(16);
81 assert_eq!(cache.get("b", "o", "t"), None);
82 }
83
84 #[test]
85 fn test_cache_eviction() {
86 let mut cache = MergeCache::new(2);
87 cache.insert("a", "b", "c", "1".to_string());
88 cache.insert("d", "e", "f", "2".to_string());
89 cache.insert("g", "h", "i", "3".to_string());
90 assert_eq!(cache.len(), 2);
91 }
92
93 #[test]
94 fn test_cache_clear() {
95 let mut cache = MergeCache::new(16);
96 cache.insert("a", "b", "c", "1".to_string());
97 cache.clear();
98 assert!(cache.is_empty());
99 }
100
101 #[test]
102 fn test_cache_different_order_is_different() {
103 let mut cache = MergeCache::new(16);
104 cache.insert("base", "ours", "theirs", "result1".to_string());
105 cache.insert("base", "theirs", "ours", "result2".to_string());
106 assert_eq!(cache.get("base", "ours", "theirs"), Some("result1"));
107 assert_eq!(cache.get("base", "theirs", "ours"), Some("result2"));
108 }
109}