Skip to main content

bump_scope/chunk/
size.rs

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