kernel/mem/
array.rs

1//! This module implements static and dynamic arrays for in-kernel use.
2
3use super::boxed::Box;
4use crate::utils::KernelError;
5use core::{borrow::Borrow, mem::MaybeUninit};
6
7/// This is a fixed-size map that can store up to N consecutive elements.
8pub struct IndexMap<K: Borrow<usize> + Default, V, const N: usize> {
9    data: [Option<V>; N],
10    phantom: core::marker::PhantomData<K>,
11}
12
13impl<K: Borrow<usize> + Default, V, const N: usize> IndexMap<K, V, N> {
14    /// Create a new IndexMap.
15    ///
16    /// Returns a new IndexMap.
17    pub const fn new() -> Self {
18        Self {
19            data: [const { None }; N],
20            phantom: core::marker::PhantomData,
21        }
22    }
23
24    /// Get the element at the given index.
25    ///
26    /// `index` - The index to get the element from.
27    ///
28    /// Returns `Some(&T)` if the index is in-bounds, otherwise `None`.
29    pub fn get(&self, index: &K) -> Option<&V> {
30        let index = *index.borrow();
31
32        if index < N {
33            self.data[index].as_ref()
34        } else {
35            None
36        }
37    }
38
39    /// Get a mutable reference to the element at the given index.
40    ///
41    /// `index` - The index to get the element from.
42    ///
43    /// Returns `Some(&mut T)` if the index is in-bounds, otherwise `None`.
44    pub fn get_mut(&mut self, index: &K) -> Option<&mut V> {
45        let index = *index.borrow();
46
47        if index < N {
48            self.data[index].as_mut()
49        } else {
50            None
51        }
52    }
53
54    /// Insert a value at the given index.
55    ///
56    /// `index` - The index to insert the value at.
57    /// `value` - The value to insert.
58    ///
59    /// Returns `Ok(())` if the index was in-bounds, otherwise `Err(KernelError::OutOfMemory)`.
60    pub fn insert(&mut self, index: &K, value: V) -> Result<(), KernelError> {
61        let index = *index.borrow();
62
63        if index < N {
64            self.data[index] = Some(value);
65            Ok(())
66        } else {
67            Err(KernelError::OutOfMemory)
68        }
69    }
70
71    /// Insert a value at the next available index.
72    ///
73    /// `value` - The value to insert.
74    ///
75    /// Returns `Ok(index)` if the value was inserted, otherwise `Err(KernelError::OutOfMemory)`.
76    pub fn insert_next(&mut self, value: V) -> Result<usize, KernelError> {
77        for (i, slot) in self.data.iter_mut().enumerate() {
78            if slot.is_none() {
79                *slot = Some(value);
80                return Ok(i);
81            }
82        }
83
84        Err(KernelError::OutOfMemory)
85    }
86
87    /// Remove the value at the given index.
88    ///
89    /// `index` - The index to remove the value from.
90    ///
91    /// Returns the value if it was removed, otherwise `None`.
92    pub fn remove(&mut self, index: &K) -> Option<V> {
93        let index = *index.borrow();
94
95        if index < N {
96            self.data[index].take()
97        } else {
98            None
99        }
100    }
101
102    /// Get an iterator over the elements in the map.
103    ///
104    /// Returns an iterator over the elements in the map.
105    pub fn iter(&self) -> impl Iterator<Item = &Option<V>> {
106        self.data.iter()
107    }
108
109    /// Get an cycling iterator over the elements in the map, starting from the given index.
110    ///
111    /// `index` - The index to start the iterator from.
112    ///
113    /// Returns an iterator over the elements in the map.
114    pub fn iter_from_cycle(&self, index: &K) -> impl Iterator<Item = &Option<V>> {
115        self.data.iter().cycle().skip(index.borrow() + 1)
116    }
117
118    /// Get the next index that contains a value (this will cycle).
119    ///
120    /// `index` - The index to start the search from.
121    ///
122    /// Returns the next index (potentially < index) that contains a value, otherwise `None`.
123    pub fn next(&self, index: Option<&K>) -> Option<usize> {
124        let default = K::default();
125        let index = index.unwrap_or(&default);
126
127        for (i, elem) in self.iter_from_cycle(index).enumerate() {
128            if elem.is_some() {
129                return Some((index.borrow() + i + 1) % N);
130            }
131        }
132
133        None
134    }
135
136    pub fn find_empty(&self) -> Option<usize> {
137        for (i, slot) in self.data.iter().enumerate() {
138            if slot.is_none() {
139                return Some(i);
140            }
141        }
142
143        None
144    }
145}
146
147/// This is a vector that can store up to N elements inline and will allocate on the heap if more are needed.
148pub struct Vec<T, const N: usize> {
149    len: usize,
150    data: [MaybeUninit<T>; N],
151    extra: Box<[MaybeUninit<T>]>,
152}
153
154impl<T: Clone + Copy, const N: usize> Vec<T, N> {
155    /// Create a new Vec.
156    ///
157    /// Returns a new Vec.
158    pub const fn new() -> Self {
159        Self {
160            len: 0,
161            data: [const { MaybeUninit::uninit() }; N],
162            extra: Box::new_slice_empty(),
163        }
164    }
165
166    /// Reserve additional space in the Vec.
167    ///
168    /// `additional` - The additional space to reserve.
169    ///
170    /// Returns `Ok(())` if the space was reserved, otherwise `Err(KernelError::OutOfMemory)`.
171    pub fn reserve(&mut self, additional: usize) -> Result<(), KernelError> {
172        let len_extra = self.extra.len();
173
174        // Check if we have enough space in the inline storage.
175        if self.len + additional <= N + len_extra {
176            return Ok(());
177        }
178
179        // If we don't have enough space, we need to grow the extra storage.
180        let grow = additional - N + len_extra;
181        let mut new_extra = Box::new_slice_uninit(grow)?;
182
183        // Check that the new extra storage has the requested length.
184        BUG_ON!(new_extra.len() != grow);
185
186        // Copy the old extra storage into the new one.
187        new_extra[..len_extra].copy_from_slice(&self.extra);
188
189        // Replace the old extra storage with the new one. The old one will be dropped.
190        self.extra = new_extra;
191        Ok(())
192    }
193
194    /// Reserve a fixed amount of space in the Vec. Does nothing if enough space is present already.
195    ///
196    /// `total_capacity` - The total space to be reserved.
197    ///
198    /// Returns `Ok(())` if the space was reserved, otherwise `Err(KernelError::OutOfMemory)`.
199    pub fn reserve_total_capacity(&mut self, total_capacity: usize) -> Result<(), KernelError> {
200        // Check if we already have enough space
201        if self.capacity() >= total_capacity {
202            return Ok(());
203        }
204
205        // If we don't have enough space, we need to grow the extra storage.
206        let new_out_of_line_cap = total_capacity - N;
207        let mut new_extra = Box::new_slice_uninit(new_out_of_line_cap)?;
208
209        // Check that the new extra storage has the requested length.
210        BUG_ON!(new_extra.len() != new_out_of_line_cap);
211
212        let curr_out_of_line_size = self.extra.len();
213        // Copy the old extra storage into the new one.
214        new_extra[..curr_out_of_line_size].copy_from_slice(&self.extra);
215
216        // Replace the old extra storage with the new one. The old one will be dropped.
217        self.extra = new_extra;
218        Ok(())
219    }
220
221    /// Create a new Vec with the given length and value.
222    ///
223    /// `length` - The length of the Vec.
224    /// `value` - The value to initialize the elements in the Vec with.
225    ///
226    /// Returns the new Vec or `Err(KernelError::OutOfMemory)` if the allocation failed.
227    pub fn new_init(length: usize, value: T) -> Result<Self, KernelError> {
228        let mut vec = Self::new();
229
230        // Check if we can fit all elements in the inline storage.
231        if length <= N {
232            // Initialize all elements in the inline storage.
233            for i in 0..length {
234                vec.data[i].write(value);
235            }
236        } else {
237            // Initialize all elements in the inline storage.
238            vec.data.fill(MaybeUninit::new(value));
239
240            // Check if we need to allocate extra storage.
241            if length - N > 0 {
242                // Allocate extra storage for the remaining elements.
243                let mut extra = Box::new_slice_uninit(length - N)?;
244
245                // Initialize all the required elements in the extra storage.
246                for i in N..length {
247                    extra[i - N].write(value);
248                }
249
250                // Set the extra storage in the Vec.
251                vec.extra = extra;
252            }
253        }
254
255        Ok(vec)
256    }
257
258    /// Push a value onto the Vec.
259    ///
260    /// `value` - The value to push.
261    ///
262    /// Returns `Ok(())` if the value was pushed, otherwise `Err(KernelError::OutOfMemory)`.
263    pub fn push(&mut self, value: T) -> Result<(), KernelError> {
264        // Check if we have enough space in the inline storage.
265        if self.len < N {
266            // Push the value into the inline storage.
267            self.data[self.len].write(value);
268            self.len += 1;
269            Ok(())
270        } else {
271            let len_extra = self.extra.len();
272
273            // Check if we have enough space in the extra storage.
274            if self.len < N + len_extra {
275                // Push the value into the extra storage.
276                self.extra[self.len - N].write(value);
277                self.len += 1;
278                Ok(())
279            } else {
280                // We need to grow the extra storage.
281                let grow = (len_extra + 1) * 2;
282                let mut new_extra = Box::new_slice_uninit(grow)?;
283
284                BUG_ON!(new_extra.len() != grow);
285
286                // Copy the old extra storage into the new one.
287                new_extra[..len_extra].copy_from_slice(&self.extra);
288
289                // Replace the old extra storage with the new one. The old one will be dropped.
290                self.extra = new_extra;
291                self.extra[len_extra].write(value);
292                self.len += 1;
293                Ok(())
294            }
295        }
296    }
297
298    /// Pop a value from the Vec.
299    ///
300    /// Returns the value if it was popped, otherwise `None`.
301    pub fn pop(&mut self) -> Option<T> {
302        if self.len == 0 {
303            return None;
304        }
305        self.remove(self.len - 1)
306    }
307
308    /// Remove the value at the given index.
309    ///
310    /// `index` - The index to remove the value from.
311    ///
312    /// Returns the value if it was removed, otherwise `None`.
313    pub fn remove(&mut self, index: usize) -> Option<T> {
314        // Check if the index is in-bounds.
315        if index >= self.len {
316            return None;
317        }
318
319        // Get the value at the given index.
320        let value = self.at(index).cloned();
321
322        // Check if we need to move inline storage elements.
323        if index < N {
324            // Move the elements in the inline storage.
325            let end = core::cmp::min(self.len, N);
326
327            // Safety: index is less than N and min too.
328            self.data.copy_within(index + 1..end, index);
329
330            // Check if we need to move the first extra storage element into the inline storage.
331            if let Some(value) = self.at(N) {
332                self.data[end - 1].write(*value);
333            }
334
335            // Move the elements in the extra storage.
336            if self.len() > N {
337                self.extra.copy_within(1..self.len - N, 0);
338            }
339        } else {
340            // We only need to move the elements in the extra storage.
341
342            let index = index - N;
343            let end = self.len - N;
344
345            // Safety: index is less than N and min too.
346            self.extra.copy_within(index + 1..end, index);
347        }
348
349        self.len -= 1;
350        value
351    }
352
353    /// Get the length of the Vec.
354    ///
355    /// Returns the length of the Vec.
356    pub fn len(&self) -> usize {
357        self.len
358    }
359
360    /// Get the value at the given index.
361    ///
362    /// `index` - The index to get the value from.
363    ///
364    /// Returns `Some(&T)` if the index is in-bounds, otherwise `None`.
365    pub fn at(&self, index: usize) -> Option<&T> {
366        // Check if the index is in-bounds.
367        if index > self.len - 1 {
368            return None;
369        }
370
371        if index < N {
372            // Safety: the elements until self.len are initialized.
373            unsafe { Some(self.data[index].assume_init_ref()) }
374        } else {
375            let index = index - N;
376            // Safety: the elements until self.len - N are initialized.
377            unsafe { Some(self.extra[index].assume_init_ref()) }
378        }
379    }
380
381    /// Get a mutable reference to the value at the given index.
382    ///
383    /// `index` - The index to get the value from.
384    ///
385    /// Returns `Some(&mut T)` if the index is in-bounds, otherwise `None`.
386    pub fn at_mut(&mut self, index: usize) -> Option<&mut T> {
387        // Check if the index is in-bounds.
388        if index > self.len - 1 {
389            return None;
390        }
391
392        if index < N {
393            // Safety: the elements until self.len are initialized.
394            unsafe { Some(self.data[index].assume_init_mut()) }
395        } else {
396            let index = index - N;
397            // Safety: the elements until self.len - N are initialized.
398            unsafe { Some(self.extra[index].assume_init_mut()) }
399        }
400    }
401
402    /// Swap the values at the given indices.
403    ///
404    /// `a` - The first index.
405    /// `b` - The second index.
406    pub fn swap(&mut self, a: usize, b: usize) {
407        // Check if the indices are in-bounds.
408        if a >= self.len || b >= self.len {
409            return;
410        }
411
412        if a < N && b < N {
413            // Both indices are in the inline storage.
414            self.data.swap(a, b);
415        } else if a >= N && b >= N {
416            // Both indices are in the extra storage.
417            self.extra.swap(a - N, b - N);
418        } else if a >= N {
419            // The first index is in the extra storage.
420            core::mem::swap(&mut self.extra[a - N], &mut self.data[b]);
421        } else {
422            // The second index is in the extra storage.
423            core::mem::swap(&mut self.data[a], &mut self.extra[b - N]);
424        }
425    }
426
427    /// Check if the Vec is empty.
428    ///
429    /// Returns `true` if the Vec is empty, otherwise `false`.
430    pub fn is_empty(&self) -> bool {
431        self.len == 0
432    }
433
434    /// Get total amount of space in Vec (in- and out-of-line)
435    ///
436    /// Returns total amount of  reserved space in the vec
437    pub fn capacity(&self) -> usize {
438        N + self.extra.len()
439    }
440}
441
442impl<T, const N: usize> Drop for Vec<T, N> {
443    fn drop(&mut self) {
444        let min = core::cmp::min(self.len, N);
445
446        // Drop all elements in the inline storage.
447        for elem in &mut self.data[0..min] {
448            // Safety: the elements until min are initialized.
449            unsafe {
450                elem.assume_init_drop();
451            }
452        }
453
454        // Drop all elements in the extra storage.
455        for elem in &mut (*self.extra)[0..self.len - N] {
456            // Safety: the elements until self.len - N are initialized.
457            unsafe {
458                elem.assume_init_drop();
459            }
460        }
461    }
462}
463
464#[cfg(kani)]
465mod verification {
466    use super::*;
467}