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}