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::BumpAllocatorSettings,
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, S>() -> ChunkSizeConfig
14where
15    S: BumpAllocatorSettings,
16{
17    ChunkSizeConfig {
18        up: S::UP,
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, S> {
34    size: NonZeroUsize,
35    marker: PhantomData<fn() -> (A, S)>,
36}
37
38impl<A, S> Clone for ChunkSize<A, S> {
39    fn clone(&self) -> Self {
40        *self
41    }
42}
43
44impl<A, S> Copy for ChunkSize<A, S> {}
45
46impl<A, S> ChunkSize<A, S>
47where
48    S: BumpAllocatorSettings,
49{
50    pub const MINIMUM: Self = match Self::from_hint(S::MINIMUM_CHUNK_SIZE) {
51        Some(some) => some,
52        None => panic!("failed to calculate minimum 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(size: usize) -> usize {
65        config::<A, S>().align_size(size)
66    }
67
68    pub const fn layout(self) -> Option<Layout> {
69        let size = self.size.get();
70        let align = core::mem::align_of::<ChunkHeader<A>>();
71        match Layout::from_size_align(size, align) {
72            Ok(ok) => Some(ok),
73            Err(_) => None,
74        }
75    }
76}
77pub struct ChunkSizeHint<A, S>(usize, PhantomData<fn() -> (A, S)>);
78
79impl<A, S> Clone for ChunkSizeHint<A, S> {
80    fn clone(&self) -> Self {
81        *self
82    }
83}
84
85impl<A, S> Copy for ChunkSizeHint<A, S> {}
86
87impl<A, S> ChunkSizeHint<A, S>
88where
89    S: BumpAllocatorSettings,
90{
91    pub const fn new(size_hint: usize) -> Self {
92        Self(size_hint, PhantomData)
93    }
94
95    pub const fn for_capacity(layout: Layout) -> Option<Self> {
96        Some(Self(attempt!(config::<A, S>().calc_hint_from_capacity(layout)), PhantomData))
97    }
98
99    pub const fn calc_size(self) -> Option<ChunkSize<A, S>> {
100        let size_hint = max(self.0, S::MINIMUM_CHUNK_SIZE);
101
102        Some(ChunkSize {
103            size: attempt!(config::<A, S>().calc_size_from_hint(size_hint)),
104            marker: PhantomData,
105        })
106    }
107
108    pub const fn max(self, other: Self) -> Self {
109        if self.0 > other.0 { self } else { other }
110    }
111}
112
113const fn max(a: usize, b: usize) -> usize {
114    if a > b { a } else { b }
115}