p3_util/
linear_map.rs

1use alloc::vec::Vec;
2use core::mem;
3use core::ops::Index;
4
5/// A linear key-value map backed by a `Vec`.
6///
7/// This map performs **O(n)** lookups and inserts.
8/// It is suitable only for **small** sets of keys which
9/// must implement `Eq`.
10///
11/// Internally stores key-value pairs in insertion order.
12/// Duplicate key inserts overwrite the previous value.
13///
14/// # Performance
15/// Avoid using this for more than a few keys. All core operations are linear.
16#[derive(Debug)]
17pub struct LinearMap<K, V>(
18    /// The underlying storage for key-value pairs.
19    Vec<(K, V)>,
20);
21
22impl<K, V> Default for LinearMap<K, V> {
23    fn default() -> Self {
24        Self(Default::default())
25    }
26}
27
28impl<K: Eq, V> LinearMap<K, V> {
29    /// Creates a new empty `LinearMap`.
30    pub fn new() -> Self {
31        Default::default()
32    }
33
34    /// Creates a new empty `LinearMap` with a pre-allocated capacity.
35    pub fn with_capacity(capacity: usize) -> Self {
36        Self(Vec::with_capacity(capacity))
37    }
38
39    /// Gets a reference to the value associated with the key, if it exists.
40    ///
41    /// Returns `Some(&V)` if found, or `None` if not present.
42    ///
43    /// This is an **O(n)** operation.
44    pub fn get(&self, k: &K) -> Option<&V> {
45        self.0.iter().find(|(kk, _)| kk == k).map(|(_, v)| v)
46    }
47
48    /// Gets a mutable reference to the value associated with the key, if it exists.
49    ///
50    /// Returns `Some(&mut V)` if found, or `None` otherwise.
51    ///
52    /// This is an **O(n)** operation.
53    pub fn get_mut(&mut self, k: &K) -> Option<&mut V> {
54        self.0.iter_mut().find(|(kk, _)| kk == k).map(|(_, v)| v)
55    }
56
57    /// Inserts a key-value pair into the map.
58    ///
59    /// If the key exists, swaps the old value with the new one and returns the old value.
60    /// Otherwise, appends the new pair and returns `None`.
61    ///
62    /// This is an **O(n)** operation due to the linear search.
63    pub fn insert(&mut self, k: K, mut v: V) -> Option<V> {
64        if let Some(vv) = self.get_mut(&k) {
65            mem::swap(&mut v, vv);
66            Some(v)
67        } else {
68            self.0.push((k, v));
69            None
70        }
71    }
72
73    /// Returns a mutable reference to the value for the given key.
74    ///
75    /// If the key exists, returns a mutable reference to the value.
76    /// Otherwise, inserts a new value created by the provided closure and returns a reference to it.
77    ///
78    /// This is an **O(n)** operation due to the key search.
79    pub fn get_or_insert_with(&mut self, k: K, f: impl FnOnce() -> V) -> &mut V {
80        let existing = self.0.iter().position(|(kk, _)| kk == &k);
81        if let Some(idx) = existing {
82            &mut self.0[idx].1
83        } else {
84            self.0.push((k, f()));
85            let slot = self.0.last_mut().unwrap();
86            &mut slot.1
87        }
88    }
89
90    /// Returns an iterator over the values in the map.
91    ///
92    /// Values are yielded in insertion order.
93    pub fn values(&self) -> impl Iterator<Item = &V> {
94        self.0.iter().map(|(_, v)| v)
95    }
96
97    /// Returns an iterator over the keys in the map.
98    ///
99    /// Keys are yielded in insertion order.
100    pub fn keys(&self) -> impl Iterator<Item = &K> {
101        self.0.iter().map(|(k, _)| k)
102    }
103
104    /// Returns an iterator over all key-value pairs in the map.
105    ///
106    /// Items are yielded in insertion order.
107    pub fn iter(&self) -> impl Iterator<Item = &(K, V)> {
108        self.0.iter()
109    }
110}
111
112impl<K: Eq, V> FromIterator<(K, V)> for LinearMap<K, V> {
113    /// Builds a `LinearMap` from an iterator of key-value pairs.
114    ///
115    /// Later duplicates overwrite earlier entries.
116    ///
117    /// This calls `insert` in a loop, so is O(n^2)!!
118    fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
119        let mut me = Self::default();
120        for (k, v) in iter {
121            me.insert(k, v);
122        }
123        me
124    }
125}
126
127impl<K, V> IntoIterator for LinearMap<K, V> {
128    type Item = (K, V);
129    type IntoIter = <Vec<(K, V)> as IntoIterator>::IntoIter;
130
131    fn into_iter(self) -> Self::IntoIter {
132        self.0.into_iter()
133    }
134}
135
136impl<K: Eq, V> Index<&K> for LinearMap<K, V> {
137    type Output = V;
138
139    fn index(&self, index: &K) -> &Self::Output {
140        self.get(index).unwrap()
141    }
142}
143
144impl<'a, K, V> IntoIterator for &'a LinearMap<K, V> {
145    type Item = &'a (K, V);
146    type IntoIter = <&'a Vec<(K, V)> as IntoIterator>::IntoIter;
147
148    fn into_iter(self) -> Self::IntoIter {
149        self.0.iter()
150    }
151}
152
153#[cfg(test)]
154mod tests {
155    use alloc::vec;
156
157    use super::*;
158
159    #[test]
160    fn test_insert_and_get() {
161        let mut map = LinearMap::new();
162
163        // Insert key=1, value="a" → should return None (new insert)
164        assert_eq!(map.insert(1, "a"), None);
165
166        // Get key=1 → should return Some("a")
167        assert_eq!(map.get(&1), Some(&"a"));
168
169        // Insert same key with new value → should return old value
170        assert_eq!(map.insert(1, "b"), Some("a"));
171
172        // After update, get should return updated value
173        assert_eq!(map.get(&1), Some(&"b"));
174
175        // Non-existent key → should return None
176        assert_eq!(map.get(&2), None);
177    }
178
179    #[test]
180    fn test_get_mut() {
181        let mut map = LinearMap::new();
182        map.insert(42, 100);
183
184        // Mutably get the value for key=42
185        if let Some(val) = map.get_mut(&42) {
186            *val += 1;
187        }
188
189        // Value should now be 101
190        assert_eq!(map.get(&42), Some(&101));
191
192        // get_mut on missing key should return None
193        assert_eq!(map.get_mut(&999), None);
194    }
195
196    #[test]
197    fn test_get_or_insert_with() {
198        let mut map = LinearMap::new();
199
200        // First call should insert 10 with value computed as 123
201        let val = map.get_or_insert_with(10, || 123);
202        assert_eq!(*val, 123);
203
204        // Second call should not invoke the closure, just return existing
205        let val2 = map.get_or_insert_with(10, || panic!("should not be called"));
206        assert_eq!(*val2, 123);
207
208        // Insert another value with a different key
209        let val3 = map.get_or_insert_with(20, || 777);
210        assert_eq!(*val3, 777);
211    }
212
213    #[test]
214    fn test_values_iterator() {
215        let mut map = LinearMap::new();
216        map.insert("a", 1);
217        map.insert("b", 2);
218        map.insert("c", 3);
219
220        // Collect all values into a vector
221        let values: Vec<_> = map.values().copied().collect();
222        assert_eq!(values, vec![1, 2, 3]);
223    }
224
225    #[test]
226    fn test_keys_iterator() {
227        let mut map = LinearMap::new();
228        map.insert("a", 1);
229        map.insert("b", 2);
230        map.insert("c", 3);
231
232        // Collect all values into a vector
233        let values: Vec<_> = map.keys().copied().collect();
234        assert_eq!(values, vec!["a", "b", "c"]);
235    }
236
237    #[test]
238    fn test_index() {
239        let mut map = LinearMap::new();
240        map.insert("a", 1);
241        map.insert("b", 2);
242        map.insert("c", 3);
243
244        assert_eq!(map[&"a"], 1);
245        assert_eq!(map[&"b"], 2);
246        assert_eq!(map[&"c"], 3);
247    }
248
249    #[test]
250    fn test_from_iterator_behavior() {
251        // Use .collect() from an iterator of key-value pairs
252        let map: LinearMap<_, _> = vec![(1, "a"), (2, "b"), (1, "c")].into_iter().collect();
253
254        // Should insert (1, "a"), (2, "b"), then replace (1, "a") with (1, "c")
255        assert_eq!(map.get(&1), Some(&"c"));
256        assert_eq!(map.get(&2), Some(&"b"));
257    }
258
259    #[test]
260    fn test_into_iterator() {
261        let mut map = LinearMap::new();
262        map.insert("x", 10);
263        map.insert("z", 30);
264        map.insert("y", 20);
265
266        // Collect items yielded by `iter()`
267        let iter_ref = map.iter().copied().collect::<Vec<_>>();
268        // Consume the LinearMap into an iterator
269        let iter = map.into_iter().collect::<Vec<_>>();
270
271        // Since it's just a Vec internally, order is preserved
272        assert_eq!(iter_ref, vec![("x", 10), ("z", 30), ("y", 20)]);
273        // Ensure both iter and into_iter yield the same elements
274        assert_eq!(iter, iter_ref);
275    }
276
277    #[test]
278    fn test_empty_map_behavior() {
279        let map: LinearMap<i32, &str> = LinearMap::new();
280
281        // Getting any key from an empty map should return None
282        assert_eq!(map.get(&0), None);
283        assert_eq!(map.get(&999), None);
284
285        // values() iterator should be empty
286        assert_eq!(map.values().count(), 0);
287    }
288}