my_ecs/ds/vec/opt_vec.rs
1use std::{cmp::Ordering, collections::HashSet, hash::BuildHasher, mem, ops::Index, slice};
2
3/// A vector containing optional values.
4///
5/// The vector would be useful when you need invariant index regardless of
6/// insertion and removal. If you remove an item from the vector, the slot
7/// remains vacant rather than removing the space by moving right items. Then
8/// the vacant slot can be filled when you insert an item into the vector.
9///
10/// For more understanding, see the diagram below.
11///
12/// ```text
13/// vector -> [ None, Some, None ]
14/// occupied No Yes No
15/// vacant Yes No Yes
16///
17/// * length: 1
18/// * number of slots: 3
19/// * number of vacancies: 2
20/// ```
21#[derive(Debug, Clone, Default)]
22pub struct OptVec<T, S> {
23 /// Optional values.
24 values: Vec<Option<T>>,
25
26 /// A set of indices to vacant slots.
27 vacancies: HashSet<usize, S>,
28}
29
30impl<T, S> OptVec<T, S>
31where
32 S: Default,
33{
34 /// Creates a new empty vector.
35 ///
36 /// # Examples
37 ///
38 /// ```
39 /// use my_ecs::ds::OptVec;
40 /// use std::hash::RandomState;
41 ///
42 /// let mut v = OptVec::<i32, RandomState>::new();
43 /// ```
44 pub fn new() -> Self {
45 Self {
46 values: Vec::new(),
47 vacancies: HashSet::default(),
48 }
49 }
50}
51
52impl<T, S> OptVec<T, S> {
53 /// Returns number of items, which is occupied slots in other words.
54 ///
55 /// Returned value is equal to `self.num_slots() - self.num_vacancies()`.
56 ///
57 /// # Examples
58 ///
59 /// ```
60 /// use my_ecs::ds::OptVec;
61 /// use std::hash::RandomState;
62 ///
63 /// let mut v = OptVec::<_, RandomState>::new();
64 /// v.add(0);
65 /// assert_eq!(v.len(), 1);
66 /// ```
67 pub fn len(&self) -> usize {
68 self.num_slots() - self.num_vacancies()
69 }
70
71 /// Returns true is the vector is empty.
72 ///
73 /// Note that vector may have slots in it even if it's empty.
74 ///
75 /// # Examples
76 ///
77 /// ```
78 /// use my_ecs::ds::OptVec;
79 /// use std::hash::RandomState;
80 ///
81 /// let mut v = OptVec::<i32, RandomState>::new();
82 /// assert!(v.is_empty());
83 /// ```
84 pub fn is_empty(&self) -> bool {
85 self.len() == 0
86 }
87
88 /// Returns number of all slots including occupied and vacant slots.
89 ///
90 /// Returned value is equal to `self.len() + self.num_vacancies()`.
91 ///
92 /// # Examples
93 ///
94 /// ```
95 /// use my_ecs::ds::OptVec;
96 /// use std::hash::RandomState;
97 ///
98 /// let mut v = OptVec::<_, RandomState>::new();
99 /// v.add(0);
100 /// assert_eq!(v.num_slots(), 1);
101 /// ```
102 pub fn num_slots(&self) -> usize {
103 self.values.len()
104 }
105
106 /// Returns number of vacant slots.
107 ///
108 /// Returned value is equal to `self.num_slots() - self.len()`.
109 ///
110 /// # Examples
111 ///
112 /// ```
113 /// use my_ecs::ds::OptVec;
114 /// use std::hash::RandomState;
115 ///
116 /// let mut v = OptVec::<_, RandomState>::new();
117 /// v.add(0);
118 /// v.take(0);
119 /// assert_eq!(v.num_vacancies(), 1);
120 /// ```
121 pub fn num_vacancies(&self) -> usize {
122 self.vacancies.len()
123 }
124
125 /// Returns true if the slot is vacant.
126 ///
127 /// # Panics
128 ///
129 /// Panics if the given index is out of bounds.
130 ///
131 /// # Examples
132 ///
133 /// ```
134 /// use my_ecs::ds::OptVec;
135 /// use std::hash::RandomState;
136 ///
137 /// let mut v = OptVec::<_, RandomState>::new();
138 /// v.add(0);
139 /// v.take(0);
140 /// assert!(v.is_vacant(0));
141 /// ```
142 pub fn is_vacant(&self, index: usize) -> bool {
143 self.values[index].is_none()
144 }
145
146 /// Returns true if the slot is occupied.
147 ///
148 /// # Panics
149 ///
150 /// Panics if the given index is out of bounds.
151 ///
152 /// # Examples
153 ///
154 /// ```
155 /// use my_ecs::ds::OptVec;
156 /// use std::hash::RandomState;
157 ///
158 /// let mut v = OptVec::<_, RandomState>::new();
159 /// v.add(0);
160 /// assert!(v.is_occupied(0));
161 /// ```
162 pub fn is_occupied(&self, index: usize) -> bool {
163 self.values[index].is_some()
164 }
165
166 /// Creates a slice from the vector.
167 ///
168 /// # Examples
169 ///
170 /// ```
171 /// use my_ecs::ds::OptVec;
172 /// use std::hash::RandomState;
173 ///
174 /// let mut v = OptVec::<_, RandomState>::new();
175 /// v.add(0);
176 /// v.add(1);
177 /// assert_eq!(v.as_slice(), &[Some(0), Some(1)]);
178 /// ```
179 pub fn as_slice(&self) -> &[Option<T>] {
180 &self.values
181 }
182
183 /// Creates a mutable slice from the vector.
184 ///
185 /// Caller must not modify occupied/vacant status in the returned slice
186 /// because the vector is tracking the status.
187 ///
188 /// # Safety
189 ///
190 /// Undefined behavior if caller take out a value from an occupied slot, or
191 /// insert a value into a vacant slot.
192 ///
193 /// # Examples
194 ///
195 /// ```
196 /// use my_ecs::ds::OptVec;
197 /// use std::hash::RandomState;
198 ///
199 /// let mut v = OptVec::<_, RandomState>::new();
200 /// v.add(0);
201 /// v.add(1);
202 /// assert_eq!(v.as_slice(), &[Some(0), Some(1)]);
203 /// ```
204 pub unsafe fn as_mut_slice(&mut self) -> &mut [Option<T>] {
205 &mut self.values
206 }
207
208 /// Returns shared reference to the value at the given index if the index is
209 /// in bounds and the slot is occupied.
210 ///
211 /// # Examples
212 ///
213 /// ```
214 /// use my_ecs::ds::OptVec;
215 /// use std::hash::RandomState;
216 ///
217 /// let mut v = OptVec::<_, RandomState>::new();
218 /// v.add(0);
219 /// assert_eq!(v.get(0), Some(&0));
220 /// ```
221 pub fn get(&self, index: usize) -> Option<&T> {
222 self.values.get(index)?.as_ref()
223 }
224
225 /// Returns shared reference to the value at the given index.
226 ///
227 /// # Safety
228 ///
229 /// Undefined behavior if
230 /// - The index is out of bounds.
231 /// - The slot is vacant.
232 ///
233 /// # Examples
234 ///
235 /// ```
236 /// use my_ecs::ds::OptVec;
237 /// use std::hash::RandomState;
238 ///
239 /// let mut v = OptVec::<_, RandomState>::new();
240 /// v.add(0);
241 /// assert_eq!(unsafe { v.get_unchecked(0) }, &0);
242 /// ```
243 pub unsafe fn get_unchecked(&self, index: usize) -> &T {
244 unsafe { self.values.get_unchecked(index).as_ref().unwrap_unchecked() }
245 }
246
247 /// Returns mutable reference to the value at the given index if the index
248 /// is in bounds and the slot is occupied.
249 ///
250 /// # Examples
251 ///
252 /// ```
253 /// use my_ecs::ds::OptVec;
254 /// use std::hash::RandomState;
255 ///
256 /// let mut v = OptVec::<_, RandomState>::new();
257 /// v.add(0);
258 /// assert_eq!(v.get_mut(0), Some(&mut 0));
259 /// ```
260 pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
261 self.values.get_mut(index)?.as_mut()
262 }
263
264 /// Returns shared reference to the value at the given index.
265 ///
266 /// # Safety
267 ///
268 /// Undefined behavior if
269 /// - The index is out of bounds.
270 /// - The slot is vacant.
271 ///
272 /// # Examples
273 ///
274 /// ```
275 /// use my_ecs::ds::OptVec;
276 /// use std::hash::RandomState;
277 ///
278 /// let mut v = OptVec::<_, RandomState>::new();
279 /// v.add(0);
280 /// assert_eq!(unsafe { v.get_unchecked_mut(0) }, &mut 0);
281 /// ```
282 pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut T {
283 unsafe {
284 self.values
285 .get_unchecked_mut(index)
286 .as_mut()
287 .unwrap_unchecked()
288 }
289 }
290
291 /// Returns an iterator visiting all values with corresponding indices.
292 ///
293 /// As return type says, vacant slots are filtered out from the iteration.
294 ///
295 /// # Examples
296 ///
297 /// ```
298 /// use my_ecs::ds::OptVec;
299 /// use std::hash::RandomState;
300 ///
301 /// let mut v = OptVec::<_, RandomState>::new();
302 /// v.add('a');
303 /// v.add('b');
304 /// let pairs = v.pairs().collect::<Vec<_>>();
305 /// assert_eq!(pairs, [(0, &'a'), (1, &'b')]);
306 /// ```
307 pub fn pairs(&self) -> impl Iterator<Item = (usize, &T)> {
308 self.values
309 .iter()
310 .enumerate()
311 .filter_map(|(i, v)| v.as_ref().map(|v| (i, v)))
312 }
313
314 /// Returns a mutable iterator visiting all values with corresponding
315 /// indices.
316 ///
317 /// As return type says, vacant slots are filtered out from the iteration.
318 ///
319 /// # Examples
320 ///
321 /// ```
322 /// use my_ecs::ds::OptVec;
323 /// use std::hash::RandomState;
324 ///
325 /// let mut v = OptVec::<_, RandomState>::new();
326 /// v.add('a');
327 /// v.add('b');
328 /// let pairs = v.pairs_mut().collect::<Vec<_>>();
329 /// assert_eq!(pairs, [(0, &mut 'a'), (1, &mut 'b')]);
330 /// ```
331 pub fn pairs_mut(&mut self) -> impl Iterator<Item = (usize, &mut T)> {
332 self.values
333 .iter_mut()
334 .enumerate()
335 .filter_map(|(i, v)| v.as_mut().map(|v| (i, v)))
336 }
337
338 /// Returns an iterator visiting all slots regardless of whether the slot
339 /// is occupied or not.
340 ///
341 /// # Examples
342 ///
343 /// ```
344 /// use my_ecs::ds::OptVec;
345 /// use std::hash::RandomState;
346 ///
347 /// let mut v = OptVec::<_, RandomState>::new();
348 /// v.add('a');
349 /// v.add('b');
350 /// v.take(0);
351 /// let slots = v.slots().cloned().collect::<Vec<_>>();
352 /// assert_eq!(slots, [None, Some('b')]);
353 /// ```
354 pub fn slots(&self) -> slice::Iter<'_, Option<T>> {
355 self.values.iter()
356 }
357
358 /// Returns an iterator visiting all values.
359 ///
360 /// As return type says, vacant slots are filtered out from the iteration.
361 ///
362 /// # Examples
363 ///
364 /// ```
365 /// use my_ecs::ds::OptVec;
366 /// use std::hash::RandomState;
367 ///
368 /// let mut v = OptVec::<_, RandomState>::new();
369 /// v.add('a');
370 /// v.add('b');
371 /// let values = v.iter().collect::<Vec<_>>();
372 /// assert_eq!(values, [&'a', &'b']);
373 /// ```
374 pub fn iter(&self) -> impl Iterator<Item = &T> + Clone {
375 self.values.iter().filter_map(|v| v.as_ref())
376 }
377
378 /// Returns a mutable iterator visiting all values.
379 ///
380 /// As return type says, vacant slots are filtered out from the iteration.
381 ///
382 /// # Examples
383 ///
384 /// ```
385 /// use my_ecs::ds::OptVec;
386 /// use std::hash::RandomState;
387 ///
388 /// let mut v = OptVec::<_, RandomState>::new();
389 /// v.add('a');
390 /// v.add('b');
391 /// let values = v.iter_mut().collect::<Vec<_>>();
392 /// assert_eq!(values, [&mut 'a', &mut 'b']);
393 /// ```
394 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
395 self.values.iter_mut().filter_map(|v| v.as_mut())
396 }
397}
398
399impl<T, S> OptVec<T, S>
400where
401 S: BuildHasher,
402{
403 /// Sets a slot with the given optional value and returns old value.
404 ///
405 /// # Panics
406 ///
407 /// Panics if the given index is out of bounds.
408 ///
409 /// # Examples
410 ///
411 /// ```
412 /// use my_ecs::ds::OptVec;
413 /// use std::hash::RandomState;
414 ///
415 /// let mut v = OptVec::<_, RandomState>::new();
416 /// v.add(0);
417 /// assert_eq!(v.set(0, None), Some(0));
418 /// ```
419 pub fn set(&mut self, index: usize, value: Option<T>) -> Option<T> {
420 if value.is_some() {
421 self.vacancies.remove(&index);
422 } else {
423 self.vacancies.insert(index);
424 }
425 mem::replace(&mut self.values[index], value)
426 }
427
428 /// Returns the next index that will be returned on the next call to
429 /// [`OptVec::add`].
430 ///
431 /// # Examples
432 ///
433 /// ```
434 /// use my_ecs::ds::OptVec;
435 /// use std::hash::RandomState;
436 ///
437 /// let mut v = OptVec::<_, RandomState>::new();
438 /// assert_eq!(v.next_index(), 0);
439 ///
440 /// v.add(0);
441 /// v.add(1);
442 /// v.take(0);
443 /// assert_eq!(v.next_index(), 0);
444 /// ```
445 pub fn next_index(&self) -> usize {
446 if let Some(index) = self.vacancies.iter().next() {
447 *index
448 } else {
449 self.values.len()
450 }
451 }
452
453 /// Inserts the given value into the vector.
454 ///
455 /// The vector prefers to insert values into vacant slots if possible. But
456 /// if the vector doesn't have any vacant slots, then the value is appended
457 /// to the end of the vector.
458 ///
459 /// # Examples
460 ///
461 /// ```
462 /// use my_ecs::ds::OptVec;
463 /// use std::hash::RandomState;
464 ///
465 /// let mut v = OptVec::<_, RandomState>::new();
466 /// v.add(0);
467 /// assert_eq!(v.len(), 1);
468 /// ```
469 pub fn add(&mut self, value: T) -> usize {
470 if let Some(index) = self.vacancies.iter().next() {
471 let index = *index;
472 self.vacancies.remove(&index);
473 self.values[index] = Some(value);
474 index
475 } else {
476 self.values.push(Some(value));
477 self.values.len() - 1
478 }
479 }
480
481 /// Appends the given optional value to the end of the vector.
482 ///
483 /// Note that this method won't insert the value into a vacant slot. It just
484 /// makes a new slot at the end of the vector then puts the value in the
485 /// slot.
486 ///
487 /// # Examples
488 ///
489 /// ```
490 /// use my_ecs::ds::OptVec;
491 /// use std::hash::RandomState;
492 ///
493 /// let mut v = OptVec::<_, RandomState>::new();
494 /// v.add(0);
495 /// v.take(0);
496 /// v.push(Some(0));
497 /// assert_eq!(v.as_slice(), &[None, Some(0)]);
498 /// ```
499 pub fn push(&mut self, value: Option<T>) {
500 if value.is_none() {
501 self.vacancies.insert(self.values.len());
502 }
503 self.values.push(value);
504 }
505
506 /// Takes value out of the slot at the given index.
507 ///
508 /// After calling the method, the slot remains vacant.
509 ///
510 /// # Panics
511 ///
512 /// Panics if the given index is out of bounds.
513 ///
514 /// # Examples
515 ///
516 /// ```
517 /// use my_ecs::ds::OptVec;
518 /// use std::hash::RandomState;
519 ///
520 /// let mut v = OptVec::<_, RandomState>::new();
521 /// v.add(0);
522 /// assert_eq!(v.take(0), Some(0));
523 /// assert_eq!(v.take(0), None);
524 /// ```
525 pub fn take(&mut self, index: usize) -> Option<T> {
526 let old = self.values[index].take()?;
527 self.vacancies.insert(index);
528 Some(old)
529 }
530
531 /// Resizes the vector to the given length.
532 ///
533 /// If the new length is greater than previous length of the vector, then
534 /// the vector is extended with the given optional value. Otherwise, the
535 /// vector is shrunk.
536 ///
537 /// # Examples
538 ///
539 /// ```
540 /// use my_ecs::ds::OptVec;
541 /// use std::hash::RandomState;
542 ///
543 /// let mut v = OptVec::<_, RandomState>::new();
544 /// v.resize(2, Some(0));
545 /// assert_eq!(v.as_slice(), &[Some(0), Some(0)]);
546 /// ```
547 pub fn resize(&mut self, new_len: usize, value: Option<T>)
548 where
549 T: Clone,
550 {
551 self.resize_with(new_len, || value.clone());
552 }
553
554 /// Resizes the vector to the given length.
555 ///
556 /// If the new length is greater than previous length of the vector, then
557 /// the vector is extended with optional values the given function
558 /// generates. In this case, generated values are appended in order.
559 /// Otherwise, the vector is shrunk.
560 ///
561 /// # Examples
562 ///
563 /// ```
564 /// use my_ecs::ds::OptVec;
565 /// use std::hash::RandomState;
566 ///
567 /// let mut v = OptVec::<_, RandomState>::new();
568 /// v.resize_with(2, || Some(0));
569 /// assert_eq!(v.as_slice(), &[Some(0), Some(0)]);
570 /// ```
571 pub fn resize_with<F>(&mut self, new_len: usize, mut f: F)
572 where
573 F: FnMut() -> Option<T>,
574 {
575 match new_len.cmp(&self.num_slots()) {
576 Ordering::Less => self.truncate(new_len),
577 Ordering::Equal => {}
578 Ordering::Greater => {
579 let range = self.num_slots()..new_len;
580 for _ in range {
581 self.push(f());
582 }
583 }
584 }
585 }
586
587 /// Shrinks the vector to the given length, and drops abandoned items.
588 ///
589 /// If the given length is greater than or equal to the current length of
590 /// the vector, nothing takes place.
591 ///
592 /// # Examples
593 ///
594 /// ```
595 /// use my_ecs::ds::OptVec;
596 /// use std::hash::RandomState;
597 ///
598 /// let mut v = OptVec::<_, RandomState>::new();
599 /// v.resize_with(4, || Some(0));
600 /// v.truncate(2);
601 /// assert_eq!(v.as_slice(), &[Some(0), Some(0)]);
602 /// ```
603 pub fn truncate(&mut self, len: usize) {
604 for index in len..self.values.len() {
605 if self.values.pop().is_none() {
606 self.vacancies.remove(&index);
607 }
608 }
609 }
610
611 /// Removes vacant slots from the end of the vector, then shrinks capacity
612 /// of the vector as much as possible.
613 ///
614 /// # Examples
615 ///
616 /// ```
617 /// use my_ecs::ds::OptVec;
618 /// use std::hash::RandomState;
619 ///
620 /// let mut v = OptVec::<_, RandomState>::new();
621 /// v.resize(5, Some(0));
622 /// v.resize(10, None);
623 /// v.shrink_to_fit();
624 /// assert_eq!(v.num_vacancies(), 0);
625 /// ```
626 pub fn shrink_to_fit(&mut self) {
627 while let Some(None) = self.values.last() {
628 self.values.pop();
629 self.vacancies.remove(&self.values.len());
630 }
631 self.values.shrink_to_fit();
632 self.vacancies.shrink_to_fit();
633 }
634
635 /// Sets a slot with the given optional value and returns old value.
636 ///
637 /// Unlike [`OptVec::set`], this method doesn't panic even if the index is
638 /// out of bounds, extending the vector with vacant slots instead.
639 ///
640 /// # Examples
641 ///
642 /// ```
643 /// use my_ecs::ds::OptVec;
644 /// use std::hash::RandomState;
645 ///
646 /// let mut v = OptVec::<_, RandomState>::new();
647 /// v.extend_set(2, 0);
648 /// assert_eq!(v.as_slice(), &[None, None, Some(0)]);
649 /// ```
650 pub fn extend_set(&mut self, index: usize, value: T) -> Option<T> {
651 while self.num_slots() < (index + 1) {
652 self.push(None);
653 }
654 self.set(index, Some(value))
655 }
656}
657
658// Do not implement IndexMut because we need to modify vacancies if users take
659// the value out of the slot.
660impl<T, S> Index<usize> for OptVec<T, S> {
661 type Output = Option<T>;
662
663 fn index(&self, index: usize) -> &Self::Output {
664 &self.values[index]
665 }
666}
667
668impl<T, S> IntoIterator for OptVec<T, S>
669where
670 S: BuildHasher,
671{
672 type Item = T;
673 type IntoIter = IntoIter<T, S>;
674
675 fn into_iter(self) -> Self::IntoIter {
676 IntoIter::new(self)
677 }
678}
679
680impl<T, S> From<OptVec<T, S>> for Vec<T>
681where
682 S: BuildHasher,
683{
684 fn from(value: OptVec<T, S>) -> Self {
685 value.into_iter().collect()
686 }
687}
688
689// TODO: Improve
690#[derive(Debug)]
691pub struct IntoIter<T, S> {
692 vec: OptVec<T, S>,
693 cur: usize,
694}
695
696impl<T, S> IntoIter<T, S> {
697 fn new(vec: OptVec<T, S>) -> Self {
698 Self { vec, cur: 0 }
699 }
700}
701
702impl<T, S> Iterator for IntoIter<T, S>
703where
704 S: BuildHasher,
705{
706 type Item = T;
707
708 fn next(&mut self) -> Option<Self::Item> {
709 if self.vec.is_empty() {
710 return None;
711 }
712
713 let mut output = None;
714 while output.is_none() {
715 output = self.vec.take(self.cur);
716 self.cur += 1;
717 }
718 output
719 }
720}