typst_utils/listset.rs
1use std::ops::DerefMut;
2
3/// Picked by gut feeling. Could probably even be a bit larger.
4const CUT_OFF: usize = 15;
5
6/// A set backed by a mutable slice-like data structure.
7///
8/// This data structure uses two different strategies depending on size:
9///
10/// - When the list is small, it is just kept as is and searched linearly in
11/// [`contains`](Self::contains).
12///
13/// - When the list is a bit bigger, it's sorted in [`new`](Self::new) and then
14/// binary-searched for containment checks.
15pub struct ListSet<S>(S);
16
17impl<T, S> ListSet<S>
18where
19 S: DerefMut<Target = [T]>,
20 T: Ord,
21{
22 /// Creates a new list set.
23 ///
24 /// If the list is longer than the cutoff point, it is sorted.
25 pub fn new(mut list: S) -> Self {
26 if list.len() > CUT_OFF {
27 list.sort_unstable();
28 }
29 Self(list)
30 }
31
32 /// Whether the set contains no elements.
33 pub fn is_empty(&self) -> bool {
34 self.0.is_empty()
35 }
36
37 /// Checks whether the set contains the given value.
38 ///
39 /// If the list is shorter than the cutoff point, performs a linear search.
40 /// If it is longer, performs a binary search.
41 pub fn contains(&self, value: &T) -> bool {
42 if self.0.len() > CUT_OFF {
43 self.0.binary_search(value).is_ok()
44 } else {
45 self.0.contains(value)
46 }
47 }
48}