cljrs_value/collections/
hash_map.rs1use crate::Value;
2use crate::collections::array_map::PersistentArrayMap;
3use rpds::HashTrieMapSync;
4
5#[derive(Debug, Clone)]
11pub struct PersistentHashMap {
12 inner: rpds::HashTrieMapSync<Value, Value>,
13}
14
15impl PersistentHashMap {
16 pub fn empty() -> Self {
17 Self {
18 inner: rpds::HashTrieMapSync::new_sync(),
19 }
20 }
21
22 pub fn new(map: HashTrieMapSync<Value, Value>) -> Self {
23 Self { inner: map }
24 }
25
26 pub fn count(&self) -> usize {
27 self.inner.size()
28 }
29
30 pub fn is_empty(&self) -> bool {
31 self.inner.is_empty()
32 }
33
34 pub fn get(&self, key: &Value) -> Option<&Value> {
36 self.inner.get(key)
37 }
38
39 pub fn contains_key(&self, key: &Value) -> bool {
40 self.inner.contains_key(key)
41 }
42
43 pub fn assoc(&self, key: Value, value: Value) -> Self {
45 Self {
46 inner: self.inner.insert(key, value),
47 }
48 }
49
50 pub fn dissoc(&self, key: &Value) -> Self {
52 Self {
53 inner: self.inner.remove(key),
54 }
55 }
56
57 pub fn iter(&self) -> impl Iterator<Item = (&Value, &Value)> {
59 self.inner.iter()
60 }
61
62 pub fn keys(&self) -> Vec<Value> {
64 self.inner.keys().cloned().collect()
65 }
66
67 pub fn vals(&self) -> Vec<Value> {
69 self.inner.values().cloned().collect()
70 }
71
72 pub fn merge(&self, other: &Self) -> Self {
74 let mut result = self.clone();
75 for (k, v) in other.inner.iter() {
76 result = result.assoc(k.clone(), v.clone());
77 }
78 result
79 }
80
81 pub fn from_pairs<I: IntoIterator<Item = (Value, Value)>>(iter: I) -> Self {
83 let mut m = Self::empty();
84 for (k, v) in iter {
85 m = m.assoc(k, v);
86 }
87 m
88 }
89
90 pub fn from_array_map(am: &PersistentArrayMap) -> Self {
92 Self::from_pairs(am.iter().map(|(k, v)| (k.clone(), v.clone())))
93 }
94
95 pub fn inner(&self) -> &HashTrieMapSync<Value, Value> {
96 &self.inner
97 }
98}
99
100impl PartialEq for PersistentHashMap {
101 fn eq(&self, other: &Self) -> bool {
102 if self.count() != other.count() {
103 return false;
104 }
105 self.inner.iter().all(|(k, v)| other.get(k) == Some(v))
106 }
107}
108
109impl cljrs_gc::Trace for PersistentHashMap {
110 fn trace(&self, visitor: &mut cljrs_gc::MarkVisitor) {
111 for (k, v) in self.inner.iter() {
112 k.trace(visitor);
113 v.trace(visitor);
114 }
115 }
116
117 fn gc_size_extra(&self) -> usize {
118 let n = self.inner.size();
121 n * (40 + 2 * std::mem::size_of::<Value>())
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use super::*;
128 use crate::Value;
129 use crate::collections::array_map::AssocResult;
130 use cljrs_gc::GcPtr;
131
132 fn kw(s: &str) -> Value {
133 Value::Keyword(GcPtr::new(crate::keyword::Keyword::simple(s)))
134 }
135 fn int(n: i64) -> Value {
136 Value::Long(n)
137 }
138
139 #[test]
140 fn test_basic_ops() {
141 let m = PersistentHashMap::empty();
142 let m = m.assoc(kw("a"), int(1));
143 let m = m.assoc(kw("b"), int(2));
144 assert_eq!(m.count(), 2);
145 assert_eq!(m.get(&kw("a")), Some(&int(1)));
146 assert_eq!(m.get(&kw("b")), Some(&int(2)));
147 assert_eq!(m.get(&kw("c")), None);
148 }
149
150 #[test]
151 fn test_update() {
152 let m = PersistentHashMap::empty()
153 .assoc(kw("a"), int(1))
154 .assoc(kw("a"), int(99));
155 assert_eq!(m.count(), 1);
156 assert_eq!(m.get(&kw("a")), Some(&int(99)));
157 }
158
159 #[test]
160 fn test_dissoc() {
161 let m = PersistentHashMap::empty()
162 .assoc(kw("a"), int(1))
163 .assoc(kw("b"), int(2));
164 let m2 = m.dissoc(&kw("a"));
165 assert_eq!(m2.count(), 1);
166 assert_eq!(m2.get(&kw("a")), None);
167 assert_eq!(m2.get(&kw("b")), Some(&int(2)));
168 }
169
170 #[test]
171 fn test_many_entries() {
172 let mut m = PersistentHashMap::empty();
173 for i in 0i64..200 {
174 m = m.assoc(int(i), int(i * 10));
175 }
176 assert_eq!(m.count(), 200);
177 for i in 0i64..200 {
178 assert_eq!(m.get(&int(i)), Some(&int(i * 10)));
179 }
180 }
181
182 #[test]
183 fn test_merge() {
184 let a = PersistentHashMap::empty()
185 .assoc(kw("a"), int(1))
186 .assoc(kw("b"), int(2));
187 let b = PersistentHashMap::empty()
188 .assoc(kw("b"), int(99))
189 .assoc(kw("c"), int(3));
190 let merged = a.merge(&b);
191 assert_eq!(merged.count(), 3);
192 assert_eq!(merged.get(&kw("a")), Some(&int(1)));
193 assert_eq!(merged.get(&kw("b")), Some(&int(99))); assert_eq!(merged.get(&kw("c")), Some(&int(3)));
195 }
196
197 #[test]
198 fn test_equality() {
199 let a = PersistentHashMap::empty()
200 .assoc(kw("a"), int(1))
201 .assoc(kw("b"), int(2));
202 let b = PersistentHashMap::empty()
203 .assoc(kw("b"), int(2))
204 .assoc(kw("a"), int(1));
205 assert_eq!(a, b);
206 }
207
208 #[test]
209 fn test_from_array_map() {
210 let mut am = PersistentArrayMap::empty();
211 for i in 0..3i64 {
212 let AssocResult::Array(next) = am.assoc(int(i), int(i * 2)) else {
213 panic!()
214 };
215 am = next;
216 }
217 let hm = PersistentHashMap::from_array_map(&am);
218 assert_eq!(hm.count(), 3);
219 for i in 0..3i64 {
220 assert_eq!(hm.get(&int(i)), Some(&int(i * 2)));
221 }
222 }
223}