grafeo_core/index/
hash.rs1use grafeo_common::types::NodeId;
7use grafeo_common::utils::hash::FxHashMap;
8use parking_lot::RwLock;
9use std::hash::Hash;
10
11pub struct HashIndex<K: Hash + Eq, V: Copy> {
29 map: RwLock<FxHashMap<K, V>>,
31}
32
33impl<K: Hash + Eq, V: Copy> HashIndex<K, V> {
34 #[must_use]
36 pub fn new() -> Self {
37 Self {
38 map: RwLock::new(FxHashMap::default()),
39 }
40 }
41
42 #[must_use]
44 pub fn with_capacity(capacity: usize) -> Self {
45 Self {
46 map: RwLock::new(FxHashMap::with_capacity_and_hasher(
47 capacity,
48 Default::default(),
49 )),
50 }
51 }
52
53 pub fn insert(&self, key: K, value: V) -> Option<V> {
57 self.map.write().insert(key, value)
58 }
59
60 pub fn get(&self, key: &K) -> Option<V> {
62 self.map.read().get(key).copied()
63 }
64
65 pub fn remove(&self, key: &K) -> Option<V> {
69 self.map.write().remove(key)
70 }
71
72 pub fn contains(&self, key: &K) -> bool {
74 self.map.read().contains_key(key)
75 }
76
77 pub fn len(&self) -> usize {
79 self.map.read().len()
80 }
81
82 pub fn is_empty(&self) -> bool {
84 self.map.read().is_empty()
85 }
86
87 pub fn clear(&self) {
89 self.map.write().clear();
90 }
91}
92
93impl<K: Hash + Eq, V: Copy> Default for HashIndex<K, V> {
94 fn default() -> Self {
95 Self::new()
96 }
97}
98
99pub type StringKeyIndex = HashIndex<String, NodeId>;
101
102pub type NodeIdIndex = HashIndex<NodeId, NodeId>;
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 #[test]
110 fn test_hash_index_basic() {
111 let index: HashIndex<u64, NodeId> = HashIndex::new();
112
113 index.insert(1, NodeId::new(100));
114 index.insert(2, NodeId::new(200));
115
116 assert_eq!(index.get(&1), Some(NodeId::new(100)));
117 assert_eq!(index.get(&2), Some(NodeId::new(200)));
118 assert_eq!(index.get(&3), None);
119 }
120
121 #[test]
122 fn test_hash_index_update() {
123 let index: HashIndex<u64, NodeId> = HashIndex::new();
124
125 index.insert(1, NodeId::new(100));
126 let old = index.insert(1, NodeId::new(200));
127
128 assert_eq!(old, Some(NodeId::new(100)));
129 assert_eq!(index.get(&1), Some(NodeId::new(200)));
130 }
131
132 #[test]
133 fn test_hash_index_remove() {
134 let index: HashIndex<u64, NodeId> = HashIndex::new();
135
136 index.insert(1, NodeId::new(100));
137 assert!(index.contains(&1));
138
139 let removed = index.remove(&1);
140 assert_eq!(removed, Some(NodeId::new(100)));
141 assert!(!index.contains(&1));
142 }
143
144 #[test]
145 fn test_hash_index_len() {
146 let index: HashIndex<u64, NodeId> = HashIndex::new();
147
148 assert!(index.is_empty());
149 assert_eq!(index.len(), 0);
150
151 index.insert(1, NodeId::new(100));
152 index.insert(2, NodeId::new(200));
153
154 assert!(!index.is_empty());
155 assert_eq!(index.len(), 2);
156 }
157
158 #[test]
159 fn test_hash_index_clear() {
160 let index: HashIndex<u64, NodeId> = HashIndex::new();
161
162 index.insert(1, NodeId::new(100));
163 index.insert(2, NodeId::new(200));
164
165 index.clear();
166
167 assert!(index.is_empty());
168 assert_eq!(index.get(&1), None);
169 }
170
171 #[test]
172 fn test_string_key_index() {
173 let index: StringKeyIndex = HashIndex::new();
174
175 index.insert("alice".to_string(), NodeId::new(1));
176 index.insert("bob".to_string(), NodeId::new(2));
177
178 assert_eq!(index.get(&"alice".to_string()), Some(NodeId::new(1)));
179 assert_eq!(index.get(&"bob".to_string()), Some(NodeId::new(2)));
180 }
181}