Skip to main content

kevy_map/
into_iter.rs

1//! Owning iteration over a [`KevyMap`] / [`crate::KevySet`], and the
2//! equality both collections compare by.
3
4use core::fmt;
5use core::ptr;
6
7use kevy_hash::KevyHash;
8
9use crate::map::{EMPTY, KevyMap};
10
11/// `(K, V)` iterator that consumes a [`KevyMap`]; order unspecified.
12/// Entries not yet yielded are dropped with the iterator.
13///
14/// ```
15/// let m: kevy_map::KevyMap<u64, &str> = [(1, "a"), (2, "b")].into_iter().collect();
16/// let mut pairs: Vec<(u64, &str)> = m.into_iter().collect();
17/// pairs.sort();
18/// assert_eq!(pairs, [(1, "a"), (2, "b")]);
19/// ```
20pub struct IntoIter<K, V> {
21    map: KevyMap<K, V>,
22    pos: usize,
23}
24
25impl<K, V> IntoIter<K, V> {
26    pub(crate) fn new(map: KevyMap<K, V>) -> Self {
27        IntoIter { map, pos: 0 }
28    }
29}
30
31impl<K, V> Iterator for IntoIter<K, V> {
32    type Item = (K, V);
33
34    fn next(&mut self) -> Option<(K, V)> {
35        while self.pos < self.map.cap {
36            let i = self.pos;
37            self.pos += 1;
38            // SAFETY: i < cap, so the metadata byte is in bounds.
39            let meta = unsafe { self.map.metadata_ptr.as_ptr().add(i) };
40            // SAFETY: as above; the byte is initialised from allocation on.
41            if unsafe { *meta } & 0x80 == 0 {
42                // the slot is marked empty before its entry leaves, so the
43                // map's Drop never sees it again: moved out exactly once
44                // SAFETY: in bounds as above.
45                unsafe { *meta = EMPTY };
46                self.map.occupied -= 1;
47                // SAFETY: a full slot holds an initialised (K, V).
48                return Some(unsafe { ptr::read(self.map.slots_ptr.as_ptr().add(i).cast()) });
49            }
50        }
51        None
52    }
53
54    fn size_hint(&self) -> (usize, Option<usize>) {
55        (self.map.occupied, Some(self.map.occupied))
56    }
57}
58
59impl<K, V> ExactSizeIterator for IntoIter<K, V> {}
60
61impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for IntoIter<K, V> {
62    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63        f.debug_struct("IntoIter").field("remaining", &self.map.occupied).finish_non_exhaustive()
64    }
65}
66
67impl<K, V> IntoIterator for KevyMap<K, V> {
68    type Item = (K, V);
69    type IntoIter = IntoIter<K, V>;
70
71    fn into_iter(self) -> IntoIter<K, V> {
72        IntoIter::new(self)
73    }
74}
75
76/// Two maps are equal when they hold the same keys, each with an equal
77/// value — capacity and probe layout do not matter.
78///
79/// ```
80/// use kevy_map::KevyMap;
81/// let a: KevyMap<u64, u8> = [(1, 1), (2, 2)].into_iter().collect();
82/// let mut b = KevyMap::with_capacity(64);
83/// b.insert(2, 2);
84/// b.insert(1, 1);
85/// assert_eq!(a, b);
86/// b.insert(3, 3);
87/// assert_ne!(a, b);
88/// ```
89impl<K, V> PartialEq for KevyMap<K, V>
90where
91    K: KevyHash + Eq,
92    V: PartialEq,
93{
94    fn eq(&self, other: &Self) -> bool {
95        self.len() == other.len() && self.iter().all(|(k, v)| other.get(k) == Some(v))
96    }
97}
98
99impl<K: KevyHash + Eq, V: Eq> Eq for KevyMap<K, V> {}