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