Skip to main content

buddy_slab_allocator/slab/
size_class.rs

1/// Object size classes for the slab allocator.
2///
3/// Each size class corresponds to a fixed object size.
4/// Allocations are rounded up to the nearest size class.
5use core::alloc::Layout;
6
7/// Number of distinct size classes.
8pub const SIZE_CLASS_COUNT: usize = 9;
9
10/// Fixed set of object sizes served by the slab allocator.
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12#[repr(u8)]
13pub enum SizeClass {
14    Bytes8 = 0,
15    Bytes16 = 1,
16    Bytes32 = 2,
17    Bytes64 = 3,
18    Bytes128 = 4,
19    Bytes256 = 5,
20    Bytes512 = 6,
21    Bytes1024 = 7,
22    Bytes2048 = 8,
23}
24
25/// Maximum object size handled by the slab.
26pub const SLAB_MAX_SIZE: usize = 2048;
27
28/// Ordered table of (object_size, index) for all classes.
29const CLASS_SIZES: [usize; SIZE_CLASS_COUNT] = [8, 16, 32, 64, 128, 256, 512, 1024, 2048];
30
31impl SizeClass {
32    /// All size classes in ascending order.
33    pub const ALL: [SizeClass; SIZE_CLASS_COUNT] = [
34        SizeClass::Bytes8,
35        SizeClass::Bytes16,
36        SizeClass::Bytes32,
37        SizeClass::Bytes64,
38        SizeClass::Bytes128,
39        SizeClass::Bytes256,
40        SizeClass::Bytes512,
41        SizeClass::Bytes1024,
42        SizeClass::Bytes2048,
43    ];
44
45    /// Number of distinct size classes.
46    pub const COUNT: usize = SIZE_CLASS_COUNT;
47
48    /// Select the smallest size class that can satisfy `layout`.
49    ///
50    /// Returns `None` if the requested size or alignment exceeds the slab's capability.
51    pub fn from_layout(layout: Layout) -> Option<SizeClass> {
52        let size = layout.size().max(layout.align());
53        if size > SLAB_MAX_SIZE {
54            return None;
55        }
56        for (i, &class_size) in CLASS_SIZES.iter().enumerate() {
57            if size <= class_size {
58                return Some(SizeClass::ALL[i]);
59            }
60        }
61        None
62    }
63
64    /// Object size in bytes.
65    pub const fn size(self) -> usize {
66        CLASS_SIZES[self as usize]
67    }
68
69    /// Array index (0-based).
70    pub const fn index(self) -> usize {
71        self as usize
72    }
73
74    /// How many pages are needed for a single slab of this class.
75    ///
76    /// Smaller classes use 1 page, larger classes may use more to amortise the
77    /// per-page header overhead.
78    pub const fn slab_pages(self, page_size: usize) -> usize {
79        let obj_size = self.size();
80        if obj_size <= 256 {
81            1
82        } else if obj_size <= 1024 {
83            2
84        } else {
85            // 2048-byte objects: 4 pages → header + room for objects
86            let v = 16 * page_size / (obj_size * 8);
87            let v = if v < 4 { v } else { 4 };
88            if v < 1 { 1 } else { v }
89        }
90    }
91}