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
/// ComponentArray is alternative to storing components in hashmap. Its considerable faster to

/// access elements of course there is a cost for that. You cannot choose your own ids ComponentArray

/// generates them for you. Model is surprisingly simple but powerful. To use this properly you have

/// to ALWAYS remove no longer needed component unless you like memory leaks.

pub struct ComponentArray<T> {
    inner: Vec<Option<T>>,
    ids: Vec<usize>,
    len: usize,
    id: usize,
}

impl<T> ComponentArray<T> {
    #[inline]
    pub fn new() -> Self {
        Self {
            inner: vec![None],
            ids: vec![],
            len: 0,
            id: 0,
        }
    }

    /// insert takes an value and returns id to is. (Its not really id but you can use it like it)

    #[inline]
    pub fn insert(&mut self, component: T) -> usize {
        self.len = self.inner.len();
        if self.ids.is_empty() {
            self.inner.push(Some(component));
            return self.len
        }
        self.len = self.ids.len() - 1;
        self.id = self.ids[self.len];
        self.inner[self.id] = Some(component);
        self.ids.truncate(self.len);

        self.id
    }

    #[inline]
    pub fn len(&self) -> usize {
        self.inner.len()
    }

    /// remove is important. Always remove the objects so memory can be reused for another one.

    #[inline]
    pub fn remove(&mut self, id: usize) -> T {
        if let None = self.inner[id] {
            panic!("value with given id is already none, call put_back and then remove, calling \
            just get instead of remove produces memory leak because space is still considered occupied.");
        }
        self.ids.push(id);
        unsafe { self.get(id).unwrap() }
    }

    #[inline]
    pub fn remove_if_present(&mut self, id: usize) -> Option<T> {
        if let None = self.inner[id] {
            return None
        }
        self.ids.push(id);
        unsafe { self.get(id) }
    }

    /// get is not equivalent fo remove, if you do not put back what you taken you are leaking memory

    /// because ComponentArray still considers it occupied. Function is here to solve situations when

    /// you need mutable and immutable asses to array elements at the same time

    #[inline]
    pub unsafe fn get(&mut self, id: usize) -> Option<T> {
        std::mem::replace(&mut self.inner[id], None)
    }

    /// Call this after get on the same id. This function is unsafe for a reason, you can very easily

    /// put your data somewhere where its considered free and it can then be overwrite by insert call

    #[inline]
    pub unsafe fn put_back(&mut self, id: usize, component: T) {
        self.inner[id] = Some(component);
    }

    /// get_ref returns reference to element or none

    #[inline]
    pub fn get_ref(&self, id: usize) -> &Option<T> {
        &self.inner[id]
    }

    /// get:mut returns mutable reference or none

    #[inline]
    pub fn get_mut(&mut self, id: usize) -> &mut Option<T> {
        &mut self.inner[id]
    }
}