heapless/
index_set.rs

1//! A fixed-capacity hash set where the iteration order is independent of the hash values.
2use core::{
3    borrow::Borrow,
4    fmt,
5    hash::{BuildHasher, Hash},
6};
7
8#[cfg(feature = "zeroize")]
9use zeroize::Zeroize;
10
11use hash32::{BuildHasherDefault, FnvHasher};
12
13use crate::index_map::{self, IndexMap};
14
15/// An [`IndexSet`] using the default FNV hasher.
16///
17/// A list of all Methods and Traits available for `FnvIndexSet` can be found in
18/// the [`IndexSet`] documentation.
19///
20/// # Examples
21/// ```
22/// use heapless::index_set::FnvIndexSet;
23///
24/// // A hash set with a capacity of 16 elements allocated on the stack
25/// let mut books = FnvIndexSet::<_, 16>::new();
26///
27/// // Add some books.
28/// books.insert("A Dance With Dragons").unwrap();
29/// books.insert("To Kill a Mockingbird").unwrap();
30/// books.insert("The Odyssey").unwrap();
31/// books.insert("The Great Gatsby").unwrap();
32///
33/// // Check for a specific one.
34/// if !books.contains("The Winds of Winter") {
35///     println!(
36///         "We have {} books, but The Winds of Winter ain't one.",
37///         books.len()
38///     );
39/// }
40///
41/// // Remove a book.
42/// books.remove("The Odyssey");
43///
44/// // Iterate over everything.
45/// for book in &books {
46///     println!("{}", book);
47/// }
48/// ```
49pub type FnvIndexSet<T, const N: usize> = IndexSet<T, BuildHasherDefault<FnvHasher>, N>;
50
51/// Fixed capacity [`IndexSet`](https://docs.rs/indexmap/2/indexmap/set/struct.IndexSet.html).
52///
53/// Note that you cannot use `IndexSet` directly, since it is generic around the hashing algorithm
54/// in use. Pick a concrete instantiation like [`FnvIndexSet`] instead
55/// or create your own.
56///
57/// Note that the capacity of the `IndexSet` must be a power of 2.
58///
59/// # Examples
60/// Since `IndexSet` cannot be used directly, we're using its `FnvIndexSet` instantiation
61/// for this example.
62///
63/// ```
64/// use heapless::index_set::FnvIndexSet;
65///
66/// // A hash set with a capacity of 16 elements allocated on the stack
67/// let mut books = FnvIndexSet::<_, 16>::new();
68///
69/// // Add some books.
70/// books.insert("A Dance With Dragons").unwrap();
71/// books.insert("To Kill a Mockingbird").unwrap();
72/// books.insert("The Odyssey").unwrap();
73/// books.insert("The Great Gatsby").unwrap();
74///
75/// // Check for a specific one.
76/// if !books.contains("The Winds of Winter") {
77///     println!(
78///         "We have {} books, but The Winds of Winter ain't one.",
79///         books.len()
80///     );
81/// }
82///
83/// // Remove a book.
84/// books.remove("The Odyssey");
85///
86/// // Iterate over everything.
87/// for book in &books {
88///     println!("{}", book);
89/// }
90/// ```
91#[cfg_attr(feature = "zeroize", derive(Zeroize), zeroize(bound = "T: Zeroize"))]
92pub struct IndexSet<T, S, const N: usize> {
93    map: IndexMap<T, (), S, N>,
94}
95
96impl<T, S, const N: usize> IndexSet<T, BuildHasherDefault<S>, N> {
97    /// Creates an empty `IndexSet`
98    pub const fn new() -> Self {
99        Self {
100            map: IndexMap::new(),
101        }
102    }
103}
104
105impl<T, S, const N: usize> IndexSet<T, S, N> {
106    /// Returns the number of elements the set can hold
107    ///
108    /// # Examples
109    ///
110    /// ```
111    /// use heapless::index_set::FnvIndexSet;
112    ///
113    /// let set = FnvIndexSet::<i32, 16>::new();
114    /// assert_eq!(set.capacity(), 16);
115    /// ```
116    pub fn capacity(&self) -> usize {
117        self.map.capacity()
118    }
119
120    /// Return an iterator over the values of the set, in insertion order
121    ///
122    /// # Examples
123    ///
124    /// ```
125    /// use heapless::index_set::FnvIndexSet;
126    ///
127    /// let mut set = FnvIndexSet::<_, 16>::new();
128    /// set.insert("a").unwrap();
129    /// set.insert("b").unwrap();
130    ///
131    /// // Will print in insertion order: a, b
132    /// for x in set.iter() {
133    ///     println!("{}", x);
134    /// }
135    /// ```
136    pub fn iter(&self) -> Iter<'_, T> {
137        Iter {
138            iter: self.map.iter(),
139        }
140    }
141
142    /// Get the first value
143    ///
144    /// Computes in *O*(1) time
145    pub fn first(&self) -> Option<&T> {
146        self.map.first().map(|(k, _v)| k)
147    }
148
149    /// Get the last value
150    ///
151    /// Computes in *O*(1) time
152    pub fn last(&self) -> Option<&T> {
153        self.map.last().map(|(k, _v)| k)
154    }
155
156    /// Returns the number of elements in the set.
157    ///
158    /// # Examples
159    ///
160    /// ```
161    /// use heapless::index_set::FnvIndexSet;
162    ///
163    /// let mut v: FnvIndexSet<_, 16> = FnvIndexSet::new();
164    /// assert_eq!(v.len(), 0);
165    /// v.insert(1).unwrap();
166    /// assert_eq!(v.len(), 1);
167    /// ```
168    pub fn len(&self) -> usize {
169        self.map.len()
170    }
171
172    /// Returns `true` if the set contains no elements.
173    ///
174    /// # Examples
175    ///
176    /// ```
177    /// use heapless::index_set::FnvIndexSet;
178    ///
179    /// let mut v: FnvIndexSet<_, 16> = FnvIndexSet::new();
180    /// assert!(v.is_empty());
181    /// v.insert(1).unwrap();
182    /// assert!(!v.is_empty());
183    /// ```
184    pub fn is_empty(&self) -> bool {
185        self.map.is_empty()
186    }
187
188    /// Returns `true` if the set is full.
189    ///
190    /// # Examples
191    ///
192    /// ```
193    /// use heapless::index_set::FnvIndexSet;
194    ///
195    /// let mut v: FnvIndexSet<_, 4> = FnvIndexSet::new();
196    /// assert!(!v.is_full());
197    /// v.insert(1).unwrap();
198    /// v.insert(2).unwrap();
199    /// v.insert(3).unwrap();
200    /// v.insert(4).unwrap();
201    /// assert!(v.is_full());
202    /// ```
203    pub fn is_full(&self) -> bool {
204        self.map.is_full()
205    }
206
207    /// Clears the set, removing all values.
208    ///
209    /// # Examples
210    ///
211    /// ```
212    /// use heapless::index_set::FnvIndexSet;
213    ///
214    /// let mut v: FnvIndexSet<_, 16> = FnvIndexSet::new();
215    /// v.insert(1).unwrap();
216    /// v.clear();
217    /// assert!(v.is_empty());
218    /// ```
219    pub fn clear(&mut self) {
220        self.map.clear();
221    }
222}
223
224impl<T, S, const N: usize> IndexSet<T, S, N>
225where
226    T: Eq + Hash,
227    S: BuildHasher,
228{
229    /// Visits the values representing the difference, i.e. the values that are in `self` but not in
230    /// `other`.
231    ///
232    /// # Examples
233    ///
234    /// ```
235    /// use heapless::index_set::FnvIndexSet;
236    ///
237    /// let mut a: FnvIndexSet<_, 16> = [1, 2, 3].iter().cloned().collect();
238    /// let mut b: FnvIndexSet<_, 16> = [4, 2, 3, 4].iter().cloned().collect();
239    ///
240    /// // Can be seen as `a - b`.
241    /// for x in a.difference(&b) {
242    ///     println!("{}", x); // Print 1
243    /// }
244    ///
245    /// let diff: FnvIndexSet<_, 16> = a.difference(&b).collect();
246    /// assert_eq!(diff, [1].iter().collect::<FnvIndexSet<_, 16>>());
247    ///
248    /// // Note that difference is not symmetric,
249    /// // and `b - a` means something else:
250    /// let diff: FnvIndexSet<_, 16> = b.difference(&a).collect();
251    /// assert_eq!(diff, [4].iter().collect::<FnvIndexSet<_, 16>>());
252    /// ```
253    pub fn difference<'a, S2, const N2: usize>(
254        &'a self,
255        other: &'a IndexSet<T, S2, N2>,
256    ) -> Difference<'a, T, S2, N2>
257    where
258        S2: BuildHasher,
259    {
260        Difference {
261            iter: self.iter(),
262            other,
263        }
264    }
265
266    /// Visits the values representing the symmetric difference, i.e. the values that are in `self`
267    /// or in `other` but not in both.
268    ///
269    /// # Examples
270    ///
271    /// ```
272    /// use heapless::index_set::FnvIndexSet;
273    ///
274    /// let mut a: FnvIndexSet<_, 16> = [1, 2, 3].iter().cloned().collect();
275    /// let mut b: FnvIndexSet<_, 16> = [4, 2, 3, 4].iter().cloned().collect();
276    ///
277    /// // Print 1, 4 in that order.
278    /// for x in a.symmetric_difference(&b) {
279    ///     println!("{}", x);
280    /// }
281    ///
282    /// let diff1: FnvIndexSet<_, 16> = a.symmetric_difference(&b).collect();
283    /// let diff2: FnvIndexSet<_, 16> = b.symmetric_difference(&a).collect();
284    ///
285    /// assert_eq!(diff1, diff2);
286    /// assert_eq!(diff1, [1, 4].iter().collect::<FnvIndexSet<_, 16>>());
287    /// ```
288    pub fn symmetric_difference<'a, S2, const N2: usize>(
289        &'a self,
290        other: &'a IndexSet<T, S2, N2>,
291    ) -> impl Iterator<Item = &'a T>
292    where
293        S2: BuildHasher,
294    {
295        self.difference(other).chain(other.difference(self))
296    }
297
298    /// Visits the values representing the intersection, i.e. the values that are both in `self` and
299    /// `other`.
300    ///
301    /// # Examples
302    ///
303    /// ```
304    /// use heapless::index_set::FnvIndexSet;
305    ///
306    /// let mut a: FnvIndexSet<_, 16> = [1, 2, 3].iter().cloned().collect();
307    /// let mut b: FnvIndexSet<_, 16> = [4, 2, 3, 4].iter().cloned().collect();
308    ///
309    /// // Print 2, 3 in that order.
310    /// for x in a.intersection(&b) {
311    ///     println!("{}", x);
312    /// }
313    ///
314    /// let intersection: FnvIndexSet<_, 16> = a.intersection(&b).collect();
315    /// assert_eq!(intersection, [2, 3].iter().collect::<FnvIndexSet<_, 16>>());
316    /// ```
317    pub fn intersection<'a, S2, const N2: usize>(
318        &'a self,
319        other: &'a IndexSet<T, S2, N2>,
320    ) -> Intersection<'a, T, S2, N2>
321    where
322        S2: BuildHasher,
323    {
324        Intersection {
325            iter: self.iter(),
326            other,
327        }
328    }
329
330    /// Visits the values representing the union, i.e. all the values in `self` or `other`, without
331    /// duplicates.
332    ///
333    /// # Examples
334    ///
335    /// ```
336    /// use heapless::index_set::FnvIndexSet;
337    ///
338    /// let mut a: FnvIndexSet<_, 16> = [1, 2, 3].iter().cloned().collect();
339    /// let mut b: FnvIndexSet<_, 16> = [4, 2, 3, 4].iter().cloned().collect();
340    ///
341    /// // Print 1, 2, 3, 4 in that order.
342    /// for x in a.union(&b) {
343    ///     println!("{}", x);
344    /// }
345    ///
346    /// let union: FnvIndexSet<_, 16> = a.union(&b).collect();
347    /// assert_eq!(union, [1, 2, 3, 4].iter().collect::<FnvIndexSet<_, 16>>());
348    /// ```
349    pub fn union<'a, S2, const N2: usize>(
350        &'a self,
351        other: &'a IndexSet<T, S2, N2>,
352    ) -> impl Iterator<Item = &'a T>
353    where
354        S2: BuildHasher,
355    {
356        self.iter().chain(other.difference(self))
357    }
358
359    /// Returns `true` if the set contains a value.
360    ///
361    /// The value may be any borrowed form of the set's value type, but `Hash` and `Eq` on the
362    /// borrowed form must match those for the value type.
363    ///
364    /// # Examples
365    ///
366    /// ```
367    /// use heapless::index_set::FnvIndexSet;
368    ///
369    /// let set: FnvIndexSet<_, 16> = [1, 2, 3].iter().cloned().collect();
370    /// assert_eq!(set.contains(&1), true);
371    /// assert_eq!(set.contains(&4), false);
372    /// ```
373    pub fn contains<Q>(&self, value: &Q) -> bool
374    where
375        T: Borrow<Q>,
376        Q: ?Sized + Eq + Hash,
377    {
378        self.map.contains_key(value)
379    }
380
381    /// Returns `true` if `self` has no elements in common with `other`. This is equivalent to
382    /// checking for an empty intersection.
383    ///
384    /// # Examples
385    ///
386    /// ```
387    /// use heapless::index_set::FnvIndexSet;
388    ///
389    /// let a: FnvIndexSet<_, 16> = [1, 2, 3].iter().cloned().collect();
390    /// let mut b = FnvIndexSet::<_, 16>::new();
391    ///
392    /// assert_eq!(a.is_disjoint(&b), true);
393    /// b.insert(4).unwrap();
394    /// assert_eq!(a.is_disjoint(&b), true);
395    /// b.insert(1).unwrap();
396    /// assert_eq!(a.is_disjoint(&b), false);
397    /// ```
398    pub fn is_disjoint<S2, const N2: usize>(&self, other: &IndexSet<T, S2, N2>) -> bool
399    where
400        S2: BuildHasher,
401    {
402        self.iter().all(|v| !other.contains(v))
403    }
404
405    /// Returns `true` if the set is a subset of another, i.e. `other` contains at least all the
406    /// values in `self`.
407    ///
408    /// # Examples
409    ///
410    /// ```
411    /// use heapless::index_set::FnvIndexSet;
412    ///
413    /// let sup: FnvIndexSet<_, 16> = [1, 2, 3].iter().cloned().collect();
414    /// let mut set = FnvIndexSet::<_, 16>::new();
415    ///
416    /// assert_eq!(set.is_subset(&sup), true);
417    /// set.insert(2).unwrap();
418    /// assert_eq!(set.is_subset(&sup), true);
419    /// set.insert(4).unwrap();
420    /// assert_eq!(set.is_subset(&sup), false);
421    /// ```
422    pub fn is_subset<S2, const N2: usize>(&self, other: &IndexSet<T, S2, N2>) -> bool
423    where
424        S2: BuildHasher,
425    {
426        self.iter().all(|v| other.contains(v))
427    }
428
429    // Returns `true` if the set is a superset of another, i.e. `self` contains at least all the
430    // values in `other`.
431    ///
432    /// # Examples
433    ///
434    /// ```
435    /// use heapless::index_set::FnvIndexSet;
436    ///
437    /// let sub: FnvIndexSet<_, 16> = [1, 2].iter().cloned().collect();
438    /// let mut set = FnvIndexSet::<_, 16>::new();
439    ///
440    /// assert_eq!(set.is_superset(&sub), false);
441    ///
442    /// set.insert(0).unwrap();
443    /// set.insert(1).unwrap();
444    /// assert_eq!(set.is_superset(&sub), false);
445    ///
446    /// set.insert(2).unwrap();
447    /// assert_eq!(set.is_superset(&sub), true);
448    /// ```
449    pub fn is_superset<S2, const N2: usize>(&self, other: &IndexSet<T, S2, N2>) -> bool
450    where
451        S2: BuildHasher,
452    {
453        other.is_subset(self)
454    }
455
456    /// Adds a value to the set.
457    ///
458    /// If the set did not have this value present, `true` is returned.
459    ///
460    /// If the set did have this value present, `false` is returned.
461    ///
462    /// # Examples
463    ///
464    /// ```
465    /// use heapless::index_set::FnvIndexSet;
466    ///
467    /// let mut set = FnvIndexSet::<_, 16>::new();
468    ///
469    /// assert_eq!(set.insert(2).unwrap(), true);
470    /// assert_eq!(set.insert(2).unwrap(), false);
471    /// assert_eq!(set.len(), 1);
472    /// ```
473    pub fn insert(&mut self, value: T) -> Result<bool, T> {
474        self.map
475            .insert(value, ())
476            .map(|old| old.is_none())
477            .map_err(|(k, _)| k)
478    }
479
480    /// Removes a value from the set. Returns `true` if the value was present in the set.
481    ///
482    /// The value may be any borrowed form of the set's value type, but `Hash` and `Eq` on the
483    /// borrowed form must match those for the value type.
484    ///
485    /// # Examples
486    ///
487    /// ```
488    /// use heapless::index_set::FnvIndexSet;
489    ///
490    /// let mut set = FnvIndexSet::<_, 16>::new();
491    ///
492    /// set.insert(2).unwrap();
493    /// assert_eq!(set.remove(&2), true);
494    /// assert_eq!(set.remove(&2), false);
495    /// ```
496    pub fn remove<Q>(&mut self, value: &Q) -> bool
497    where
498        T: Borrow<Q>,
499        Q: ?Sized + Eq + Hash,
500    {
501        self.map.remove(value).is_some()
502    }
503
504    /// Retains only the elements specified by the predicate.
505    ///
506    /// In other words, remove all elements `e` for which `f(&e)` returns `false`.
507    pub fn retain<F>(&mut self, mut f: F)
508    where
509        F: FnMut(&T) -> bool,
510    {
511        self.map.retain(move |k, _| f(k));
512    }
513}
514
515impl<T, S, const N: usize> Clone for IndexSet<T, S, N>
516where
517    T: Clone,
518    S: Clone,
519{
520    fn clone(&self) -> Self {
521        Self {
522            map: self.map.clone(),
523        }
524    }
525}
526
527impl<T, S, const N: usize> fmt::Debug for IndexSet<T, S, N>
528where
529    T: fmt::Debug,
530{
531    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
532        f.debug_set().entries(self.iter()).finish()
533    }
534}
535
536impl<T, S, const N: usize> Default for IndexSet<T, S, N>
537where
538    S: Default,
539{
540    fn default() -> Self {
541        Self {
542            map: <_>::default(),
543        }
544    }
545}
546
547impl<T, S1, S2, const N1: usize, const N2: usize> PartialEq<IndexSet<T, S2, N2>>
548    for IndexSet<T, S1, N1>
549where
550    T: Eq + Hash,
551    S1: BuildHasher,
552    S2: BuildHasher,
553{
554    fn eq(&self, other: &IndexSet<T, S2, N2>) -> bool {
555        self.len() == other.len() && self.is_subset(other)
556    }
557}
558
559impl<T, S, const N: usize> Extend<T> for IndexSet<T, S, N>
560where
561    T: Eq + Hash,
562    S: BuildHasher,
563{
564    fn extend<I>(&mut self, iterable: I)
565    where
566        I: IntoIterator<Item = T>,
567    {
568        self.map.extend(iterable.into_iter().map(|k| (k, ())));
569    }
570}
571
572impl<'a, T, S, const N: usize> Extend<&'a T> for IndexSet<T, S, N>
573where
574    T: 'a + Eq + Hash + Copy,
575    S: BuildHasher,
576{
577    fn extend<I>(&mut self, iterable: I)
578    where
579        I: IntoIterator<Item = &'a T>,
580    {
581        self.extend(iterable.into_iter().cloned());
582    }
583}
584
585impl<T, S, const N: usize> FromIterator<T> for IndexSet<T, S, N>
586where
587    T: Eq + Hash,
588    S: BuildHasher + Default,
589{
590    fn from_iter<I>(iter: I) -> Self
591    where
592        I: IntoIterator<Item = T>,
593    {
594        let mut set = Self::default();
595        set.extend(iter);
596        set
597    }
598}
599
600impl<'a, T, S, const N: usize> IntoIterator for &'a IndexSet<T, S, N>
601where
602    T: Eq + Hash,
603    S: BuildHasher,
604{
605    type Item = &'a T;
606    type IntoIter = Iter<'a, T>;
607
608    fn into_iter(self) -> Self::IntoIter {
609        self.iter()
610    }
611}
612
613/// An iterator over the items of a [`IndexSet`].
614///
615/// This `struct` is created by the [`iter`](IndexSet::iter) method on [`IndexSet`]. See its
616/// documentation for more.
617pub struct Iter<'a, T> {
618    iter: index_map::Iter<'a, T, ()>,
619}
620
621impl<'a, T> Iterator for Iter<'a, T> {
622    type Item = &'a T;
623
624    fn next(&mut self) -> Option<Self::Item> {
625        self.iter.next().map(|(k, _)| k)
626    }
627}
628
629impl<T> Clone for Iter<'_, T> {
630    fn clone(&self) -> Self {
631        Self {
632            iter: self.iter.clone(),
633        }
634    }
635}
636
637/// An iterator over the difference of two `IndexSet`s.
638///
639/// This is created by the [`IndexSet::difference`] method.
640pub struct Difference<'a, T, S, const N: usize>
641where
642    S: BuildHasher,
643    T: Eq + Hash,
644{
645    iter: Iter<'a, T>,
646    other: &'a IndexSet<T, S, N>,
647}
648
649impl<'a, T, S, const N: usize> Iterator for Difference<'a, T, S, N>
650where
651    S: BuildHasher,
652    T: Eq + Hash,
653{
654    type Item = &'a T;
655
656    fn next(&mut self) -> Option<Self::Item> {
657        loop {
658            let elt = self.iter.next()?;
659            if !self.other.contains(elt) {
660                return Some(elt);
661            }
662        }
663    }
664}
665
666/// An iterator over the intersection of two `IndexSet`s.
667///
668/// This is created by the [`IndexSet::intersection`] method.
669pub struct Intersection<'a, T, S, const N: usize>
670where
671    S: BuildHasher,
672    T: Eq + Hash,
673{
674    iter: Iter<'a, T>,
675    other: &'a IndexSet<T, S, N>,
676}
677
678impl<'a, T, S, const N: usize> Iterator for Intersection<'a, T, S, N>
679where
680    S: BuildHasher,
681    T: Eq + Hash,
682{
683    type Item = &'a T;
684
685    fn next(&mut self) -> Option<Self::Item> {
686        loop {
687            let elt = self.iter.next()?;
688            if self.other.contains(elt) {
689                return Some(elt);
690            }
691        }
692    }
693}
694
695#[cfg(test)]
696mod tests {
697    use static_assertions::assert_not_impl_any;
698
699    use super::{BuildHasherDefault, IndexSet};
700
701    // Ensure a `IndexSet` containing `!Send` values stays `!Send` itself.
702    assert_not_impl_any!(IndexSet<*const (), BuildHasherDefault<()>, 4>: Send);
703
704    #[test]
705    #[cfg(feature = "zeroize")]
706    fn test_index_set_zeroize() {
707        use zeroize::Zeroize;
708
709        let mut set: IndexSet<u8, BuildHasherDefault<hash32::FnvHasher>, 8> = IndexSet::new();
710        for i in 1..=8 {
711            set.insert(i).unwrap();
712        }
713
714        assert_eq!(set.len(), 8);
715        assert!(set.contains(&8));
716
717        // zeroized using index_map's implementation
718        set.zeroize();
719
720        assert_eq!(set.len(), 0);
721        assert!(set.is_empty());
722
723        set.insert(1).unwrap();
724        assert_eq!(set.len(), 1);
725        assert!(set.contains(&1));
726    }
727}