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 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 assert_eq!(META, 16);
240 for size in PAGE_SIZES {
241 assert_eq!(BytePageSize::from_alloc_size(size.alloc_size()), size);
242 assert_eq!(BytePageSize::from_alloc_size(size.capacity() + META), size);
243 assert_eq!(
244 BytePageSize::from_alloc_size(size.alloc_size() - 1),
245 BytePageSize::Unset
246 );
247 assert_eq!(
248 BytePageSize::from_alloc_size(size.alloc_size() + 1),
249 BytePageSize::Unset
250 );
251 }
252 for units in [0, 3, 5, 10, 40, 63, 64 + 1, 128 + 1] {
253 assert_eq!(
254 BytePageSize::from_alloc_size(units * 4096),
255 BytePageSize::Unset
256 );
257 }
258 for size in [0, 1, 4095, 512 * 1024, usize::MAX, usize::MAX & !0xFFF] {
259 assert_eq!(BytePageSize::from_alloc_size(size), BytePageSize::Unset);
260 }
261 }
262
263 #[test]
264 fn page_size_for_capacity() {
265 assert_eq!(BytePageSize::for_capacity(0), BytePageSize::Size4);
266 for size in PAGE_SIZES {
267 let cap = size.capacity();
268 assert_eq!(BytePageSize::for_capacity(cap), size);
269 if size != BytePageSize::Size4 {
270 assert_eq!(BytePageSize::for_capacity(size.prev().capacity() + 1), size);
271 }
272 }
273 assert_eq!(
274 BytePageSize::for_capacity(BytePageSize::Size256.capacity() + 1),
275 BytePageSize::Unset
276 );
277 assert_eq!(BytePageSize::for_capacity(usize::MAX), BytePageSize::Unset);
278 }
279
280 #[test]
281 fn page_size_next_prev() {
282 let mut size = BytePageSize::Size4;
283 for expected in &PAGE_SIZES[1..] {
284 size = size.next();
285 assert_eq!(size, *expected);
286 }
287 assert_eq!(size.next(), BytePageSize::Unset);
288 assert_eq!(BytePageSize::Unset.next(), BytePageSize::Unset);
289
290 let mut size = BytePageSize::Unset;
291 for expected in PAGE_SIZES.iter().rev() {
292 size = size.prev();
293 assert_eq!(size, *expected);
294 }
295 assert_eq!(size.prev(), BytePageSize::Size4);
296
297 for pair in PAGE_SIZES.windows(2) {
298 assert!(pair[0].capacity() < pair[1].capacity());
299 }
300 }
301}