Skip to main content

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