crdt_richtext/
small_set.rs1use fxhash::FxHashSet;
2const STACK_LEN: usize = 4;
3
4#[derive(Debug, Clone)]
16pub enum SmallSetI32 {
17 Stack(([i32; STACK_LEN], u8)),
18 Heap(FxHashSet<i32>),
19}
20
21impl Default for SmallSetI32 {
22 fn default() -> Self {
23 Self::new()
24 }
25}
26
27impl SmallSetI32 {
28 const EMPTY_VALUE: i32 = 0;
29 pub(crate) fn new() -> Self {
30 SmallSetI32::Stack(([Self::EMPTY_VALUE; STACK_LEN], 0))
31 }
32
33 pub(crate) fn insert(&mut self, value: i32) {
34 assert!(value != 0);
35 if self.contains(-value) {
36 self.remove(-value);
37 return;
38 }
39
40 match self {
41 SmallSetI32::Stack((stack, size)) => {
42 for entry in stack.iter() {
43 if *entry == value {
44 return;
46 }
47 }
48
49 for entry in stack.iter_mut() {
50 if *entry == Self::EMPTY_VALUE {
51 *entry = value;
52 *size += 1;
53 return;
54 }
55 }
56
57 let mut set =
58 FxHashSet::with_capacity_and_hasher(STACK_LEN * 2, Default::default());
59
60 for &v in stack.iter() {
61 set.insert(v);
63 }
64 set.insert(value);
65 *self = SmallSetI32::Heap(set);
66 }
67 SmallSetI32::Heap(set) => {
68 set.insert(value);
69 }
70 }
71 }
72
73 pub(crate) fn contains(&self, value: i32) -> bool {
74 if value == 0 {
75 return false;
76 }
77
78 match self {
79 SmallSetI32::Stack((stack, size)) => {
80 if *size == 0 {
81 return false;
82 }
83
84 for entry in stack.iter() {
85 if *entry == value {
86 return true;
87 }
88 }
89
90 false
91 }
92 SmallSetI32::Heap(set) => set.contains(&value),
93 }
94 }
95
96 pub(crate) fn remove(&mut self, value: i32) {
97 match self {
98 SmallSetI32::Stack((stack, size)) => {
99 if *size == 0 {
100 return;
101 }
102
103 for entry in stack.iter_mut() {
104 if *entry == value {
105 *entry = Self::EMPTY_VALUE;
106 *size -= 1;
107 }
108 }
109 }
110 SmallSetI32::Heap(set) => {
111 set.remove(&value);
112 }
113 }
114 }
115
116 pub(crate) fn iter(&self) -> SmallSetIter {
117 match self {
118 SmallSetI32::Stack((stack, _)) => SmallSetIter::Stack(stack.iter()),
119 SmallSetI32::Heap(set) => SmallSetIter::Heap(set.iter()),
120 }
121 }
122
123 pub(crate) fn len(&self) -> usize {
124 match self {
125 SmallSetI32::Stack((_, size)) => *size as usize,
126 SmallSetI32::Heap(set) => set.len(),
127 }
128 }
129
130 pub(crate) fn is_empty(&self) -> bool {
131 self.len() == 0
132 }
133}
134
135pub(crate) enum SmallSetIter<'a> {
136 Stack(std::slice::Iter<'a, i32>),
137 Heap(std::collections::hash_set::Iter<'a, i32>),
138}
139
140impl<'a> Iterator for SmallSetIter<'a> {
141 type Item = i32;
142
143 fn next(&mut self) -> Option<Self::Item> {
144 match self {
145 SmallSetIter::Stack(iter) => {
146 let mut ans = iter.next();
147 while ans == Some(&SmallSetI32::EMPTY_VALUE) {
148 ans = iter.next();
149 }
150 ans.copied()
151 }
152 SmallSetIter::Heap(iter) => iter.next().copied(),
153 }
154 }
155}
156
157#[cfg(test)]
158mod test {
159 use super::SmallSetI32;
160
161 #[test]
162 fn test() {
163 let mut set = SmallSetI32::new();
164 set.insert(1);
165 set.insert(2);
166 set.insert(2);
167 set.insert(2);
168 set.insert(1);
169 assert_eq!(set.len(), 2);
170 assert!(set.contains(2));
171 assert!(set.contains(1));
172 assert!(!set.contains(0));
173 assert!(!set.contains(-2));
174 set.remove(2);
175 assert!(!set.contains(2));
176 assert!(set.len() == 1);
177 }
178
179 #[test]
180 fn smallset_size() {
181 assert_eq!(32, std::mem::size_of::<SmallSetI32>());
182 }
183}