bump_scope/chunk_size/
chunk_size_config.rs1#![forbid(unsafe_code)]
2use core::{alloc::Layout, num::NonZeroUsize};
9
10pub const ASSUMED_PAGE_SIZE: usize = 0x1000;
11pub const MIN_CHUNK_ALIGN: usize = 16;
12
13#[derive(Clone, Copy)]
14pub struct ChunkSizeConfig {
15 pub up: bool,
16 pub assumed_malloc_overhead_layout: Layout,
17 pub chunk_header_layout: Layout,
18}
19
20macro_rules! attempt {
22 ($expr:expr) => {
23 match $expr {
24 Some(some) => some,
25 None => return None,
26 }
27 };
28}
29
30impl ChunkSizeConfig {
31 #[inline(always)]
51 pub const fn align_size(self, size: usize) -> usize {
52 let Self {
53 up, chunk_header_layout, ..
54 } = self;
55
56 down_align(
57 size,
58 if up {
59 MIN_CHUNK_ALIGN
60 } else {
61 max(MIN_CHUNK_ALIGN, chunk_header_layout.align())
62 },
63 )
64 }
65
66 #[inline(always)]
67 pub const fn calc_size_from_hint(self, size_hint: usize) -> Option<NonZeroUsize> {
68 let Self {
69 assumed_malloc_overhead_layout,
70 chunk_header_layout,
71 ..
72 } = self;
73
74 let min = {
75 let mut offset = 0;
76 offset = attempt!(offset_add_layout(offset, assumed_malloc_overhead_layout));
77 offset = attempt!(offset_add_layout(offset, chunk_header_layout));
78 offset
79 };
80
81 let size_step = max(ASSUMED_PAGE_SIZE, chunk_header_layout.align());
82 let size_hint = max(size_hint, min);
83
84 let mut size = attempt!(if size_hint < size_step {
85 size_hint.checked_next_power_of_two()
87 } else {
88 up_align(size_hint, size_step)
89 });
90
91 debug_assert!(size % chunk_header_layout.align() == 0);
92 debug_assert!(size >= min);
93
94 debug_assert!(if size < size_step {
95 size.is_power_of_two()
96 } else {
97 size % size_step == 0
98 });
99
100 if self.up || self.chunk_header_layout.align() <= MIN_CHUNK_ALIGN {
107 let size_without_overhead = size - assumed_malloc_overhead_layout.size();
108 size = self.align_size(size_without_overhead);
109 }
110
111 NonZeroUsize::new(size)
112 }
113
114 #[inline(always)]
115 pub const fn calc_hint_from_capacity(self, layout: Layout) -> Option<usize> {
116 let Self { chunk_header_layout, .. } = self;
117
118 let maximum_required_padding = layout.align().saturating_sub(chunk_header_layout.align());
119 let required_size = attempt!(layout.size().checked_add(maximum_required_padding));
120 self.calc_hint_from_capacity_bytes(required_size)
121 }
122
123 #[inline(always)]
124 pub const fn calc_hint_from_capacity_bytes(self, bytes: usize) -> Option<usize> {
125 let Self {
126 up,
127 assumed_malloc_overhead_layout,
128 chunk_header_layout,
129 ..
130 } = self;
131
132 let mut size = 0;
133
134 if up {
135 size = attempt!(offset_add_layout(size, assumed_malloc_overhead_layout));
136 size = attempt!(offset_add_layout(size, chunk_header_layout));
137 size = attempt!(size.checked_add(bytes));
138 } else {
139 size = attempt!(offset_add_layout(size, assumed_malloc_overhead_layout));
140 size = attempt!(size.checked_add(bytes));
141 size = attempt!(offset_add_layout(size, chunk_header_layout));
142 }
143
144 size = attempt!(size.checked_add(MIN_CHUNK_ALIGN));
148
149 Some(size)
150 }
151}
152
153const fn max(lhs: usize, rhs: usize) -> usize {
154 if lhs > rhs { lhs } else { rhs }
155}
156
157const fn offset_add_layout(mut offset: usize, layout: Layout) -> Option<usize> {
158 offset = attempt!(up_align(offset, layout.align()));
159 offset = attempt!(offset.checked_add(layout.size()));
160 Some(offset)
161}
162
163#[inline(always)]
164const fn up_align(addr: usize, align: usize) -> Option<usize> {
165 debug_assert!(align.is_power_of_two());
166 let mask = align - 1;
167 let addr_plus_mask = attempt!(addr.checked_add(mask));
168 let aligned = addr_plus_mask & !mask;
169 Some(aligned)
170}
171
172#[inline(always)]
173const fn down_align(addr: usize, align: usize) -> usize {
174 debug_assert!(align.is_power_of_two());
175 let mask = align - 1;
176 addr & !mask
177}