1use crate::stvec;
2
3#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
9#[non_exhaustive]
10pub enum BytePageSize {
11 Size4 = 0,
13 Size8 = 1,
15 #[default]
17 Size16 = 2,
18 Size24 = 3,
20 Size32 = 4,
22 Size48 = 5,
24 Size64 = 6,
26 Size128 = 7,
28 Size256 = 8,
30 Unset = 9,
37}
38
39pub(crate) const PAGE_SIZES: [BytePageSize; 9] = [
41 BytePageSize::Size4,
42 BytePageSize::Size8,
43 BytePageSize::Size16,
44 BytePageSize::Size24,
45 BytePageSize::Size32,
46 BytePageSize::Size48,
47 BytePageSize::Size64,
48 BytePageSize::Size128,
49 BytePageSize::Size256,
50];
51
52const PAGE_UNIT_SHIFT: u32 = 12;
54
55const CLASS_BY_UNITS: [BytePageSize; 65] = {
58 let mut table = [BytePageSize::Unset; 65];
59 let mut i = 0;
60 while i < PAGE_SIZES.len() {
61 table[PAGE_SIZES[i].alloc_size() >> PAGE_UNIT_SHIFT] = PAGE_SIZES[i];
62 i += 1;
63 }
64 table
65};
66
67impl BytePageSize {
68 pub const fn for_capacity(capacity: usize) -> BytePageSize {
84 let mut i = 0;
85 while i < PAGE_SIZES.len() {
86 if capacity <= PAGE_SIZES[i].capacity() {
87 return PAGE_SIZES[i];
88 }
89 i += 1;
90 }
91 BytePageSize::Unset
92 }
93
94 #[must_use]
99 pub const fn next(self) -> BytePageSize {
100 match self {
101 BytePageSize::Size4 => BytePageSize::Size8,
102 BytePageSize::Size8 => BytePageSize::Size16,
103 BytePageSize::Size16 => BytePageSize::Size24,
104 BytePageSize::Size24 => BytePageSize::Size32,
105 BytePageSize::Size32 => BytePageSize::Size48,
106 BytePageSize::Size48 => BytePageSize::Size64,
107 BytePageSize::Size64 => BytePageSize::Size128,
108 BytePageSize::Size128 => BytePageSize::Size256,
109 BytePageSize::Size256 | BytePageSize::Unset => BytePageSize::Unset,
110 }
111 }
112
113 #[must_use]
118 pub const fn prev(self) -> BytePageSize {
119 match self {
120 BytePageSize::Size4 | BytePageSize::Size8 => BytePageSize::Size4,
121 BytePageSize::Size16 => BytePageSize::Size8,
122 BytePageSize::Size24 => BytePageSize::Size16,
123 BytePageSize::Size32 => BytePageSize::Size24,
124 BytePageSize::Size48 => BytePageSize::Size32,
125 BytePageSize::Size64 => BytePageSize::Size48,
126 BytePageSize::Size128 => BytePageSize::Size64,
127 BytePageSize::Size256 => BytePageSize::Size128,
128 BytePageSize::Unset => BytePageSize::Size256,
129 }
130 }
131
132 pub const fn capacity(self) -> usize {
138 self.alloc_size() - stvec::METADATA_SIZE
139 }
140
141 pub(crate) const fn alloc_size(self) -> usize {
142 match self {
143 BytePageSize::Size4 => 4 * 1024,
144 BytePageSize::Size8 => 8 * 1024,
145 BytePageSize::Size16 => 16 * 1024,
146 BytePageSize::Size24 => 24 * 1024,
147 BytePageSize::Size32 => 32 * 1024,
148 BytePageSize::Size48 => 48 * 1024,
149 BytePageSize::Size64 | BytePageSize::Unset => 64 * 1024,
150 BytePageSize::Size128 => 128 * 1024,
151 BytePageSize::Size256 => 256 * 1024,
152 }
153 }
154
155 #[inline]
158 pub(crate) const fn from_alloc_size(size: usize) -> BytePageSize {
159 let units = size >> PAGE_UNIT_SHIFT;
160 if size & ((1 << PAGE_UNIT_SHIFT) - 1) != 0 || units >= CLASS_BY_UNITS.len() {
161 BytePageSize::Unset
162 } else {
163 CLASS_BY_UNITS[units]
164 }
165 }
166
167 pub const fn half_capacity(self) -> usize {
171 match self {
172 BytePageSize::Size4 => 2 * 1024,
173 BytePageSize::Size8 => 4 * 1024,
174 BytePageSize::Size16 => 8 * 1024,
175 BytePageSize::Size24 => 12 * 1024,
176 BytePageSize::Size32
177 | BytePageSize::Size48
178 | BytePageSize::Size64
179 | BytePageSize::Size128
180 | BytePageSize::Size256
181 | BytePageSize::Unset => 16 * 1024,
182 }
183 }
184
185 pub const fn low(self) -> usize {
203 self.alloc_size() >> 4
204 }
205}
206
207#[cfg(test)]
208mod tests {
209 use super::*;
210
211 #[test]
212 fn page_size() {
213 const META: usize = stvec::METADATA_SIZE;
214 assert_eq!(BytePageSize::Size4.capacity(), 4 * 1024 - META);
215 assert_eq!(BytePageSize::Size8.capacity(), 8 * 1024 - META);
216 assert_eq!(BytePageSize::Size16.capacity(), 16 * 1024 - META);
217 assert_eq!(BytePageSize::Size24.capacity(), 24 * 1024 - META);
218 assert_eq!(BytePageSize::Size32.capacity(), 32 * 1024 - META);
219 assert_eq!(BytePageSize::Size48.capacity(), 48 * 1024 - META);
220 assert_eq!(BytePageSize::Size64.capacity(), 64 * 1024 - META);
221 assert_eq!(BytePageSize::Size128.capacity(), 128 * 1024 - META);
222 assert_eq!(BytePageSize::Size256.capacity(), 256 * 1024 - META);
223 assert_eq!(BytePageSize::Unset.capacity(), 64 * 1024 - META);
224 assert_eq!(BytePageSize::Size4.half_capacity(), 2 * 1024);
225 assert_eq!(BytePageSize::Size8.half_capacity(), 4 * 1024);
226 assert_eq!(BytePageSize::Size16.half_capacity(), 8 * 1024);
227 assert_eq!(BytePageSize::Size24.half_capacity(), 12 * 1024);
228 assert_eq!(BytePageSize::Size32.half_capacity(), 16 * 1024);
229 assert_eq!(BytePageSize::Size48.half_capacity(), 16 * 1024);
230 assert_eq!(BytePageSize::Size64.half_capacity(), 16 * 1024);
231 assert_eq!(BytePageSize::Size128.half_capacity(), 16 * 1024);
232 assert_eq!(BytePageSize::Size256.half_capacity(), 16 * 1024);
233 assert_eq!(BytePageSize::Unset.half_capacity(), 16 * 1024);
234 }
235
236 #[test]
237 fn page_size_from_alloc_size() {
238 const META: usize = stvec::METADATA_SIZE;
239 for size in PAGE_SIZES {
240 assert_eq!(BytePageSize::from_alloc_size(size.alloc_size()), size);
241 assert_eq!(BytePageSize::from_alloc_size(size.capacity() + META), size);
242 assert_eq!(
243 BytePageSize::from_alloc_size(size.alloc_size() - 1),
244 BytePageSize::Unset
245 );
246 assert_eq!(
247 BytePageSize::from_alloc_size(size.alloc_size() + 1),
248 BytePageSize::Unset
249 );
250 }
251 for units in [0, 3, 5, 10, 40, 63, 64 + 1, 128 + 1] {
252 assert_eq!(
253 BytePageSize::from_alloc_size(units * 4096),
254 BytePageSize::Unset
255 );
256 }
257 for size in [0, 1, 4095, 512 * 1024, usize::MAX, usize::MAX & !0xFFF] {
258 assert_eq!(BytePageSize::from_alloc_size(size), BytePageSize::Unset);
259 }
260 }
261
262 #[test]
263 fn page_size_for_capacity() {
264 assert_eq!(BytePageSize::for_capacity(0), BytePageSize::Size4);
265 for size in PAGE_SIZES {
266 let cap = size.capacity();
267 assert_eq!(BytePageSize::for_capacity(cap), size);
268 if size != BytePageSize::Size4 {
269 assert_eq!(BytePageSize::for_capacity(size.prev().capacity() + 1), size);
270 }
271 }
272 assert_eq!(
273 BytePageSize::for_capacity(BytePageSize::Size256.capacity() + 1),
274 BytePageSize::Unset
275 );
276 assert_eq!(BytePageSize::for_capacity(usize::MAX), BytePageSize::Unset);
277 }
278
279 #[test]
280 fn page_size_next_prev() {
281 let mut size = BytePageSize::Size4;
282 for expected in &PAGE_SIZES[1..] {
283 size = size.next();
284 assert_eq!(size, *expected);
285 }
286 assert_eq!(size.next(), BytePageSize::Unset);
287 assert_eq!(BytePageSize::Unset.next(), BytePageSize::Unset);
288
289 let mut size = BytePageSize::Unset;
290 for expected in PAGE_SIZES.iter().rev() {
291 size = size.prev();
292 assert_eq!(size, *expected);
293 }
294 assert_eq!(size.prev(), BytePageSize::Size4);
295
296 for pair in PAGE_SIZES.windows(2) {
297 assert!(pair[0].capacity() < pair[1].capacity());
298 }
299 }
300}