bump_scope/
chunk_size.rs

1use core::{alloc::Layout, marker::PhantomData, num::NonZeroUsize};
2
3use chunk_size_config::ChunkSizeConfig;
4
5use crate::ChunkHeader;
6
7mod chunk_size_config;
8
9const _: () = assert!(chunk_size_config::MIN_CHUNK_ALIGN == crate::bumping::MIN_CHUNK_ALIGN);
10
11/// We leave some space per allocation for the base allocator.
12pub(crate) type AssumedMallocOverhead = [*const u8; 2];
13
14pub const fn config<A, const UP: bool>() -> ChunkSizeConfig {
15    ChunkSizeConfig {
16        up: UP,
17        assumed_malloc_overhead_layout: Layout::new::<AssumedMallocOverhead>(),
18        chunk_header_layout: Layout::new::<ChunkHeader<A>>(),
19    }
20}
21
22macro_rules! attempt {
23    ($expr:expr) => {
24        match $expr {
25            Some(some) => some,
26            None => return None,
27        }
28    };
29}
30
31pub struct ChunkSize<A, const UP: bool> {
32    size: NonZeroUsize,
33    marker: PhantomData<*const A>,
34}
35
36impl<A, const UP: bool> Clone for ChunkSize<A, UP> {
37    fn clone(&self) -> Self {
38        *self
39    }
40}
41
42impl<A, const UP: bool> Copy for ChunkSize<A, UP> {}
43
44impl<A, const UP: bool> ChunkSize<A, UP> {
45    pub const DEFAULT: Self = ChunkSizeHint::DEFAULT.calc_size().unwrap();
46
47    pub const fn from_hint(size_hint: usize) -> Option<Self> {
48        ChunkSizeHint::new(size_hint).calc_size()
49    }
50
51    pub const fn from_capacity(layout: Layout) -> Option<Self> {
52        attempt!(ChunkSizeHint::for_capacity(layout)).calc_size()
53    }
54
55    /// See [`chunk_size_config::ChunkSizeConfig::align_size`].
56    pub const fn align_allocation_size(self, size: usize) -> usize {
57        _ = self;
58        config::<A, UP>().align_size(size)
59    }
60
61    pub const fn layout(self) -> Option<Layout> {
62        let size = self.size.get();
63        let align = core::mem::align_of::<ChunkHeader<A>>();
64        match Layout::from_size_align(size, align) {
65            Ok(ok) => Some(ok),
66            Err(_) => None,
67        }
68    }
69}
70pub struct ChunkSizeHint<A, const UP: bool>(usize, PhantomData<*const A>);
71
72impl<A, const UP: bool> Clone for ChunkSizeHint<A, UP> {
73    fn clone(&self) -> Self {
74        *self
75    }
76}
77
78impl<A, const UP: bool> Copy for ChunkSizeHint<A, UP> {}
79
80impl<A, const UP: bool> ChunkSizeHint<A, UP> {
81    pub const DEFAULT: Self = Self::new(512);
82
83    pub const fn new(size_hint: usize) -> Self {
84        Self(size_hint, PhantomData)
85    }
86
87    pub const fn for_capacity(layout: Layout) -> Option<Self> {
88        Some(Self(attempt!(config::<A, UP>().calc_hint_from_capacity(layout)), PhantomData))
89    }
90
91    pub const fn calc_size(self) -> Option<ChunkSize<A, UP>> {
92        Some(ChunkSize {
93            size: attempt!(config::<A, UP>().calc_size_from_hint(self.0)),
94            marker: PhantomData,
95        })
96    }
97
98    pub const fn max(self, other: Self) -> Self {
99        if self.0 > other.0 { self } else { other }
100    }
101}