1use super::arena::{grown_capacity, step_bytes};
17use super::gc::Room;
18use crate::value::Value;
19
20const CLASSES: usize = 64;
23const LARGEST: u32 = 62;
25const SHORT_RUN: usize = 64;
27
28#[inline]
31pub const fn class_size(class: u32) -> u32 {
32 ((((2 | (class & 1)) as u64) << (class >> 1)) >> 1) as u32
33}
34
35#[inline]
37pub const fn class_of(len: u32) -> u32 {
38 let k = len.trailing_zeros();
39 if len.is_power_of_two() {
40 2 * k
41 } else {
42 2 * k + 3
43 }
44}
45
46#[inline]
49fn class_for(len: u32) -> (u32, u32) {
50 let k = u32::BITS - (len - 1).leading_zeros();
51 if k >= 2 && len <= 3 << (k - 2) {
52 (3 << (k - 2), 2 * k - 1)
53 } else {
54 (1 << k, 2 * k)
55 }
56}
57
58#[inline]
60fn class_at_most(slots: usize) -> u32 {
61 let k = usize::BITS - 1 - slots.leading_zeros();
62 let class = if k >= 1 && slots >= 3 << (k - 1) {
63 2 * k + 1
64 } else {
65 2 * k
66 };
67 class.min(LARGEST)
68}
69
70#[derive(Clone, Copy, Debug, PartialEq, Eq)]
72pub struct Range {
73 pub start: u32,
74 pub len: u32,
75}
76
77impl Range {
78 pub const EMPTY: Range = Range { start: 0, len: 0 };
79
80 #[inline]
84 pub const fn log(self) -> u8 {
85 if self.len == 0 {
86 u8::MAX
87 } else {
88 let class = class_of(self.len);
89 ((class >> 1) | ((class & 1) << 7)) as u8
90 }
91 }
92
93 #[inline]
95 pub const fn exponent(self) -> u8 {
96 if self.len == 0 {
97 u8::MAX
98 } else {
99 self.len.trailing_zeros() as u8
100 }
101 }
102
103 #[inline]
106 pub const fn from_exponent(start: u32, log: u8) -> Range {
107 if log == u8::MAX {
108 Range::EMPTY
109 } else {
110 Range {
111 start,
112 len: 1 << log,
113 }
114 }
115 }
116
117 #[inline]
118 pub const fn from_log(start: u32, log: u8) -> Range {
119 if log == u8::MAX {
120 Range::EMPTY
121 } else {
122 let len = ((((2 | (log >> 7)) as u64) << (log & 0x7f)) >> 1) as u32;
123 Range { start, len }
124 }
125 }
126}
127
128#[inline]
130pub fn class_len(len: u32) -> u32 {
131 if len == 0 { 0 } else { class_for(len).0 }
132}
133
134pub fn next_class_len(len: u32) -> u32 {
136 let class = class_for(len.max(1)).1;
137 class_size(if class == 0 { 2 } else { class + 1 })
138}
139
140pub struct ValueHeap {
141 values: Vec<Value>,
142 free: [Vec<u32>; CLASSES],
143 listed: u64,
146 runs: Vec<(u32, u32, u32)>,
149 current: (u32, u32),
151 free_slots: usize,
152 bits: Vec<u64>,
154}
155
156impl Default for ValueHeap {
157 fn default() -> Self {
158 Self::new()
159 }
160}
161
162impl ValueHeap {
163 pub fn new() -> Self {
164 ValueHeap {
165 values: Vec::new(),
166 free: std::array::from_fn(|_| Vec::new()),
167 listed: 0,
168 runs: Vec::new(),
169 current: (0, 0),
170 free_slots: 0,
171 bits: Vec::new(),
172 }
173 }
174
175 #[inline]
179 pub fn alloc(&mut self, len: u32, room: &mut Room) -> Range {
180 if len == 0 {
181 return Range::EMPTY;
182 }
183 let (len, class) = class_for(len);
184 self.alloc_class(len, class, room)
185 }
186
187 #[inline]
190 pub fn alloc_slots(&mut self, len: u32, room: &mut Room) -> Range {
191 if len == 0 {
192 return Range::EMPTY;
193 }
194 let len = len.next_power_of_two();
195 self.alloc_class(len, 2 * len.trailing_zeros(), room)
196 }
197
198 #[inline]
199 fn alloc_class(&mut self, len: u32, class: u32, room: &mut Room) -> Range {
200 if let Some(start) = self.free[class as usize].pop() {
201 self.free_slots -= len as usize;
202 return Range { start, len };
203 }
204 let (start, end) = self.current;
205 if end - start >= len {
206 self.current.0 += len;
207 self.free_slots -= len as usize;
208 return Range { start, len };
209 }
210 self.alloc_slow(len, class, room)
211 }
212
213 #[inline(never)]
216 fn alloc_slow(&mut self, len: u32, class: u32, room: &mut Room) -> Range {
217 loop {
218 let (start, end) = self.current;
219 if end - start >= len {
220 self.current.0 += len;
221 self.free_slots -= len as usize;
222 return Range { start, len };
223 }
224 if !self
226 .runs
227 .last()
228 .is_some_and(|&(_, _, longest)| longest >= len)
229 {
230 break;
231 }
232 self.push_run(start as usize, end as usize);
235 match self.runs.pop() {
236 Some((start, end, _)) => self.current = (start, end),
237 None => unreachable!("a run long enough was left"),
238 }
239 }
240 let mut larger = self.listed & !((2u64 << class) - 1);
241 while larger != 0 {
242 let source = larger.trailing_zeros();
243 larger &= larger - 1;
244 let Some(start) = self.free[source as usize].pop() else {
245 self.listed &= !(1 << source);
246 continue;
247 };
248 self.push_run(
251 (start + len) as usize,
252 (start + class_size(source)) as usize,
253 );
254 self.free_slots -= len as usize;
255 return Range { start, len };
256 }
257 self.alloc_fresh(len, room)
258 }
259
260 #[inline]
261 fn push(&mut self, start: u32, class: u32) {
262 self.free[class as usize].push(start);
263 self.listed |= 1 << class;
264 }
265
266 fn push_run(&mut self, mut start: usize, stop: usize) {
269 while start < stop {
270 let class = class_at_most(stop - start);
271 self.push(start as u32, class);
272 start += class_size(class) as usize;
273 }
274 }
275
276 fn alloc_fresh(&mut self, len: u32, room: &mut Room) -> Range {
277 let start = u32::try_from(self.values.len()).expect("value heap overflow");
278 let end = self.values.len() + len as usize;
279 assert!(end <= u32::MAX as usize, "value heap overflow");
280 if end > self.values.capacity() {
281 let before = self.values.capacity();
282 let target = grown_capacity(before, end, 8);
283 self.values.reserve_exact(target - self.values.len());
284 room.take((self.values.capacity() - before) * 8);
285 }
286 self.values.resize(end, Value::EMPTY);
287 Range { start, len }
288 }
289
290 pub fn growth_bytes(&self, len: u32) -> usize {
292 let len = len.next_power_of_two() * u32::from(len != 0);
296 let (start, end) = self.current;
297 if len == 0
298 || end - start >= len
299 || self
300 .runs
301 .last()
302 .is_some_and(|&(_, _, longest)| longest >= len)
303 || self.free[class_of(len) as usize..]
304 .iter()
305 .any(|list| !list.is_empty())
306 {
307 return 0;
308 }
309 let end = self.values.len() + len as usize;
310 let capacity = self.values.capacity();
311 (grown_capacity(capacity, end, 8) - capacity) * 8
312 }
313
314 pub fn grow(&mut self, range: Range, new_len: u32, room: &mut Room) -> Range {
318 if new_len <= range.len {
319 return range;
320 }
321 let new = self.alloc(new_len, room);
322 self.moved(range, new)
323 }
324
325 pub fn grow_slots(&mut self, range: Range, new_len: u32, room: &mut Room) -> Range {
327 if new_len <= range.len {
328 return range;
329 }
330 let new = self.alloc_slots(new_len, room);
331 self.moved(range, new)
332 }
333
334 fn moved(&mut self, range: Range, new: Range) -> Range {
336 let (from, to) = (range.start as usize, new.start as usize);
337 self.values.copy_within(from..from + range.len as usize, to);
338 self.free(range);
339 new
340 }
341
342 pub fn free(&mut self, range: Range) {
344 if range.len == 0 {
345 return;
346 }
347 debug_assert_eq!(class_len(range.len), range.len);
348 let start = range.start as usize;
349 self.values[start..start + range.len as usize].fill(Value::EMPTY);
350 self.push(range.start, class_of(range.len));
351 self.free_slots += range.len as usize;
352 }
353
354 pub fn begin_sweep(&mut self) {
358 let mut bits = std::mem::take(&mut self.bits);
359 bits.clear();
360 bits.resize(self.values.len().div_ceil(64), 0);
361 for (class, list) in self.free.iter_mut().enumerate() {
362 for start in list.drain(..) {
363 let end = start as usize + class_size(class as u32) as usize;
364 set_bits(&mut bits, start as usize, end);
365 }
366 }
367 let (start, end) = std::mem::take(&mut self.current);
368 for (start, end, _) in self.runs.drain(..).chain([(start, end, 0)]) {
369 if start < end {
370 set_bits(&mut bits, start as usize, end as usize);
371 }
372 }
373 self.bits = bits;
374 self.listed = 0;
375 self.free_slots = 0;
376 }
377
378 pub fn release(&mut self, range: Range) {
381 if range.len == 0 {
382 return;
383 }
384 let (start, end) = (range.start as usize, (range.start + range.len) as usize);
385 self.values[start..end].fill(Value::EMPTY);
386 set_bits(&mut self.bits, start, end);
387 }
388
389 pub fn finish_sweep(&mut self) {
397 let len = self.values.len();
398 let bits = std::mem::take(&mut self.bits);
399 let mut at = 0;
400 while let Some(start) = next_bit(&bits, at, true, len) {
401 let stop = next_bit(&bits, start, false, len).unwrap_or(len);
402 let capacity = self.values.capacity();
403 if stop == len && (capacity - start) * 4 > capacity {
404 self.values.truncate(start);
405 self.values.shrink_to(start + step_bytes(start * 8, 8) / 8);
406 break;
407 }
408 self.free_slots += stop - start;
409 if stop - start < SHORT_RUN {
410 self.push_run(start, stop);
411 } else {
412 self.runs.push((start as u32, stop as u32, 0));
413 }
414 at = stop;
415 }
416 self.bits = bits;
417 self.runs.reverse();
418 let mut longest = 0;
419 for run in &mut self.runs {
420 longest = longest.max(run.1 - run.0);
421 run.2 = longest;
422 }
423 for list in &mut self.free {
424 list.reverse();
425 if list.capacity() > 2 * list.len() + 16 {
426 list.shrink_to(2 * list.len());
427 }
428 }
429 }
430
431 #[cfg(test)]
433 fn coalesce(&mut self) {
434 self.begin_sweep();
435 self.finish_sweep();
436 }
437
438 #[inline]
439 #[track_caller]
440 pub fn get(&self, range: Range, slot: u32) -> Value {
441 debug_assert!(
442 slot < range.len,
443 "slot {slot} outside range of {}",
444 range.len
445 );
446 self.values[(range.start + slot) as usize]
447 }
448
449 #[inline]
450 #[track_caller]
451 pub fn set(&mut self, range: Range, slot: u32, value: Value) {
452 debug_assert!(
453 slot < range.len,
454 "slot {slot} outside range of {}",
455 range.len
456 );
457 self.values[(range.start + slot) as usize] = value;
458 }
459
460 #[inline]
462 pub fn get_or_empty(&self, range: Range, slot: u32) -> Value {
463 if slot < range.len {
464 self.get(range, slot)
465 } else {
466 Value::EMPTY
467 }
468 }
469
470 #[inline]
472 pub fn get_at(&self, index: u32) -> Value {
473 self.values[index as usize]
474 }
475
476 #[inline]
477 pub fn set_at(&mut self, index: u32, value: Value) {
478 self.values[index as usize] = value;
479 }
480
481 #[inline]
482 pub fn slice(&self, range: Range) -> &[Value] {
483 let start = range.start as usize;
484 &self.values[start..start + range.len as usize]
485 }
486
487 #[inline]
488 pub fn slice_mut(&mut self, range: Range) -> &mut [Value] {
489 let start = range.start as usize;
490 &mut self.values[start..start + range.len as usize]
491 }
492
493 pub fn total_slots(&self) -> usize {
495 self.values.len()
496 }
497
498 pub fn free_slots(&self) -> usize {
500 self.free_slots
501 }
502
503 pub fn used_slots(&self) -> usize {
505 self.values.len() - self.free_slots
506 }
507
508 pub fn fragmentation(&self) -> f64 {
510 if self.values.is_empty() {
511 0.0
512 } else {
513 self.free_slots as f64 / self.values.len() as f64
514 }
515 }
516
517 pub fn bytes(&self) -> usize {
518 self.values.capacity() * 8
519 + self
520 .free
521 .iter()
522 .map(|list| list.capacity() * 4)
523 .sum::<usize>()
524 + self.runs.capacity() * 12
525 + self.bits.capacity() * 8
526 }
527
528 pub fn free_blocks(&self) -> impl Iterator<Item = Range> + '_ {
530 self.free.iter().enumerate().flat_map(|(class, starts)| {
531 starts.iter().map(move |&start| Range {
532 start,
533 len: class_size(class as u32),
534 })
535 })
536 }
537
538 pub fn free_runs(&self) -> impl Iterator<Item = (u32, u32)> + '_ {
540 let (start, end) = self.current;
541 (start < end)
542 .then_some((start, end))
543 .into_iter()
544 .chain(self.runs.iter().rev().map(|&(start, end, _)| (start, end)))
545 }
546}
547
548fn set_bits(bits: &mut [u64], from: usize, to: usize) {
550 let (first, last) = (from / 64, (to - 1) / 64);
551 let low = !0u64 << (from % 64);
552 let high = !0u64 >> (63 - (to - 1) % 64);
553 if first == last {
554 bits[first] |= low & high;
555 return;
556 }
557 bits[first] |= low;
558 bits[first + 1..last].fill(!0);
559 bits[last] |= high;
560}
561
562fn next_bit(bits: &[u64], from: usize, set: bool, len: usize) -> Option<usize> {
565 if from >= len {
566 return None;
567 }
568 let flip = if set { 0 } else { !0 };
569 let mut word = from / 64;
570 let mut current = (bits[word] ^ flip) & (!0u64 << (from % 64));
571 loop {
572 if current != 0 {
573 let index = word * 64 + current.trailing_zeros() as usize;
574 return (index < len).then_some(index);
575 }
576 word += 1;
577 if word == bits.len() {
578 return None;
579 }
580 current = bits[word] ^ flip;
581 }
582}
583
584#[cfg(test)]
585mod tests {
586 use super::*;
587
588 #[test]
589 fn classes_round_up_and_reuse() {
590 let room = &mut Room::unbounded();
591 let mut heap = ValueHeap::new();
592 let a = heap.alloc(5, room);
593 assert_eq!(a, Range { start: 0, len: 6 });
594 assert!(heap.slice(a).iter().all(|v| v.is_empty()));
595 heap.set(a, 2, Value::int32(5));
596 let b = heap.alloc(1, room);
597 assert_eq!(b, Range { start: 6, len: 1 });
598 heap.free(a);
599 assert_eq!(heap.free_slots(), 6);
600 let c = heap.alloc(6, room);
601 assert_eq!(c.start, 0);
602 assert!(heap.get(c, 2).is_empty(), "freed slots are poisoned");
603 assert_eq!(heap.alloc(0, room), Range::EMPTY);
604 }
605
606 #[test]
607 fn grow_copies_and_frees() {
608 let room = &mut Room::unbounded();
609 let mut heap = ValueHeap::new();
610 let a = heap.alloc(2, room);
611 heap.set(a, 0, Value::int32(1));
612 heap.set(a, 1, Value::int32(2));
613 assert_eq!(heap.grow(a, 2, room), a);
614 let b = heap.grow(a, 3, room);
615 assert_eq!(b.len, 3);
616 assert_eq!(heap.get(b, 0), Value::int32(1));
617 assert_eq!(heap.get(b, 1), Value::int32(2));
618 assert!(heap.get(b, 2).is_empty());
619 assert_eq!(heap.free_blocks().collect::<Vec<_>>(), [a]);
620 let large = heap.alloc(1000, room);
621 assert_eq!(large.len, 1024);
622 heap.free(large);
623 assert_eq!(heap.alloc(513, room).start, large.start);
624 }
625
626 #[test]
627 fn a_request_splits_a_larger_range() {
628 let room = &mut Room::unbounded();
629 let mut heap = ValueHeap::new();
630 let big = heap.alloc(16, room);
631 let after = heap.alloc(1, room);
632 heap.free(big);
633 assert_eq!(heap.alloc(2, room), Range { start: 0, len: 2 });
634 assert_eq!(heap.alloc(2, room), Range { start: 14, len: 2 });
636 assert_eq!(heap.alloc(8, room), Range { start: 2, len: 8 });
637 assert_eq!(heap.alloc(4, room), Range { start: 10, len: 4 });
638 assert_eq!(heap.free_slots(), 0);
639 assert_eq!(heap.alloc(1, room).start, after.start + 1);
640 }
641
642 #[test]
643 fn requests_take_from_free_runs_in_address_order() {
644 let room = &mut Room::unbounded();
645 let mut heap = ValueHeap::new();
646 heap.alloc(1, room);
647 let big = heap.alloc(1024, room);
648 let tail = heap.alloc(1, room);
649 heap.free(big);
650 heap.coalesce();
651 assert_eq!(heap.free_runs().collect::<Vec<_>>(), [(1, 1025)]);
652 assert_eq!(heap.alloc(4, room).start, 1);
653 assert_eq!(heap.alloc(2, room).start, 5);
654 assert_eq!(heap.alloc(512, room).start, 7);
655 assert_eq!(heap.alloc(512, room).start, tail.start + 1);
658 assert_eq!(heap.free_runs().collect::<Vec<_>>(), [(519, 1025)]);
659 assert_eq!(heap.free_slots(), 506);
660 assert_eq!(heap.alloc(256, room).start, 519);
661 }
662
663 #[test]
664 fn coalescing_rebuilds_runs_and_cuts_the_end() {
665 let room = &mut Room::unbounded();
666 let mut heap = ValueHeap::new();
667 let ranges: Vec<Range> = (0..8).map(|_| heap.alloc(2, room)).collect();
668 for &index in &[1, 2, 3, 5, 6, 7] {
670 heap.free(ranges[index]);
671 }
672 heap.coalesce();
673 assert_eq!(heap.total_slots(), 10);
674 assert_eq!(heap.free_slots(), 6);
675 assert_eq!(
676 heap.free_blocks().collect::<Vec<_>>(),
677 [Range { start: 2, len: 6 }]
678 );
679 assert_eq!(heap.alloc(4, room).start, 2);
680 assert_eq!(heap.alloc(2, room).start, 6);
681 assert_eq!(heap.alloc(2, room).start, 10);
682 }
683
684 #[test]
685 fn a_short_free_end_stays_listed() {
686 let room = &mut Room::unbounded();
687 let mut heap = ValueHeap::new();
688 let ranges: Vec<Range> = (0..8).map(|_| heap.alloc(2, room)).collect();
689 heap.free(ranges[7]);
690 heap.coalesce();
691 assert_eq!(heap.total_slots(), 16);
692 assert_eq!(heap.free_blocks().collect::<Vec<_>>(), [ranges[7]]);
693 }
694
695 #[test]
696 fn a_long_free_end_gives_back_capacity() {
697 let room = &mut Room::unbounded();
698 let mut heap = ValueHeap::new();
699 let keep = heap.alloc(64, room);
700 let large = heap.alloc(1 << 20, room);
701 heap.free(large);
702 let before = heap.bytes();
703 heap.coalesce();
704 assert_eq!(heap.total_slots(), 64);
705 assert!(heap.bytes() < before / 4);
706 assert_eq!(heap.alloc(64, room).start, keep.start + 64);
707 }
708
709 #[test]
710 fn bit_runs() {
711 let mut bits = vec![0u64; 3];
712 set_bits(&mut bits, 3, 130);
713 assert_eq!(next_bit(&bits, 0, true, 192), Some(3));
714 assert_eq!(next_bit(&bits, 3, false, 192), Some(130));
715 assert_eq!(next_bit(&bits, 130, true, 192), None);
716 set_bits(&mut bits, 150, 151);
717 assert_eq!(next_bit(&bits, 130, true, 192), Some(150));
718 assert_eq!(next_bit(&bits, 150, false, 140), None);
719 }
720
721 #[test]
722 fn classes_are_powers_of_two_and_three_times_them() {
723 let sizes: Vec<u32> = (0..12)
724 .filter(|&class| class != 1)
725 .map(class_size)
726 .collect();
727 assert_eq!(sizes, [1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48]);
728 assert_eq!(class_size(LARGEST), 1 << 31);
729 for len in 1..5000 {
730 let (size, class) = class_for(len);
731 assert_eq!(class_size(class), size);
732 assert_eq!(class_of(size), class);
733 assert!(size >= len);
734 assert!(class <= 2 || class_size(class - 1 - u32::from(class == 2)) < len);
735 }
736 assert_eq!(class_len(10), 12);
737 assert_eq!(next_class_len(1024), 1536);
738 assert_eq!(next_class_len(1536), 2048);
739 assert_eq!(next_class_len(1), 2);
740 assert_eq!(class_at_most(7), class_of(6));
741 assert_eq!(class_at_most(5), class_of(4));
742 }
743
744 #[test]
745 fn range_log_round_trips() {
746 for len in [0, 1, 2, 3, 6, 12, 256, 384, 1 << 20, 3 << 29, 1 << 31] {
747 let range = Range { start: 9, len };
748 let decoded = Range::from_log(9, range.log());
749 assert_eq!(decoded.len, len);
750 assert!(len == 0 || decoded == range);
751 }
752 }
753}