sim_lib_sequence/mutable/
sparse.rs1#[derive(Clone, Copy, Debug, Eq, PartialEq)]
3pub enum SparseSequenceError {
4 LengthLimit {
6 requested: usize,
8 limit: usize,
10 },
11 IndexOverflow {
13 index: usize,
15 },
16}
17impl fmt::Display for SparseSequenceError {
18 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
19 match self {
20 Self::LengthLimit { requested, limit } => {
21 write!(
22 formatter,
23 "sparse sequence length {requested} exceeds limit {limit}"
24 )
25 }
26 Self::IndexOverflow { index } => {
27 write!(
28 formatter,
29 "sparse sequence index {index} cannot grow the length"
30 )
31 }
32 }
33 }
34}
35
36impl std::error::Error for SparseSequenceError {}
37
38#[derive(Clone, Debug)]
45pub struct SparseSequence<T> {
46 chunks: BTreeMap<usize, Box<[Option<T>; CHUNK_LEN]>>,
47 len: usize,
48 occupied: usize,
49 max_len: usize,
50 revision: u64,
51}
52
53impl<T: PartialEq> PartialEq for SparseSequence<T> {
54 fn eq(&self, other: &Self) -> bool {
55 self.len == other.len
56 && self.occupied == other.occupied
57 && self.occupied_in(..).eq(other.occupied_in(..))
58 }
59}
60
61impl<T: Eq> Eq for SparseSequence<T> {}
62
63impl<T> SparseSequence<T> {
64 pub fn new(max_len: usize) -> Self {
66 Self {
67 chunks: BTreeMap::new(),
68 len: 0,
69 occupied: 0,
70 max_len,
71 revision: 0,
72 }
73 }
74
75 pub fn len(&self) -> usize {
77 self.len
78 }
79
80 pub fn is_empty(&self) -> bool {
82 self.len == 0
83 }
84
85 pub fn max_len(&self) -> usize {
87 self.max_len
88 }
89
90 pub fn occupied_len(&self) -> usize {
92 self.occupied
93 }
94
95 pub fn revision(&self) -> u64 {
101 self.revision
102 }
103
104 pub fn get(&self, index: usize) -> Option<&T> {
106 if index >= self.len {
107 return None;
108 }
109 let (chunk, offset) = split_index(index);
110 self.chunks.get(&chunk)?.get(offset)?.as_ref()
111 }
112
113 pub fn contains_index(&self, index: usize) -> bool {
115 self.get(index).is_some()
116 }
117
118 pub fn set(&mut self, index: usize, value: T) -> Result<Option<T>, SparseSequenceError> {
122 let required_len = index
123 .checked_add(1)
124 .ok_or(SparseSequenceError::IndexOverflow { index })?;
125 self.check_len(required_len)?;
126
127 let (chunk_index, offset) = split_index(index);
128 let chunk = self
129 .chunks
130 .entry(chunk_index)
131 .or_insert_with(|| Box::new(std::array::from_fn(|_| None)));
132 let previous = chunk[offset].replace(value);
133 if previous.is_none() {
134 self.occupied += 1;
135 }
136 self.len = self.len.max(required_len);
137 self.bump_revision();
138 Ok(previous)
139 }
140
141 pub fn remove(&mut self, index: usize) -> Option<T> {
143 if index >= self.len {
144 return None;
145 }
146 let (chunk_index, offset) = split_index(index);
147 let chunk = self.chunks.get_mut(&chunk_index)?;
148 let removed = chunk[offset].take()?;
149 self.occupied -= 1;
150 if chunk.iter().all(Option::is_none) {
151 self.chunks.remove(&chunk_index);
152 }
153 self.bump_revision();
154 Some(removed)
155 }
156
157 pub fn set_len(&mut self, new_len: usize) -> Result<(), SparseSequenceError> {
160 self.check_len(new_len)?;
161 if new_len == self.len {
162 return Ok(());
163 }
164 if new_len < self.len {
165 self.truncate_values(new_len);
166 }
167 self.len = new_len;
168 self.bump_revision();
169 Ok(())
170 }
171
172 pub fn occupied_in<R>(&self, range: R) -> impl Iterator<Item = (usize, &T)>
177 where
178 R: RangeBounds<usize>,
179 {
180 let start = match range.start_bound() {
181 Bound::Included(index) => *index,
182 Bound::Excluded(index) => index.saturating_add(1),
183 Bound::Unbounded => 0,
184 }
185 .min(self.len);
186 let end = match range.end_bound() {
187 Bound::Included(index) => index.saturating_add(1),
188 Bound::Excluded(index) => *index,
189 Bound::Unbounded => self.len,
190 }
191 .min(self.len)
192 .max(start);
193 let first_chunk = start / CHUNK_LEN;
194 let end_chunk = end / CHUNK_LEN + usize::from(end % CHUNK_LEN != 0);
195
196 self.chunks
197 .range(first_chunk..end_chunk)
198 .flat_map(move |(chunk_index, chunk)| {
199 chunk.iter().enumerate().filter_map(move |(offset, value)| {
200 let index = chunk_index * CHUNK_LEN + offset;
201 (start..end)
202 .contains(&index)
203 .then(|| value.as_ref().map(|value| (index, value)))
204 .flatten()
205 })
206 })
207 }
208
209 fn check_len(&self, requested: usize) -> Result<(), SparseSequenceError> {
210 if requested > self.max_len {
211 return Err(SparseSequenceError::LengthLimit {
212 requested,
213 limit: self.max_len,
214 });
215 }
216 Ok(())
217 }
218
219 fn truncate_values(&mut self, new_len: usize) {
220 let first_removed_chunk = new_len / CHUNK_LEN;
221 let first_removed_offset = new_len % CHUNK_LEN;
222
223 if first_removed_offset != 0
224 && let Some(chunk) = self.chunks.get_mut(&first_removed_chunk)
225 {
226 for slot in &mut chunk[first_removed_offset..] {
227 if slot.take().is_some() {
228 self.occupied -= 1;
229 }
230 }
231 if chunk.iter().all(Option::is_none) {
232 self.chunks.remove(&first_removed_chunk);
233 }
234 }
235
236 let remove_from = first_removed_chunk + usize::from(first_removed_offset != 0);
237 let removed = self.chunks.split_off(&remove_from);
238 self.occupied -= removed
239 .values()
240 .map(|chunk| chunk.iter().filter(|slot| slot.is_some()).count())
241 .sum::<usize>();
242 }
243
244 fn bump_revision(&mut self) {
245 self.revision = self.revision.wrapping_add(1);
246 }
247}
248
249fn split_index(index: usize) -> (usize, usize) {
250 (index / CHUNK_LEN, index % CHUNK_LEN)
251}