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}