compact_map/
base.rs

1use crate::base::{
2    drain::{DrainInner, HeaplessDrain},
3    entry::{Entry, HeaplessEntry, OccupiedEntry, VacantEntry},
4    iter::{IntoIterInner, IterInner, IterMutInner},
5};
6use std::borrow::Borrow;
7use std::collections::HashMap;
8use std::fmt::Display;
9use std::hash::Hash;
10use std::hint::unreachable_unchecked;
11use std::mem::ManuallyDrop;
12use std::ptr;
13
14pub(crate) mod drain;
15pub(crate) mod entry;
16#[cfg(feature = "extract_if")]
17pub(crate) mod extract_if;
18pub(crate) mod iter;
19
20pub(crate) enum MapImpl<K, V, const N: usize> {
21    Heapless(heapless::Vec<(K, V), N>),
22    Spilled(HashMap<K, V>),
23}
24
25impl<K, V, const N: usize> MapImpl<K, V, N> {
26    #[inline(always)]
27    pub const fn new() -> Self {
28        Self::Heapless(heapless::Vec::new())
29    }
30
31    #[inline(always)]
32    pub const fn spilled(&self) -> bool {
33        matches!(self, Self::Spilled(_))
34    }
35
36    #[inline(always)]
37    pub fn capacity(&self) -> usize {
38        match self {
39            Self::Heapless(_) => N,
40            Self::Spilled(m) => m.capacity(),
41        }
42    }
43
44    #[inline]
45    pub fn iter(&self) -> IterInner<'_, K, V, N> {
46        match self {
47            Self::Heapless(vec) => IterInner::Heapless { next: 0, vec },
48            Self::Spilled(map) => IterInner::Spilled(map.iter()),
49        }
50    }
51
52    #[inline]
53    pub fn iter_mut(&mut self) -> IterMutInner<'_, K, V, N> {
54        match self {
55            Self::Heapless(vec) => IterMutInner::Heapless(vec.iter_mut()),
56            Self::Spilled(map) => IterMutInner::Spilled(map.iter_mut()),
57        }
58    }
59
60    #[inline]
61    pub fn len(&self) -> usize {
62        match self {
63            Self::Heapless(vec) => vec.len(),
64            Self::Spilled(map) => map.len(),
65        }
66    }
67
68    #[inline]
69    pub fn is_empty(&self) -> bool {
70        match self {
71            Self::Heapless(vec) => vec.is_empty(),
72            Self::Spilled(m) => m.is_empty(),
73        }
74    }
75
76    #[inline]
77    pub fn drain(&mut self) -> DrainInner<'_, K, V, N> {
78        match self {
79            Self::Heapless(base) => DrainInner::Heapless(HeaplessDrain { base }),
80            Self::Spilled(map) => DrainInner::Spilled(map.drain()),
81        }
82    }
83
84    #[cfg(feature = "extract_if")]
85    #[inline]
86    pub fn extract_if<F>(&mut self, pred: F) -> extract_if::ExtractIfInner<'_, K, V, F, N>
87    where
88        F: FnMut(&K, &mut V) -> bool,
89    {
90        match self {
91            Self::Heapless(base) => extract_if::ExtractIfInner::Heapless {
92                base,
93                next: 0,
94                pred,
95            },
96            Self::Spilled(map) => extract_if::ExtractIfInner::Spilled(map.extract_if(pred)),
97        }
98    }
99
100    #[inline]
101    pub fn retain<F>(&mut self, mut f: F)
102    where
103        F: FnMut(&K, &mut V) -> bool,
104    {
105        match self {
106            Self::Heapless(vec) => {
107                vec.retain_mut(|(k, v)| f(k, v));
108            }
109            Self::Spilled(map) => {
110                map.retain(f);
111            }
112        }
113    }
114
115    #[inline]
116    pub fn clear(&mut self) {
117        match self {
118            Self::Heapless(vec) => vec.clear(),
119            Self::Spilled(m) => m.clear(),
120        }
121    }
122
123    /// # Safety
124    ///
125    /// `MapImpl` must be in the `Heapless` variant.
126    #[inline]
127    unsafe fn into_heapless_unchecked(self) -> heapless::Vec<(K, V), N> {
128        match self {
129            Self::Heapless(v) => v,
130            _ => unsafe { unreachable_unchecked() },
131        }
132    }
133
134    /// # Safety
135    ///
136    /// `MapImpl` must be in the `Spilled` variant.
137    #[inline]
138    unsafe fn into_spilled_unchecked(self) -> HashMap<K, V> {
139        match self {
140            Self::Spilled(m) => m,
141            _ => unsafe { unreachable_unchecked() },
142        }
143    }
144
145    /// # Safety
146    ///
147    /// `MapImpl` must be in the `Heapless` variant.
148    #[inline]
149    unsafe fn as_heapless_unchecked(&self) -> &heapless::Vec<(K, V), N> {
150        match self {
151            Self::Heapless(m) => m,
152            _ => unsafe { unreachable_unchecked() },
153        }
154    }
155
156    /// # Safety
157    ///
158    /// `MapImpl` must be in the `Heapless` variant.
159    #[inline]
160    unsafe fn as_heapless_mut_unchecked(&mut self) -> &mut heapless::Vec<(K, V), N> {
161        match self {
162            Self::Heapless(m) => m,
163            _ => unsafe { unreachable_unchecked() },
164        }
165    }
166
167    // /// # Safety
168    // ///
169    // /// `MapImpl` must be in the `Spilled` variant.
170    // #[inline]
171    // unsafe fn as_spilled_unchecked(&self) -> &HashMap<K, V> {
172    //     match self {
173    //         Self::Spilled(m) => m,
174    //         _ => unsafe { unreachable_unchecked() },
175    //     }
176    // }
177
178    /// # Safety
179    ///
180    /// `MapImpl` must be in the `Spilled` variant.
181    #[inline]
182    unsafe fn as_spilled_mut_unchecked(&mut self) -> &mut HashMap<K, V> {
183        match self {
184            Self::Spilled(m) => m,
185            _ => unsafe { unreachable_unchecked() },
186        }
187    }
188}
189
190impl<K, V, const N: usize> MapImpl<K, V, N>
191where
192    K: Eq + Hash,
193{
194    #[inline]
195    pub fn reserve(&mut self, additional: usize) {
196        if !self.spilled() && self.len() + additional > N {
197            // Safety: we just checked the variant
198            unsafe { self.try_spill(additional) }.unwrap();
199        } else {
200            // Safety: we just checked the variant
201            unsafe {
202                self.as_spilled_mut_unchecked().reserve(additional);
203            }
204        }
205    }
206
207    #[inline]
208    pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
209        if !self.spilled() {
210            if self.len() + additional > N {
211                // Safety: we just checked the variant
212                unsafe { self.try_spill(additional) }?;
213            }
214            // otherwise, we're good
215        } else {
216            // Safety: we just checked the variant
217            unsafe {
218                self.as_spilled_mut_unchecked().try_reserve(additional)?;
219            }
220        }
221        Ok(())
222    }
223
224    #[inline]
225    pub fn spill(&mut self) {
226        if !self.spilled() {
227            // Safety: we just checked the variant
228            unsafe { self.try_spill(0) }.unwrap();
229        }
230    }
231
232    pub fn shrink_into_heapless<const M: usize>(
233        self,
234    ) -> Result<MapImpl<K, V, M>, MapImpl<K, V, N>> {
235        if self.len() > M {
236            return Err(self);
237        }
238
239        let heapless = match self {
240            MapImpl::Heapless(vec) => {
241                let vec = ManuallyDrop::new(vec);
242                let mut new = heapless::Vec::new();
243                unsafe {
244                    // Safety: vec won't be dropped, vec cannot overlap with new
245                    ptr::copy_nonoverlapping(vec.as_ptr(), new.as_mut_ptr(), vec.len());
246                    new.set_len(vec.len());
247                }
248                new
249            }
250            MapImpl::Spilled(map) => map.into_iter().collect::<heapless::Vec<(K, V), M>>(),
251        };
252
253        Ok(MapImpl::Heapless(heapless))
254    }
255
256    #[inline]
257    pub fn shrink_to_fit(&mut self) {
258        if let Self::Spilled(map) = self {
259            map.shrink_to_fit()
260        }
261    }
262
263    #[inline]
264    pub fn shrink_to(&mut self, min_capacity: usize) {
265        if let Self::Spilled(map) = self {
266            map.shrink_to(min_capacity)
267        }
268    }
269
270    #[inline]
271    pub fn entry(&mut self, key: K) -> Entry<'_, K, V, N> {
272        match self {
273            Self::Heapless(vec) => {
274                if vec.is_empty() {
275                    Entry::Vacant(VacantEntry::Heapless(HeaplessEntry {
276                        key: Some(key),
277                        inner: self,
278                        index: 0,
279                    }))
280                } else if let Some(index) = vec.iter().position(|(k, _)| k == &key) {
281                    Entry::Occupied(OccupiedEntry::Heapless(HeaplessEntry {
282                        key: Some(key),
283                        inner: self,
284                        index,
285                    }))
286                } else {
287                    let len = vec.len();
288                    Entry::Vacant(VacantEntry::Heapless(HeaplessEntry {
289                        key: Some(key),
290                        inner: self,
291                        index: len,
292                    }))
293                }
294            }
295            Self::Spilled(map) => match map.entry(key) {
296                std::collections::hash_map::Entry::Occupied(entry) => {
297                    Entry::Occupied(OccupiedEntry::Spilled(entry))
298                }
299                std::collections::hash_map::Entry::Vacant(entry) => {
300                    Entry::Vacant(VacantEntry::Spilled(entry))
301                }
302            },
303        }
304    }
305
306    #[inline]
307    pub fn get<Q>(&self, k: &Q) -> Option<&V>
308    where
309        K: Borrow<Q>,
310        Q: Hash + Eq + ?Sized,
311    {
312        match self.get_key_value(k) {
313            Some((_, value)) => Some(value),
314            None => None,
315        }
316    }
317
318    #[inline]
319    pub fn get_key_value<Q>(&self, k: &Q) -> Option<(&K, &V)>
320    where
321        K: Borrow<Q>,
322        Q: Hash + Eq + ?Sized,
323    {
324        match self {
325            Self::Heapless(vec) => {
326                if vec.is_empty() {
327                    None
328                } else {
329                    match vec.iter().find(|(key, _)| key.borrow() == k) {
330                        Some((key, value)) => Some((key, value)),
331                        None => None,
332                    }
333                }
334            }
335            Self::Spilled(map) => map.get_key_value(k),
336        }
337    }
338
339    #[cfg(feature = "many_mut")]
340    #[inline]
341    pub fn get_many_mut<Q, const M: usize>(&mut self, ks: [&Q; M]) -> Option<[&'_ mut V; M]>
342    where
343        K: Borrow<Q>,
344        Q: Hash + Eq + ?Sized,
345    {
346        match self {
347            Self::Heapless(vec) => {
348                let is =
349                    ks.map(|k| {
350                        vec.iter().enumerate().find_map(|(i, (key, _))| {
351                            if key.borrow() == k {
352                                Some(i)
353                            } else {
354                                None
355                            }
356                        })
357                    });
358                if is.iter().any(|i| i.is_none()) {
359                    return None;
360                }
361                let is = is.map(|i| unsafe { i.unwrap_unchecked() });
362                Some(vec.get_many_mut(is).ok()?.map(|(_, v)| v))
363            }
364            Self::Spilled(map) => map.get_many_mut(ks),
365        }
366    }
367
368    #[cfg(feature = "many_mut")]
369    #[inline]
370    pub unsafe fn get_many_unchecked_mut<Q, const M: usize>(
371        &mut self,
372        ks: [&Q; M],
373    ) -> Option<[&'_ mut V; M]>
374    where
375        K: Borrow<Q>,
376        Q: Hash + Eq + ?Sized,
377    {
378        match self {
379            Self::Heapless(vec) => {
380                let is =
381                    ks.map(|k| {
382                        vec.iter().enumerate().find_map(|(i, (key, _))| {
383                            if key.borrow() == k {
384                                Some(i)
385                            } else {
386                                None
387                            }
388                        })
389                    });
390                if is.iter().any(|i| i.is_none()) {
391                    return None;
392                }
393                let is = is.map(|i| unsafe { i.unwrap_unchecked() });
394                let es = unsafe { vec.get_many_unchecked_mut(is) };
395                Some(es.map(|(_, v)| v))
396            }
397            Self::Spilled(map) => unsafe { map.get_many_unchecked_mut(ks) },
398        }
399    }
400
401    #[inline]
402    pub fn contains_key<Q>(&self, k: &Q) -> bool
403    where
404        K: Borrow<Q>,
405        Q: Hash + Eq + ?Sized,
406    {
407        self.get(k).is_some()
408    }
409
410    #[inline]
411    pub fn get_mut<Q>(&mut self, k: &Q) -> Option<&mut V>
412    where
413        K: Borrow<Q>,
414        Q: Hash + Eq + ?Sized,
415    {
416        match self {
417            Self::Heapless(vec) => {
418                if vec.is_empty() {
419                    None
420                } else {
421                    match vec.iter_mut().find(|(key, _)| key.borrow() == k) {
422                        Some((_, value)) => Some(value),
423                        None => None,
424                    }
425                }
426            }
427            Self::Spilled(map) => map.get_mut(k),
428        }
429    }
430
431    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
432        match self {
433            Self::Heapless(vec) => {
434                // Scan for equivalent key
435                for (key, value) in vec.iter_mut() {
436                    if key == &k {
437                        return Some(std::mem::replace(value, v));
438                    }
439                }
440                // No equivalent key found, insert new entry
441                // find first None slot (previous removal)
442                match vec.push((k, v)) {
443                    Ok(()) => None,
444                    Err((k, v)) => {
445                        // No None slot found, spill to HashMap
446                        // Safety: we just checked the variant
447                        let map = unsafe { self.try_spill(1) };
448                        map.unwrap().insert(k, v);
449                        None
450                    }
451                }
452            }
453            Self::Spilled(m) => m.insert(k, v),
454        }
455    }
456
457    #[inline]
458    pub fn remove<Q>(&mut self, k: &Q) -> Option<V>
459    where
460        K: Borrow<Q>,
461        Q: Hash + Eq + ?Sized,
462    {
463        match self.remove_entry(k) {
464            Some((_, value)) => Some(value),
465            None => None,
466        }
467    }
468
469    #[inline]
470    pub fn remove_entry<Q>(&mut self, k: &Q) -> Option<(K, V)>
471    where
472        K: Borrow<Q>,
473        Q: Hash + Eq + ?Sized,
474    {
475        match self {
476            Self::Heapless(vec) => {
477                // find index
478                let index = vec.iter().position(|(key, _)| key.borrow() == k)?;
479                // Safety: index is in bounds
480                Some(unsafe { vec.swap_remove_unchecked(index) })
481            }
482            Self::Spilled(m) => m.remove_entry(k),
483        }
484    }
485
486    #[inline]
487    pub fn into_hashmap(mut self) -> HashMap<K, V> {
488        if !self.spilled() {
489            // Safety: we just checked the variant
490            unsafe { self.try_spill(0) }.unwrap();
491        }
492        // Safety: we just spilled the map
493        unsafe { self.into_spilled_unchecked() }
494    }
495
496    /// # Safety
497    ///
498    /// Must be in the `Heapless` variant.
499    #[inline]
500    unsafe fn try_spill(
501        &mut self,
502        additional: usize,
503    ) -> Result<&mut HashMap<K, V>, TryReserveError> {
504        let cap_needed = N
505            .checked_add(additional)
506            .ok_or(TryReserveError { kind: () })?;
507        let mut map = HashMap::new();
508        map.try_reserve(cap_needed)?;
509        let vec = std::mem::replace(self, Self::Spilled(map));
510        let (vec, map) = unsafe {
511            // Safety: we just swapped the variant
512            (
513                vec.into_heapless_unchecked(),
514                self.as_spilled_mut_unchecked(),
515            )
516        };
517        map.extend(vec);
518        Ok(map)
519    }
520
521    pub fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
522        if let MapImpl::Spilled(map) = self {
523            map.extend(iter);
524            return;
525        }
526        for (k, v) in iter {
527            self.insert(k, v);
528        }
529    }
530}
531
532impl<K, V, const N: usize> IntoIterator for MapImpl<K, V, N> {
533    type Item = (K, V);
534    type IntoIter = IntoIterInner<K, V, N>;
535
536    #[inline]
537    fn into_iter(self) -> IntoIterInner<K, V, N> {
538        match self {
539            MapImpl::Heapless(vec) => IntoIterInner::Heapless(vec),
540            MapImpl::Spilled(map) => IntoIterInner::Spilled(map.into_iter()),
541        }
542    }
543}
544
545impl<K, V, const N: usize, const M: usize> From<[(K, V); N]> for MapImpl<K, V, M>
546where
547    K: Eq + Hash,
548{
549    fn from(arr: [(K, V); N]) -> Self {
550        if N <= M {
551            Self::Heapless(heapless::Vec::from_iter(arr))
552        } else {
553            Self::Spilled(HashMap::from(arr))
554        }
555    }
556}
557
558/// The error type for `try_reserve` methods.
559#[derive(Clone, PartialEq, Eq, Debug)]
560pub struct TryReserveError {
561    kind: (),
562}
563
564impl From<std::collections::TryReserveError> for TryReserveError {
565    fn from(_: std::collections::TryReserveError) -> Self {
566        Self { kind: () }
567    }
568}
569
570impl Display for TryReserveError {
571    fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
572        fmt.write_str("memory allocation failed")
573    }
574}
575
576impl std::error::Error for TryReserveError {}