space_alloc/
linear.rs

1use std::num::NonZeroU64;
2
3use super::OutOfMemory;
4
5/// A space allocator that allocates lineally without any packing nor space reusal.
6///
7/// Internally, it uses a cursor that can only move forward. Once the user tries to allocate a size
8/// bigger than the space left dictated by the total block size minus the cursor offset, it will
9/// fail with an out of memory error.
10#[derive(Debug, Clone)]
11pub struct LinearAllocator {
12    /// The total available space for the allocator.
13    block_size: u64,
14    /// Where the allocator will allocate next, relative to the block start.
15    cursor_offset: u64,
16}
17
18impl LinearAllocator {
19    pub fn new(block_size: u64) -> Self {
20        Self {
21            block_size,
22            cursor_offset: 0,
23        }
24    }
25
26    /// Resets the internal cursor offset to 0, thus effectively "freeing the contents" of the
27    /// allocator.
28    pub fn reset(&mut self) {
29        self.cursor_offset = 0;
30    }
31
32    /// Returns the space left in the allocator, calculated using the internal cursor offset.
33    pub fn space_free(&mut self) -> u64 {
34        self.block_size - self.cursor_offset
35    }
36}
37
38/// Allocation information from a `LinearAllocator` allocation.
39#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
40pub struct LinearAllocation {
41    offset: u64,
42    size: u64,
43}
44
45impl super::Allocation for LinearAllocation {
46    fn offset(&self) -> u64 {
47        self.offset
48    }
49
50    fn size(&self) -> u64 {
51        self.size
52    }
53}
54
55impl super::Allocator for LinearAllocator {
56    type Allocation = LinearAllocation;
57
58    /// Offsets the internal cursor by the size given taking alignment into account.
59    fn allocate(
60        &mut self,
61        size: std::num::NonZeroU64,
62        alignment: std::num::NonZeroU64,
63    ) -> Result<Self::Allocation, OutOfMemory> {
64        // Align the cursor
65        self.cursor_offset += self.cursor_offset % alignment;
66
67        let size = size.get();
68        if size > self.space_free() {
69            // If what we want to allocate is bigger than our space left, we obviously cannot
70            // provide the allocation required.
71            Err(OutOfMemory)
72        } else {
73            self.cursor_offset += size;
74            Ok(LinearAllocation {
75                offset: self.cursor_offset - size,
76                size,
77            })
78        }
79    }
80
81    fn from_properties(_min_alloc: u64, capacity: NonZeroU64) -> Self {
82        Self::new(capacity.get())
83    }
84}