1#![no_std]
2#![doc = include_str!("../README.md")]
3
4use core::ops::Range;
5
6use bit_field::BitField;
7
8pub trait BitAlloc: Default {
10 const CAP: usize;
12
13 const DEFAULT: Self;
15
16 fn alloc(&mut self) -> Option<usize>;
18
19 fn alloc_contiguous(
23 &mut self,
24 base: Option<usize>,
25 size: usize,
26 align_log2: usize,
27 ) -> Option<usize>;
28
29 fn next(&self, key: usize) -> Option<usize>;
31
32 fn dealloc(&mut self, key: usize) -> bool;
36
37 fn dealloc_contiguous(&mut self, base: usize, size: usize) -> bool;
41
42 fn insert(&mut self, range: Range<usize>);
44
45 fn remove(&mut self, range: Range<usize>);
47
48 #[deprecated = "use `!self.is_empty()` instead"]
50 fn any(&self) -> bool;
51
52 fn is_empty(&self) -> bool;
54
55 fn test(&self, key: usize) -> bool;
57}
58
59pub type BitAlloc256 = BitAllocCascade16<BitAlloc16>;
82pub type BitAlloc4K = BitAllocCascade16<BitAlloc256>;
84pub type BitAlloc64K = BitAllocCascade16<BitAlloc4K>;
86pub type BitAlloc1M = BitAllocCascade16<BitAlloc64K>;
88pub type BitAlloc16M = BitAllocCascade16<BitAlloc1M>;
90pub type BitAlloc256M = BitAllocCascade16<BitAlloc16M>;
92
93#[derive(Default)]
95pub struct BitAllocCascade16<T: BitAlloc> {
96 bitset: u16,
98 sub: [T; 16],
99}
100
101impl<T: BitAlloc> BitAlloc for BitAllocCascade16<T> {
102 const CAP: usize = T::CAP * 16;
103
104 const DEFAULT: Self = BitAllocCascade16 {
105 bitset: 0,
106 sub: [T::DEFAULT; 16],
107 };
108
109 fn alloc(&mut self) -> Option<usize> {
110 if !self.is_empty() {
111 let i = self.bitset.trailing_zeros() as usize;
112 let res = self.sub[i].alloc().unwrap() + i * T::CAP;
113 self.bitset.set_bit(i, !self.sub[i].is_empty());
114 Some(res)
115 } else {
116 None
117 }
118 }
119
120 fn alloc_contiguous(
121 &mut self,
122 base: Option<usize>,
123 size: usize,
124 align_log2: usize,
125 ) -> Option<usize> {
126 match base {
127 Some(base) => check_contiguous(self, base, Self::CAP, size, align_log2).then(|| {
128 self.remove(base..base + size);
129 base
130 }),
131 None => find_contiguous(self, Self::CAP, size, align_log2).inspect(|&base| {
132 self.remove(base..base + size);
133 }),
134 }
135 }
136
137 fn dealloc(&mut self, key: usize) -> bool {
138 let i = key / T::CAP;
139 self.bitset.set_bit(i, true);
140 self.sub[i].dealloc(key % T::CAP)
141 }
142
143 fn dealloc_contiguous(&mut self, base: usize, size: usize) -> bool {
144 let mut success = true;
145 let Range { start, end } = base..base + size;
146
147 if end > Self::CAP {
149 return false;
150 }
151
152 for i in start / T::CAP..=(end - 1) / T::CAP {
153 let begin = if start / T::CAP == i {
154 start % T::CAP
155 } else {
156 0
157 };
158 let end = if end / T::CAP == i {
159 end % T::CAP
160 } else {
161 T::CAP
162 };
163 success = success && self.sub[i].dealloc_contiguous(begin, end - begin);
164 self.bitset.set_bit(i, !self.sub[i].is_empty());
165 }
166 success
167 }
168
169 fn insert(&mut self, range: Range<usize>) {
170 self.for_range(range, |sub: &mut T, range| sub.insert(range));
171 }
172 fn remove(&mut self, range: Range<usize>) {
173 self.for_range(range, |sub: &mut T, range| sub.remove(range));
174 }
175 fn any(&self) -> bool {
176 !self.is_empty()
177 }
178 fn is_empty(&self) -> bool {
179 self.bitset == 0
180 }
181 fn test(&self, key: usize) -> bool {
182 self.sub[key / T::CAP].test(key % T::CAP)
183 }
184 fn next(&self, key: usize) -> Option<usize> {
185 let idx = key / T::CAP;
186 (idx..16).find_map(|i| {
187 if self.bitset.get_bit(i) {
188 let key = if i == idx { key - T::CAP * idx } else { 0 };
189 self.sub[i].next(key).map(|x| x + T::CAP * i)
190 } else {
191 None
192 }
193 })
194 }
195}
196
197impl<T: BitAlloc> BitAllocCascade16<T> {
198 fn for_range(&mut self, range: Range<usize>, f: impl Fn(&mut T, Range<usize>)) {
199 let Range { start, end } = range;
200 assert!(start <= end);
201 assert!(end <= Self::CAP);
202 for i in start / T::CAP..=(end - 1) / T::CAP {
203 let begin = if start / T::CAP == i {
204 start % T::CAP
205 } else {
206 0
207 };
208 let end = if end / T::CAP == i {
209 end % T::CAP
210 } else {
211 T::CAP
212 };
213 f(&mut self.sub[i], begin..end);
214 self.bitset.set_bit(i, !self.sub[i].is_empty());
215 }
216 }
217}
218
219#[derive(Default)]
244pub struct BitAlloc16(u16);
245
246impl BitAlloc for BitAlloc16 {
247 const CAP: usize = u16::BITS as usize;
248
249 const DEFAULT: Self = Self(0);
250
251 fn alloc(&mut self) -> Option<usize> {
252 let i = self.0.trailing_zeros() as usize;
253 if i < Self::CAP {
254 self.0.set_bit(i, false);
255 Some(i)
256 } else {
257 None
258 }
259 }
260 fn alloc_contiguous(
261 &mut self,
262 base: Option<usize>,
263 size: usize,
264 align_log2: usize,
265 ) -> Option<usize> {
266 match base {
267 Some(base) => check_contiguous(self, base, Self::CAP, size, align_log2).then(|| {
268 self.remove(base..base + size);
269 base
270 }),
271 None => find_contiguous(self, Self::CAP, size, align_log2).inspect(|&base| {
272 self.remove(base..base + size);
273 }),
274 }
275 }
276
277 fn dealloc(&mut self, key: usize) -> bool {
278 let success = !self.test(key);
279 self.0.set_bit(key, true);
280 success
281 }
282
283 fn dealloc_contiguous(&mut self, base: usize, size: usize) -> bool {
284 if self.0.get_bits(base..base + size) == 0 {
285 self.insert(base..base + size);
286 return true;
287 }
288 false
289 }
290
291 fn insert(&mut self, range: Range<usize>) {
292 self.0.set_bits(range.clone(), 0xffff.get_bits(range));
293 }
294 fn remove(&mut self, range: Range<usize>) {
295 self.0.set_bits(range, 0);
296 }
297 fn any(&self) -> bool {
298 !self.is_empty()
299 }
300 fn is_empty(&self) -> bool {
301 self.0 == 0
302 }
303 fn test(&self, key: usize) -> bool {
304 self.0.get_bit(key)
305 }
306 fn next(&self, key: usize) -> Option<usize> {
307 (key..Self::CAP).find(|&i| self.0.get_bit(i))
308 }
309}
310
311fn find_contiguous(
312 ba: &impl BitAlloc,
313 capacity: usize,
314 size: usize,
315 align_log2: usize,
316) -> Option<usize> {
317 if align_log2 >= 64 || capacity < (1 << align_log2) || ba.is_empty() {
318 return None;
319 }
320
321 let mut base = 0;
322 if let Some(start) = ba.next(base) {
324 base = align_up_log2(start, align_log2);
325 } else {
326 return None;
327 }
328
329 let mut offset = base;
330
331 while offset < capacity {
332 if let Some(next) = ba.next(offset) {
333 if next != offset {
334 assert!(next > offset);
337 base = (((next - 1) >> align_log2) + 1) << align_log2;
338 assert_ne!(offset, next);
339 offset = base;
340 continue;
341 }
342 } else {
343 return None;
344 }
345 offset += 1;
346 if offset - base == size {
347 return Some(base);
348 }
349 }
350 None
351}
352
353fn check_contiguous(
354 ba: &impl BitAlloc,
355 base: usize,
356 capacity: usize,
357 size: usize,
358 align_log2: usize,
359) -> bool {
360 if align_log2 >= 64 || capacity < (1 << align_log2) || ba.is_empty() {
361 return false;
362 }
363
364 if !is_aligned_log2(base, align_log2) {
366 return false;
367 }
368
369 let mut offset = base;
370 while offset < capacity {
371 if let Some(next) = ba.next(offset) {
372 if next != offset {
373 return false;
374 }
375 offset += 1;
376 if offset - base == size {
377 return true;
378 }
379 } else {
380 return false;
381 }
382 }
383 false
384}
385
386fn align_up_log2(base: usize, align_log2: usize) -> usize {
387 (base + ((1 << align_log2) - 1)) & !((1 << align_log2) - 1)
388}
389
390fn is_aligned_log2(base: usize, align_log2: usize) -> bool {
391 (base & ((1 << align_log2) - 1)) == 0
392}
393
394#[cfg(test)]
395mod tests {
396 use super::*;
397
398 #[test]
399 fn bitalloc16() {
400 let mut ba = BitAlloc16::default();
401 assert_eq!(BitAlloc16::CAP, 16);
402 ba.insert(0..16);
403 for i in 0..16 {
404 assert!(ba.test(i));
405 }
406 ba.remove(2..8);
407 assert_eq!(ba.alloc(), Some(0));
408 assert_eq!(ba.alloc(), Some(1));
409 assert_eq!(ba.alloc(), Some(8));
410 ba.dealloc(0);
411 ba.dealloc(1);
412 ba.dealloc(8);
413
414 assert!(!ba.is_empty());
415 for _ in 0..10 {
416 assert!(ba.alloc().is_some());
417 }
418 assert!(ba.is_empty());
419 assert!(ba.alloc().is_none());
420
421 for key in 0..16 {
422 assert!(ba.dealloc(key));
423 }
424
425 assert!(!ba.dealloc(10));
426 assert!(!ba.dealloc(0));
427
428 assert_eq!(ba.alloc(), Some(0));
429 assert_eq!(ba.test(0), false);
430 assert_eq!(ba.alloc_contiguous(None, 2, 0), Some(1));
431 assert_eq!(ba.test(1), false);
432 assert_eq!(ba.test(2), false);
433
434 assert_eq!(ba.alloc_contiguous(None, 2, 1), Some(4));
436 assert_eq!(ba.test(3), true);
438 assert_eq!(ba.test(4), false);
439 assert_eq!(ba.test(5), false);
440 assert_eq!(ba.next(5), Some(6));
441
442 assert_eq!(ba.alloc_contiguous(None, 3, 3), Some(8));
444 assert_eq!(ba.next(8), Some(11));
445
446 assert_eq!(ba.alloc_contiguous(Some(2), 2, 1), None);
447 assert_eq!(ba.alloc_contiguous(Some(6), 2, 1), Some(6));
448 assert_eq!(ba.alloc_contiguous(Some(6), 2, 1), None);
449
450 assert!(ba.dealloc_contiguous(8, 3));
451
452 assert_eq!(ba.alloc_contiguous(Some(8), 3, 2), Some(8));
453 assert_eq!(ba.next(8), Some(11));
454 assert_eq!(ba.alloc_contiguous(Some(11), 1, 0), Some(11));
455 assert_eq!(ba.next(11), Some(12));
456
457 assert_eq!(ba.alloc_contiguous(Some(12), 3, 2), Some(12));
458
459 assert_eq!(ba.next(12), Some(15));
460
461 assert_eq!(ba.alloc(), Some(3));
462 assert_eq!(ba.alloc(), Some(15));
463
464 assert!(ba.is_empty());
465 assert!(ba.alloc().is_none());
466
467 assert!(ba.dealloc_contiguous(6, 2));
468 assert!(ba.dealloc_contiguous(8, 3));
469 assert!(ba.dealloc_contiguous(11, 1));
470 assert!(ba.dealloc_contiguous(12, 3));
471 }
472
473 #[test]
474 fn bitalloc4k() {
475 let mut ba = BitAlloc4K::default();
476 assert_eq!(BitAlloc4K::CAP, 4096);
477 ba.insert(0..4096);
478 for i in 0..4096 {
479 assert!(ba.test(i));
480 }
481 ba.remove(2..4094);
482 for i in 0..4096 {
483 assert_eq!(ba.test(i), !(2..4094).contains(&i));
484 }
485 assert_eq!(ba.alloc(), Some(0));
486 assert_eq!(ba.alloc(), Some(1));
487 assert_eq!(ba.alloc(), Some(4094));
488 ba.dealloc(0);
489 ba.dealloc(1);
490 ba.dealloc(4094);
491
492 assert!(!ba.is_empty());
493 for _ in 0..4 {
494 assert!(ba.alloc().is_some());
495 }
496 assert!(ba.is_empty());
497 assert!(ba.alloc().is_none());
498 }
499
500 #[test]
501 fn bitalloc_contiguous() {
502 let mut ba0 = BitAlloc16::default();
503 ba0.insert(0..BitAlloc16::CAP);
504 ba0.remove(3..6);
505 assert_eq!(ba0.next(0), Some(0));
506 assert_eq!(ba0.alloc_contiguous(None, 1, 1), Some(0));
507 assert_eq!(find_contiguous(&ba0, BitAlloc4K::CAP, 2, 0), Some(1));
508
509 let mut ba = BitAlloc4K::default();
510 assert_eq!(BitAlloc4K::CAP, 4096);
511 ba.insert(0..BitAlloc4K::CAP);
512 ba.remove(3..6);
513 assert_eq!(ba.next(0), Some(0));
514 assert_eq!(ba.alloc_contiguous(None, 1, 1), Some(0));
515 assert_eq!(ba.next(0), Some(1));
516 assert_eq!(ba.next(1), Some(1));
517 assert_eq!(ba.next(2), Some(2));
518 assert_eq!(find_contiguous(&ba, BitAlloc4K::CAP, 2, 0), Some(1));
519 assert_eq!(ba.alloc_contiguous(None, 2, 0), Some(1));
520 assert_eq!(ba.alloc_contiguous(None, 2, 3), Some(8));
521 ba.remove(0..4096 - 64);
522 assert_eq!(ba.alloc_contiguous(None, 128, 7), None);
523 assert_eq!(ba.alloc_contiguous(None, 7, 3), Some(4096 - 64));
524 ba.insert(321..323);
525 assert_eq!(ba.alloc_contiguous(None, 2, 1), Some(4096 - 64 + 8));
526 assert_eq!(ba.alloc_contiguous(None, 2, 0), Some(321));
527 assert_eq!(ba.alloc_contiguous(None, 64, 6), None);
528 assert_eq!(ba.alloc_contiguous(None, 32, 4), Some(4096 - 48));
529 for i in 0..4096 - 64 + 7 {
530 assert!(ba.dealloc(i));
531 }
532 for i in 4096 - 64 + 8..4096 - 64 + 10 {
533 assert!(ba.dealloc(i));
534 }
535 for i in 4096 - 48..4096 - 16 {
536 assert!(ba.dealloc(i));
537 }
538 }
539}