1use crate::Value;
2use crate::collections::array_map::PersistentArrayMap;
3use rpds::{HashTrieMapSync, RedBlackTreeMapSync};
4
5#[derive(Debug, Clone)]
20pub struct PersistentHashMap {
21 index: HashTrieMapSync<Value, u64>,
22 order: RedBlackTreeMapSync<u64, (Value, Value)>,
23 next_seq: u64,
24}
25
26impl PersistentHashMap {
27 pub fn empty() -> Self {
28 Self {
29 index: HashTrieMapSync::new_sync(),
30 next_seq: 0,
31 order: RedBlackTreeMapSync::new_sync(),
32 }
33 }
34
35 pub fn new(map: HashTrieMapSync<Value, Value>) -> Self {
40 Self::from_pairs(map.iter().map(|(k, v)| (k.clone(), v.clone())))
41 }
42
43 pub fn count(&self) -> usize {
44 self.index.size()
45 }
46
47 pub fn is_empty(&self) -> bool {
48 self.index.is_empty()
49 }
50
51 pub fn get(&self, key: &Value) -> Option<&Value> {
53 let seq = self.index.get(key)?;
54 self.order.get(seq).map(|(_, v)| v)
55 }
56
57 pub fn contains_key(&self, key: &Value) -> bool {
58 self.index.contains_key(key)
59 }
60
61 pub fn assoc(&self, key: Value, value: Value) -> Self {
66 if let Some(seq) = self.index.get(&key) {
67 let seq = *seq;
68 Self {
69 index: self.index.clone(),
70 order: self.order.insert(seq, (key, value)),
71 next_seq: self.next_seq,
72 }
73 } else {
74 let seq = self.next_seq;
75 Self {
76 index: self.index.insert(key.clone(), seq),
77 order: self.order.insert(seq, (key, value)),
78 next_seq: seq + 1,
79 }
80 }
81 }
82
83 pub fn dissoc(&self, key: &Value) -> Self {
85 match self.index.get(key) {
86 Some(seq) => Self {
87 index: self.index.remove(key),
88 order: self.order.remove(seq),
89 next_seq: self.next_seq,
90 },
91 None => self.clone(),
92 }
93 }
94
95 pub fn iter(&self) -> impl Iterator<Item = (&Value, &Value)> {
97 self.order.iter().map(|(_, (k, v))| (k, v))
98 }
99
100 pub fn keys(&self) -> Vec<Value> {
102 self.iter().map(|(k, _)| k.clone()).collect()
103 }
104
105 pub fn vals(&self) -> Vec<Value> {
107 self.iter().map(|(_, v)| v.clone()).collect()
108 }
109
110 pub fn merge(&self, other: &Self) -> Self {
112 let mut result = self.clone();
113 for (k, v) in other.iter() {
114 result = result.assoc(k.clone(), v.clone());
115 }
116 result
117 }
118
119 pub fn from_pairs<I: IntoIterator<Item = (Value, Value)>>(iter: I) -> Self {
121 let mut m = Self::empty();
122 for (k, v) in iter {
123 m = m.assoc(k, v);
124 }
125 m
126 }
127
128 pub fn from_array_map(am: &PersistentArrayMap) -> Self {
130 Self::from_pairs(am.iter().map(|(k, v)| (k.clone(), v.clone())))
131 }
132}
133
134impl PartialEq for PersistentHashMap {
135 fn eq(&self, other: &Self) -> bool {
136 if self.count() != other.count() {
137 return false;
138 }
139 self.iter().all(|(k, v)| other.get(k) == Some(v))
140 }
141}
142
143impl cljrs_gc::Trace for PersistentHashMap {
144 fn trace(&self, visitor: &mut cljrs_gc::MarkVisitor) {
145 for (_, (k, v)) in self.order.iter() {
146 k.trace(visitor);
147 v.trace(visitor);
148 }
149 }
150
151 fn gc_size_extra(&self) -> usize {
152 let n = self.index.size();
155 n * (88 + 2 * std::mem::size_of::<Value>())
156 }
157}
158
159#[cfg(test)]
160mod tests {
161 use super::*;
162 use crate::Value;
163 use crate::collections::array_map::AssocResult;
164 use cljrs_gc::GcPtr;
165
166 fn kw(s: &str) -> Value {
167 Value::Keyword(GcPtr::new(crate::keyword::Keyword::simple(s)))
168 }
169 fn int(n: i64) -> Value {
170 Value::Long(n)
171 }
172
173 #[test]
174 fn test_basic_ops() {
175 let m = PersistentHashMap::empty();
176 let m = m.assoc(kw("a"), int(1));
177 let m = m.assoc(kw("b"), int(2));
178 assert_eq!(m.count(), 2);
179 assert_eq!(m.get(&kw("a")), Some(&int(1)));
180 assert_eq!(m.get(&kw("b")), Some(&int(2)));
181 assert_eq!(m.get(&kw("c")), None);
182 }
183
184 #[test]
185 fn test_update() {
186 let m = PersistentHashMap::empty()
187 .assoc(kw("a"), int(1))
188 .assoc(kw("a"), int(99));
189 assert_eq!(m.count(), 1);
190 assert_eq!(m.get(&kw("a")), Some(&int(99)));
191 }
192
193 #[test]
194 fn test_dissoc() {
195 let m = PersistentHashMap::empty()
196 .assoc(kw("a"), int(1))
197 .assoc(kw("b"), int(2));
198 let m2 = m.dissoc(&kw("a"));
199 assert_eq!(m2.count(), 1);
200 assert_eq!(m2.get(&kw("a")), None);
201 assert_eq!(m2.get(&kw("b")), Some(&int(2)));
202 }
203
204 #[test]
205 fn test_many_entries() {
206 let mut m = PersistentHashMap::empty();
207 for i in 0i64..200 {
208 m = m.assoc(int(i), int(i * 10));
209 }
210 assert_eq!(m.count(), 200);
211 for i in 0i64..200 {
212 assert_eq!(m.get(&int(i)), Some(&int(i * 10)));
213 }
214 }
215
216 #[test]
217 fn test_merge() {
218 let a = PersistentHashMap::empty()
219 .assoc(kw("a"), int(1))
220 .assoc(kw("b"), int(2));
221 let b = PersistentHashMap::empty()
222 .assoc(kw("b"), int(99))
223 .assoc(kw("c"), int(3));
224 let merged = a.merge(&b);
225 assert_eq!(merged.count(), 3);
226 assert_eq!(merged.get(&kw("a")), Some(&int(1)));
227 assert_eq!(merged.get(&kw("b")), Some(&int(99))); assert_eq!(merged.get(&kw("c")), Some(&int(3)));
229 }
230
231 #[test]
232 fn test_equality() {
233 let a = PersistentHashMap::empty()
234 .assoc(kw("a"), int(1))
235 .assoc(kw("b"), int(2));
236 let b = PersistentHashMap::empty()
237 .assoc(kw("b"), int(2))
238 .assoc(kw("a"), int(1));
239 assert_eq!(a, b);
240 }
241
242 #[test]
243 fn test_from_array_map() {
244 let mut am = PersistentArrayMap::empty();
245 for i in 0..3i64 {
246 let AssocResult::Array(next) = am.assoc(int(i), int(i * 2)) else {
247 panic!()
248 };
249 am = next;
250 }
251 let hm = PersistentHashMap::from_array_map(&am);
252 assert_eq!(hm.count(), 3);
253 for i in 0..3i64 {
254 assert_eq!(hm.get(&int(i)), Some(&int(i * 2)));
255 }
256 }
257
258 #[test]
259 fn test_iteration_order_matches_insertion_order() {
260 let mut m = PersistentHashMap::empty();
261 let keys = ["j", "i", "h", "g", "f", "e", "d", "c", "b", "a", "z", "y"];
262 for k in keys {
263 m = m.assoc(kw(k), int(0));
264 }
265 let iterated: Vec<Value> = m.keys();
266 let expected: Vec<Value> = keys.iter().map(|k| kw(k)).collect();
267 assert_eq!(iterated, expected);
268 }
269
270 #[test]
271 fn test_reassoc_keeps_original_position() {
272 let m = PersistentHashMap::empty()
273 .assoc(kw("a"), int(1))
274 .assoc(kw("b"), int(2))
275 .assoc(kw("c"), int(3))
276 .assoc(kw("b"), int(99));
277 let keys = m.keys();
278 assert_eq!(keys, vec![kw("a"), kw("b"), kw("c")]);
279 assert_eq!(m.get(&kw("b")), Some(&int(99)));
280 }
281
282 #[test]
283 fn test_dissoc_preserves_remaining_order() {
284 let m = PersistentHashMap::empty()
285 .assoc(kw("a"), int(1))
286 .assoc(kw("b"), int(2))
287 .assoc(kw("c"), int(3))
288 .dissoc(&kw("b"));
289 assert_eq!(m.keys(), vec![kw("a"), kw("c")]);
290 }
291}