1#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
5pub struct SparseSet<T> {
6 sparse: Vec<usize>,
7 dense: Vec<T>,
8}
9
10impl<T> SparseSet<T> {
11 const NULL_INDEX: usize = usize::MAX;
12
13 pub fn new() -> Self {
15 Self {
16 sparse: Vec::new(),
17 dense: Vec::new(),
18 }
19 }
20
21 pub fn insert(&mut self, index: usize, value: T) {
23 if self.sparse.len() + index > self.sparse.capacity() {
24 self.sparse.reserve(index.max(4));
25 }
26 self.sparse.insert(index, self.dense.len());
27 self.dense.push(value);
28 }
29
30 pub fn get(&self, index: usize) -> Option<&T> {
32 if index == Self::NULL_INDEX {
33 None
34 } else if let Some(i) = self.sparse.get(index).copied() {
35 self.dense.get(i)
36 } else {
37 None
38 }
39 }
40
41 pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
43 if index == Self::NULL_INDEX {
44 None
45 } else if let Some(i) = self.sparse.get(index).copied() {
46 self.dense.get_mut(i)
47 } else {
48 None
49 }
50 }
51
52 pub fn remove(&mut self, index: usize) {
54 if self.dense.is_empty() {
55 return;
56 }
57
58 let Some(dense_index) = self.sparse.get(index).copied() else {
59 return;
60 };
61
62 let back = self.dense.len() - 1;
63 self.dense.swap(dense_index, back);
64 self.dense.remove(back);
65 self.sparse[index] = Self::NULL_INDEX;
66 self.sparse[back] = index;
67 }
68}
69
70impl<T> Default for SparseSet<T> {
71 fn default() -> Self {
72 Self {
73 sparse: Vec::new(),
74 dense: Vec::new(),
75 }
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use std::time::SystemTime;
82
83 use super::*;
84
85 #[test]
86 fn basic() {
87 const N: usize = 1000000;
88 let time = SystemTime::now();
89 let mut set = SparseSet::new();
90
91 let mut remove = vec![];
94 for i in 0..=N {
95 set.insert(i, format!("Hello #{i}"));
96
97 if i % 153 == 0 {
98 remove.push(i);
99 }
100 }
101
102 for i in &remove {
105 set.remove(*i);
106 }
107 let dur = time.elapsed().unwrap();
108 println!("Time took: {}ms:{}ns", dur.as_millis(), dur.as_nanos());
109 remove.clear();
110
111 let mut hash = std::collections::HashMap::new();
112 let time = SystemTime::now();
113 for i in 0..=N {
114 hash.insert(i, format!("Hello #{i}"));
115
116 if i % 153 == 0 {
117 remove.push(i);
118 }
119 }
120
121 for i in &remove {
122 hash.remove(i);
123 }
124
125 let dur = time.elapsed().unwrap();
126 println!("Time took: {}ms:{}ns", dur.as_millis(), dur.as_nanos());
127 }
128}