summaryrefslogtreecommitdiff
path: root/src/sparse_set.rs
blob: d7a69eb40827230352e6e2d50fa79f8eb51245ac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use super::Entity;

pub struct SparseSet<T> {
    pub dense: Vec<T>,
    pub entities: Vec<Entity>,
    pub sparse: Vec<Option<usize>>,
}

impl<T> SparseSet<T> {
    pub fn new() -> Self {
        Self {
            dense: Vec::new(),
            entities: Vec::new(),
            sparse: Vec::new(),
        }
    }

    pub fn insert(&mut self, entity: Entity, component: T) {
        if self.sparse.len() <= entity {
            self.sparse.resize(entity + 1, None);
        }

        self.dense.push(component);
        self.entities.push(entity);

        let id = self.dense.len() - 1;
        self.sparse[entity] = Some(id);
    }

    pub fn remove(&mut self, entity: Entity) {
        let Some(id) = self.sparse.get(entity).copied().flatten() else {
            return;
        };
        let Some(last) = self.entities.last().copied() else {
            return;
        };
        self.dense.swap_remove(id);
        self.entities.swap_remove(id);
        self.sparse[last] = Some(id);
        self.sparse[entity] = None;
    }

    pub fn iter(&self) -> impl Iterator<Item = (Entity, &T)> {
        self.entities.iter().copied().zip(self.dense.iter())
    }

    pub fn iter_mut(&mut self) -> impl Iterator<Item = (Entity, &mut T)> {
        self.entities.iter().copied().zip(self.dense.iter_mut())
    }

    pub fn get(&self, entity: Entity) -> Option<&T> {
        if let Some(id) = self.sparse.get(entity) {
            match id {
                Some(id) => self.dense.get(*id),
                None => None,
            }
        } else {
            None
        }
    }

    pub fn get_mut(&mut self, entity: Entity) -> Option<&mut T> {
        if let Some(id) = self.sparse.get(entity) {
            match id {
                Some(id) => self.dense.get_mut(*id),
                None => None,
            }
        } else {
            None
        }
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn test_remove() {
        let mut set = SparseSet::<i32>::new();
        set.insert(3, 300);
        set.insert(2, 200);
        set.insert(4, 400);
        set.insert(7, 700);

        set.remove(4);

        assert!(set.get(7).copied() == Some(700));
        assert!(set.get(3).copied() == Some(300));
        assert!(set.get(2).copied() == Some(200));
        assert!(set.get(4).copied().is_none());

        set.remove(7);
        assert!(set.get(7).copied().is_none());
        assert!(set.get(3).copied() == Some(300));
        assert!(set.get(2).copied() == Some(200));
        assert!(set.get(4).copied().is_none());
    }
}