1use std::marker::PhantomData;
6
7use std::collections::{HashMap, VecDeque};
8
9#[allow(dead_code)]
11pub struct ChainedArena {
12 blocks: Vec<ArenaBlock>,
13 block_size: usize,
14 total_alloc: usize,
15}
16#[allow(dead_code)]
17impl ChainedArena {
18 pub fn new(block_size: usize) -> Self {
20 let first = ArenaBlock::new(block_size);
21 Self {
22 blocks: vec![first],
23 block_size,
24 total_alloc: 0,
25 }
26 }
27 pub fn alloc(&mut self, bytes: usize, align: usize) -> usize {
29 let last = self.blocks.len() - 1;
30 if let Some(offset) = self.blocks[last].try_alloc(bytes, align) {
31 self.total_alloc += bytes;
32 return offset + last * self.block_size;
33 }
34 let new_block_size = self.block_size.max(bytes + align);
35 let mut block = ArenaBlock::new(new_block_size);
36 let offset = block
37 .try_alloc(bytes, align)
38 .expect("arena block allocation must succeed");
39 let block_idx = self.blocks.len();
40 self.blocks.push(block);
41 self.total_alloc += bytes;
42 offset + block_idx * self.block_size
43 }
44 pub fn num_blocks(&self) -> usize {
46 self.blocks.len()
47 }
48 pub fn total_allocated(&self) -> usize {
50 self.total_alloc
51 }
52}
53#[derive(Debug, Clone)]
58pub struct ArenaMap<T, V> {
59 data: Vec<Option<V>>,
60 _marker: PhantomData<T>,
61}
62impl<T, V> ArenaMap<T, V> {
63 pub fn new() -> Self {
65 Self {
66 data: Vec::new(),
67 _marker: PhantomData,
68 }
69 }
70 pub fn insert(&mut self, idx: Idx<T>, value: V) {
72 let i = idx.to_usize();
73 if i >= self.data.len() {
74 self.data.resize_with(i + 1, || None);
75 }
76 self.data[i] = Some(value);
77 }
78 pub fn get(&self, idx: Idx<T>) -> Option<&V> {
80 self.data.get(idx.to_usize())?.as_ref()
81 }
82 pub fn get_mut(&mut self, idx: Idx<T>) -> Option<&mut V> {
84 self.data.get_mut(idx.to_usize())?.as_mut()
85 }
86 pub fn remove(&mut self, idx: Idx<T>) -> Option<V> {
88 self.data.get_mut(idx.to_usize())?.take()
89 }
90 pub fn contains(&self, idx: Idx<T>) -> bool {
92 self.get(idx).is_some()
93 }
94 pub fn count(&self) -> usize {
96 self.data.iter().filter(|e| e.is_some()).count()
97 }
98 pub fn iter(&self) -> impl Iterator<Item = (Idx<T>, &V)> {
100 self.data
101 .iter()
102 .enumerate()
103 .filter_map(|(i, v)| v.as_ref().map(|val| (Idx::new(i as u32), val)))
104 }
105}
106#[allow(dead_code)]
108pub struct ScopeStack {
109 names: Vec<String>,
110}
111#[allow(dead_code)]
112impl ScopeStack {
113 pub fn new() -> Self {
115 Self { names: Vec::new() }
116 }
117 pub fn push(&mut self, name: impl Into<String>) {
119 self.names.push(name.into());
120 }
121 pub fn pop(&mut self) -> Option<String> {
123 self.names.pop()
124 }
125 pub fn current(&self) -> Option<&str> {
127 self.names.last().map(|s| s.as_str())
128 }
129 pub fn depth(&self) -> usize {
131 self.names.len()
132 }
133 pub fn is_empty(&self) -> bool {
135 self.names.is_empty()
136 }
137 pub fn path(&self) -> String {
139 self.names.join(".")
140 }
141}
142#[allow(dead_code)]
144pub struct StringInterner {
145 strings: Vec<String>,
146 map: std::collections::HashMap<String, u32>,
147}
148#[allow(dead_code)]
149impl StringInterner {
150 pub fn new() -> Self {
152 Self {
153 strings: Vec::new(),
154 map: std::collections::HashMap::new(),
155 }
156 }
157 pub fn intern(&mut self, s: &str) -> u32 {
159 if let Some(&id) = self.map.get(s) {
160 return id;
161 }
162 let id = self.strings.len() as u32;
163 self.strings.push(s.to_string());
164 self.map.insert(s.to_string(), id);
165 id
166 }
167 pub fn get(&self, id: u32) -> Option<&str> {
169 self.strings.get(id as usize).map(|s| s.as_str())
170 }
171 pub fn len(&self) -> usize {
173 self.strings.len()
174 }
175 pub fn is_empty(&self) -> bool {
177 self.strings.is_empty()
178 }
179}
180#[allow(dead_code)]
182pub struct DiagMeta {
183 pub(super) entries: Vec<(String, String)>,
184}
185#[allow(dead_code)]
186impl DiagMeta {
187 pub fn new() -> Self {
189 Self {
190 entries: Vec::new(),
191 }
192 }
193 pub fn add(&mut self, key: impl Into<String>, val: impl Into<String>) {
195 self.entries.push((key.into(), val.into()));
196 }
197 pub fn get(&self, key: &str) -> Option<&str> {
199 self.entries
200 .iter()
201 .find(|(k, _)| k == key)
202 .map(|(_, v)| v.as_str())
203 }
204 pub fn len(&self) -> usize {
206 self.entries.len()
207 }
208 pub fn is_empty(&self) -> bool {
210 self.entries.is_empty()
211 }
212}
213#[allow(dead_code)]
215#[allow(missing_docs)]
216pub struct StatCache<K: std::hash::Hash + Eq + Clone, V: Clone> {
217 pub inner: SimpleLruCache<K, V>,
219 pub hits: u64,
221 pub misses: u64,
223}
224#[allow(dead_code)]
225impl<K: std::hash::Hash + Eq + Clone, V: Clone> StatCache<K, V> {
226 pub fn new(capacity: usize) -> Self {
228 Self {
229 inner: SimpleLruCache::new(capacity),
230 hits: 0,
231 misses: 0,
232 }
233 }
234 pub fn get(&mut self, key: &K) -> Option<&V> {
236 let result = self.inner.get(key);
237 if result.is_some() {
238 self.hits += 1;
239 } else {
240 self.misses += 1;
241 }
242 None
243 }
244 pub fn put(&mut self, key: K, val: V) {
246 self.inner.put(key, val);
247 }
248 pub fn hit_rate(&self) -> f64 {
250 let total = self.hits + self.misses;
251 if total == 0 {
252 return 0.0;
253 }
254 self.hits as f64 / total as f64
255 }
256}
257#[allow(dead_code)]
259pub struct TwoGenerationArena {
260 pub(crate) nursery: GrowableArena,
261 pub(crate) stable: GrowableArena,
262 promotions: usize,
263}
264#[allow(dead_code)]
265impl TwoGenerationArena {
266 pub fn new(nursery_cap: usize, stable_cap: usize) -> Self {
268 Self {
269 nursery: GrowableArena::new(nursery_cap),
270 stable: GrowableArena::new(stable_cap),
271 promotions: 0,
272 }
273 }
274 pub fn alloc_nursery(&mut self, size: usize, align: usize) -> usize {
276 self.nursery.alloc(size, align)
277 }
278 pub fn promote(&mut self, size: usize, align: usize) -> usize {
280 self.promotions += 1;
281 self.stable.alloc(size, align)
282 }
283 pub fn minor_gc(&mut self) {
285 self.nursery.reset();
286 }
287 pub fn num_promotions(&self) -> usize {
289 self.promotions
290 }
291}
292#[allow(dead_code)]
294#[allow(missing_docs)]
295pub struct ArenaCheckpoint {
296 pub watermark: usize,
298}
299#[allow(dead_code)]
300impl ArenaCheckpoint {
301 pub fn create(arena: &LinearArena) -> Self {
303 Self {
304 watermark: arena.used(),
305 }
306 }
307 pub fn restore(self, arena: &mut LinearArena) {
309 arena.top = self.watermark;
310 }
311}
312#[allow(dead_code)]
314#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
315pub struct Timestamp(u64);
316#[allow(dead_code)]
317impl Timestamp {
318 pub const fn from_us(us: u64) -> Self {
320 Self(us)
321 }
322 pub fn as_us(self) -> u64 {
324 self.0
325 }
326 pub fn elapsed_since(self, earlier: Timestamp) -> u64 {
328 self.0.saturating_sub(earlier.0)
329 }
330}
331#[derive(Debug)]
336pub struct ScopedArena<T> {
337 inner: Arena<T>,
338}
339impl<T> ScopedArena<T> {
340 pub fn new() -> Self {
342 Self {
343 inner: Arena::new(),
344 }
345 }
346 pub fn alloc(&mut self, value: T) -> Idx<T> {
348 self.inner.alloc(value)
349 }
350 pub fn get(&self, idx: Idx<T>) -> &T {
352 self.inner.get(idx)
353 }
354 pub fn checkpoint(&self) -> u32 {
356 self.inner.len() as u32
357 }
358 pub fn rollback(&mut self, checkpoint: u32) {
362 self.inner.data.truncate(checkpoint as usize);
363 }
364 pub fn len(&self) -> usize {
366 self.inner.len()
367 }
368 pub fn is_empty(&self) -> bool {
370 self.inner.is_empty()
371 }
372}
373#[allow(dead_code)]
375pub struct LinearArena {
376 pub(crate) buf: Vec<u8>,
377 top: usize,
378 stats: ArenaStatsExt,
379}
380#[allow(dead_code)]
381impl LinearArena {
382 pub fn new(capacity: usize) -> Self {
384 Self {
385 buf: vec![0u8; capacity],
386 top: 0,
387 stats: ArenaStatsExt::new(),
388 }
389 }
390 pub fn alloc(&mut self, size: usize, align: usize) -> Option<usize> {
393 let aligned = (self.top + align - 1) & !(align - 1);
394 let end = aligned.checked_add(size)?;
395 if end > self.buf.len() {
396 return None;
397 }
398 let waste = aligned - self.top;
399 self.top = end;
400 self.stats.bytes_allocated += size;
401 self.stats.alloc_count += 1;
402 self.stats.wasted_bytes += waste;
403 Some(aligned)
404 }
405 pub fn reset(&mut self) {
407 self.top = 0;
408 self.stats = ArenaStatsExt::new();
409 }
410 pub fn used(&self) -> usize {
412 self.top
413 }
414 pub fn capacity(&self) -> usize {
416 self.buf.len()
417 }
418 pub fn stats(&self) -> &ArenaStatsExt {
420 &self.stats
421 }
422}
423#[derive(Debug, Clone, Copy, PartialEq, Eq)]
425pub struct ArenaStats {
426 pub len: usize,
428 pub capacity: usize,
430}
431impl ArenaStats {
432 pub fn utilisation(&self) -> f64 {
434 if self.capacity == 0 {
435 0.0
436 } else {
437 self.len as f64 / self.capacity as f64
438 }
439 }
440 pub fn free(&self) -> usize {
442 self.capacity.saturating_sub(self.len)
443 }
444}
445#[allow(dead_code)]
447pub struct AnnotationTable {
448 map: std::collections::HashMap<String, Vec<String>>,
449}
450#[allow(dead_code)]
451impl AnnotationTable {
452 pub fn new() -> Self {
454 Self {
455 map: std::collections::HashMap::new(),
456 }
457 }
458 pub fn annotate(&mut self, key: impl Into<String>, val: impl Into<String>) {
460 self.map.entry(key.into()).or_default().push(val.into());
461 }
462 pub fn get_all(&self, key: &str) -> &[String] {
464 self.map.get(key).map(|v| v.as_slice()).unwrap_or(&[])
465 }
466 pub fn num_keys(&self) -> usize {
468 self.map.len()
469 }
470 pub fn has(&self, key: &str) -> bool {
472 self.map.contains_key(key)
473 }
474}
475#[derive(Debug)]
480pub struct BumpArena {
481 buf: Vec<u8>,
482 pos: usize,
483}
484impl BumpArena {
485 pub fn with_capacity(cap: usize) -> Self {
487 Self {
488 buf: vec![0u8; cap],
489 pos: 0,
490 }
491 }
492 pub fn alloc_bytes(&mut self, size: usize) -> Option<usize> {
496 if self.pos + size > self.buf.len() {
497 None
498 } else {
499 let offset = self.pos;
500 self.pos += size;
501 Some(offset)
502 }
503 }
504 pub fn write_at(&mut self, offset: usize, data: &[u8]) {
506 self.buf[offset..offset + data.len()].copy_from_slice(data);
507 }
508 pub fn read_at(&self, offset: usize, len: usize) -> &[u8] {
510 &self.buf[offset..offset + len]
511 }
512 pub fn reset(&mut self) {
514 self.pos = 0;
515 }
516 pub fn used(&self) -> usize {
518 self.pos
519 }
520 pub fn capacity(&self) -> usize {
522 self.buf.len()
523 }
524 pub fn remaining(&self) -> usize {
526 self.buf.len().saturating_sub(self.pos)
527 }
528}
529#[derive(Debug)]
533pub struct ArenaPool<T> {
534 pub(super) pool: Vec<Arena<T>>,
535}
536impl<T> ArenaPool<T> {
537 pub fn new() -> Self {
539 Self { pool: Vec::new() }
540 }
541 pub fn acquire(&mut self) -> Arena<T> {
543 self.pool.pop().unwrap_or_default()
544 }
545 pub fn release(&mut self, mut arena: Arena<T>) {
547 arena.clear();
548 self.pool.push(arena);
549 }
550 pub fn pool_size(&self) -> usize {
552 self.pool.len()
553 }
554}
555#[allow(dead_code)]
557pub struct SimpleLruCache<K: std::hash::Hash + Eq + Clone, V: Clone> {
558 capacity: usize,
559 map: std::collections::HashMap<K, usize>,
560 keys: Vec<K>,
561 vals: Vec<V>,
562 order: Vec<usize>,
563}
564#[allow(dead_code)]
565impl<K: std::hash::Hash + Eq + Clone, V: Clone> SimpleLruCache<K, V> {
566 pub fn new(capacity: usize) -> Self {
568 assert!(capacity > 0);
569 Self {
570 capacity,
571 map: std::collections::HashMap::new(),
572 keys: Vec::new(),
573 vals: Vec::new(),
574 order: Vec::new(),
575 }
576 }
577 pub fn put(&mut self, key: K, val: V) {
579 if let Some(&idx) = self.map.get(&key) {
588 self.vals[idx] = val;
591 self.order.retain(|&x| x != idx);
594 self.order.insert(0, idx);
595 return;
596 }
597 match self.order.last() {
598 Some(&evict_idx) if self.keys.len() >= self.capacity => {
602 let map_key = key.clone();
607 let removed = self.map.remove_entry(&self.keys[evict_idx]);
608 let old_key = std::mem::replace(&mut self.keys[evict_idx], key);
612 let old_val = std::mem::replace(&mut self.vals[evict_idx], val);
613 self.order.rotate_right(1);
614 self.map.insert(map_key, evict_idx);
617 drop((removed, old_key, old_val));
618 }
619 _ => {
622 let map_key = key.clone();
623 let idx = self.keys.len();
624 self.keys.reserve(1);
628 self.vals.reserve(1);
629 self.order.reserve(1);
630 self.keys.push(key);
631 self.vals.push(val);
632 self.order.insert(0, idx);
633 self.map.insert(map_key, idx);
634 }
635 }
636 }
637 pub fn get(&mut self, key: &K) -> Option<&V> {
639 let idx = *self.map.get(key)?;
642 self.order.retain(|&x| x != idx);
643 self.order.insert(0, idx);
644 Some(&self.vals[idx])
645 }
646 pub fn len(&self) -> usize {
648 self.keys.len()
649 }
650 pub fn is_empty(&self) -> bool {
652 self.keys.is_empty()
653 }
654}
655#[allow(dead_code)]
657pub struct IdDispenser<T> {
658 next: u32,
659 _phantom: std::marker::PhantomData<T>,
660}
661#[allow(dead_code)]
662impl<T> IdDispenser<T> {
663 pub fn new() -> Self {
665 Self {
666 next: 0,
667 _phantom: std::marker::PhantomData,
668 }
669 }
670 #[allow(clippy::should_implement_trait)]
672 pub fn next(&mut self) -> TypedId<T> {
673 let id = TypedId::new(self.next);
674 self.next += 1;
675 id
676 }
677 pub fn count(&self) -> u32 {
679 self.next
680 }
681}
682#[allow(dead_code)]
684pub struct GrowableArena {
685 pub(crate) data: Vec<u8>,
686 top: usize,
687 count: usize,
688}
689#[allow(dead_code)]
690impl GrowableArena {
691 pub fn new(initial: usize) -> Self {
693 Self {
694 data: vec![0u8; initial.max(16)],
695 top: 0,
696 count: 0,
697 }
698 }
699 pub fn alloc(&mut self, size: usize, align: usize) -> usize {
701 let aligned = (self.top + align - 1) & !(align - 1);
702 let end = aligned + size;
703 if end > self.data.len() {
704 let new_cap = (self.data.len() * 2).max(end);
705 self.data.resize(new_cap, 0);
706 }
707 self.top = end;
708 self.count += 1;
709 aligned
710 }
711 pub fn used(&self) -> usize {
713 self.top
714 }
715 pub fn count(&self) -> usize {
717 self.count
718 }
719 pub fn reset(&mut self) {
721 self.top = 0;
722 self.count = 0;
723 }
724}
725#[allow(dead_code)]
727pub struct TypedArena<T> {
728 items: Vec<T>,
730 last: Option<T>,
732}
733#[allow(dead_code)]
734impl<T> TypedArena<T> {
735 pub fn new() -> Self {
737 Self {
738 items: Vec::new(),
739 last: None,
740 }
741 }
742 pub fn alloc(&mut self, val: T) -> &T {
744 if let Some(previous) = self.last.take() {
745 self.items.push(previous);
746 }
747 self.last.insert(val)
748 }
749 pub fn len(&self) -> usize {
751 self.items.len() + usize::from(self.last.is_some())
752 }
753 pub fn is_empty(&self) -> bool {
755 self.last.is_none()
756 }
757 pub fn clear(&mut self) {
759 let last = self.last.take();
763 self.items.clear();
764 drop(last);
765 }
766}
767#[allow(dead_code)]
769pub struct Slot<T> {
770 inner: Option<T>,
771}
772#[allow(dead_code)]
773impl<T> Slot<T> {
774 pub fn empty() -> Self {
776 Self { inner: None }
777 }
778 pub fn fill(&mut self, val: T) {
780 assert!(self.inner.is_none(), "Slot: already filled");
781 self.inner = Some(val);
782 }
783 pub fn get(&self) -> Option<&T> {
785 self.inner.as_ref()
786 }
787 pub fn is_filled(&self) -> bool {
789 self.inner.is_some()
790 }
791 pub fn take(&mut self) -> Option<T> {
793 self.inner.take()
794 }
795 pub fn get_or_fill_with(&mut self, f: impl FnOnce() -> T) -> &T {
797 self.inner.get_or_insert_with(f)
798 }
799}
800#[derive(Clone, Copy)]
804pub struct IdxRange<T> {
805 pub start: Idx<T>,
807 pub end: Idx<T>,
809}
810impl<T> IdxRange<T> {
811 pub fn new(start: Idx<T>, end: Idx<T>) -> Self {
813 Self { start, end }
814 }
815 pub fn empty_at(idx: Idx<T>) -> Self {
817 let r = idx.raw;
818 Self {
819 start: Idx::new(r),
820 end: Idx::new(r),
821 }
822 }
823 pub fn len(self) -> usize {
825 (self.end.raw as usize).saturating_sub(self.start.raw as usize)
826 }
827 pub fn is_empty(self) -> bool {
829 self.start.raw >= self.end.raw
830 }
831 pub fn contains(self, idx: Idx<T>) -> bool {
833 idx.raw >= self.start.raw && idx.raw < self.end.raw
834 }
835 pub fn iter(self) -> impl Iterator<Item = Idx<T>> {
837 (self.start.raw..self.end.raw).map(Idx::new)
838 }
839}
840#[allow(dead_code)]
842pub struct ArenaBlock {
843 data: Vec<u8>,
844 used: usize,
845}
846#[allow(dead_code)]
847impl ArenaBlock {
848 pub fn new(size: usize) -> Self {
850 Self {
851 data: vec![0u8; size],
852 used: 0,
853 }
854 }
855 pub fn try_alloc(&mut self, bytes: usize, align: usize) -> Option<usize> {
857 let base = (self.used + align - 1) & !(align - 1);
858 let end = base.checked_add(bytes)?;
859 if end > self.data.len() {
860 return None;
861 }
862 self.used = end;
863 Some(base)
864 }
865 pub fn remaining(&self) -> usize {
867 self.data.len() - self.used
868 }
869 pub fn block_size(&self) -> usize {
871 self.data.len()
872 }
873}
874#[derive(Debug)]
879pub struct InterningArena<T: PartialEq + Clone> {
880 inner: Arena<T>,
881}
882impl<T: PartialEq + Clone> InterningArena<T> {
883 pub fn new() -> Self {
885 Self {
886 inner: Arena::new(),
887 }
888 }
889 pub fn intern(&mut self, value: T) -> Idx<T> {
894 for (i, v) in self.inner.data.iter().enumerate() {
895 if *v == value {
896 return Idx::new(i as u32);
897 }
898 }
899 self.inner.alloc(value)
900 }
901 pub fn get(&self, idx: Idx<T>) -> &T {
903 self.inner.get(idx)
904 }
905 pub fn len(&self) -> usize {
907 self.inner.len()
908 }
909 pub fn is_empty(&self) -> bool {
911 self.inner.is_empty()
912 }
913 pub fn contains(&self, value: &T) -> bool {
915 self.inner.data.iter().any(|v| v == value)
916 }
917 pub fn stats(&self) -> ArenaStats {
919 self.inner.stats()
920 }
921}
922#[allow(dead_code)]
924pub struct LoopClock {
925 start: crate::wall_clock::Instant,
926 iters: u64,
927}
928#[allow(dead_code)]
929impl LoopClock {
930 pub fn start() -> Self {
932 Self {
933 start: crate::wall_clock::Instant::now(),
934 iters: 0,
935 }
936 }
937 pub fn tick(&mut self) {
939 self.iters += 1;
940 }
941 pub fn elapsed_us(&self) -> f64 {
943 self.start.elapsed().as_secs_f64() * 1e6
944 }
945 pub fn avg_us_per_iter(&self) -> f64 {
947 if self.iters == 0 {
948 return 0.0;
949 }
950 self.elapsed_us() / self.iters as f64
951 }
952 pub fn iters(&self) -> u64 {
954 self.iters
955 }
956}
957#[allow(dead_code)]
959pub struct MemoSlot<T: Clone> {
960 cached: Option<T>,
961}
962#[allow(dead_code)]
963impl<T: Clone> MemoSlot<T> {
964 pub fn new() -> Self {
966 Self { cached: None }
967 }
968 pub fn get_or_compute(&mut self, f: impl FnOnce() -> T) -> &T {
970 self.cached.get_or_insert_with(f)
971 }
972 pub fn invalidate(&mut self) {
974 self.cached = None;
975 }
976 pub fn is_cached(&self) -> bool {
978 self.cached.is_some()
979 }
980}
981#[derive(Debug)]
986pub struct Arena<T> {
987 data: Vec<T>,
988}
989impl<T> Arena<T> {
990 #[inline]
992 pub fn new() -> Self {
993 Self { data: Vec::new() }
994 }
995 #[inline]
997 pub fn with_capacity(capacity: usize) -> Self {
998 Self {
999 data: Vec::with_capacity(capacity),
1000 }
1001 }
1002 #[inline]
1004 pub fn alloc(&mut self, value: T) -> Idx<T> {
1005 let idx = self.data.len();
1006 assert!(idx < u32::MAX as usize, "arena overflow");
1007 self.data.push(value);
1008 Idx::new(idx as u32)
1009 }
1010 pub fn alloc_many(&mut self, values: impl IntoIterator<Item = T>) -> IdxRange<T> {
1012 let start = Idx::new(self.data.len() as u32);
1013 self.data.extend(values);
1014 let end = Idx::new(self.data.len() as u32);
1015 IdxRange::new(start, end)
1016 }
1017 #[inline]
1022 pub fn get(&self, idx: Idx<T>) -> &T {
1023 &self.data[idx.raw as usize]
1024 }
1025 #[inline]
1027 pub fn get_mut(&mut self, idx: Idx<T>) -> &mut T {
1028 &mut self.data[idx.raw as usize]
1029 }
1030 pub fn get_range(&self, range: IdxRange<T>) -> &[T] {
1032 &self.data[range.start.to_usize()..range.end.to_usize()]
1033 }
1034 #[inline]
1036 pub fn len(&self) -> usize {
1037 self.data.len()
1038 }
1039 #[inline]
1041 pub fn is_empty(&self) -> bool {
1042 self.data.is_empty()
1043 }
1044 pub fn next_idx(&self) -> Idx<T> {
1046 Idx::new(self.data.len() as u32)
1047 }
1048 pub fn iter_indexed(&self) -> impl Iterator<Item = (Idx<T>, &T)> {
1050 self.data
1051 .iter()
1052 .enumerate()
1053 .map(|(i, v)| (Idx::new(i as u32), v))
1054 }
1055 pub fn iter(&self) -> impl Iterator<Item = &T> {
1057 self.data.iter()
1058 }
1059 pub fn stats(&self) -> ArenaStats {
1061 ArenaStats {
1062 len: self.data.len(),
1063 capacity: self.data.capacity(),
1064 }
1065 }
1066 pub fn shrink_to_fit(&mut self) {
1068 self.data.shrink_to_fit();
1069 }
1070 pub fn clear(&mut self) {
1072 self.data.clear();
1073 }
1074}
1075#[allow(dead_code)]
1077pub struct BiMap<A: std::hash::Hash + Eq + Clone, B: std::hash::Hash + Eq + Clone> {
1078 forward: std::collections::HashMap<A, B>,
1079 backward: std::collections::HashMap<B, A>,
1080}
1081#[allow(dead_code)]
1082impl<A: std::hash::Hash + Eq + Clone, B: std::hash::Hash + Eq + Clone> BiMap<A, B> {
1083 pub fn new() -> Self {
1085 Self {
1086 forward: std::collections::HashMap::new(),
1087 backward: std::collections::HashMap::new(),
1088 }
1089 }
1090 pub fn insert(&mut self, a: A, b: B) {
1092 self.forward.insert(a.clone(), b.clone());
1093 self.backward.insert(b, a);
1094 }
1095 pub fn get_b(&self, a: &A) -> Option<&B> {
1097 self.forward.get(a)
1098 }
1099 pub fn get_a(&self, b: &B) -> Option<&A> {
1101 self.backward.get(b)
1102 }
1103 pub fn len(&self) -> usize {
1105 self.forward.len()
1106 }
1107 pub fn is_empty(&self) -> bool {
1109 self.forward.is_empty()
1110 }
1111}
1112#[allow(dead_code)]
1114pub struct ArenaString {
1115 pub(crate) offset: usize,
1116 len: usize,
1117}
1118#[allow(dead_code)]
1119impl ArenaString {
1120 pub fn store(arena: &mut LinearArena, s: &str) -> Option<Self> {
1122 let bytes = s.as_bytes();
1123 let offset = arena.alloc(bytes.len() + 1, 1)?;
1124 let start = offset;
1125 for (i, &b) in bytes.iter().enumerate() {
1126 arena.buf[start + i] = b;
1127 }
1128 arena.buf[start + bytes.len()] = 0;
1129 Some(Self {
1130 offset,
1131 len: bytes.len(),
1132 })
1133 }
1134 pub fn len(&self) -> usize {
1136 self.len
1137 }
1138 pub fn is_empty(&self) -> bool {
1140 self.len == 0
1141 }
1142}
1143#[allow(dead_code)]
1145pub struct IntervalSet {
1146 intervals: Vec<(i64, i64)>,
1147}
1148#[allow(dead_code)]
1149impl IntervalSet {
1150 pub fn new() -> Self {
1152 Self {
1153 intervals: Vec::new(),
1154 }
1155 }
1156 pub fn add(&mut self, lo: i64, hi: i64) {
1158 if lo > hi {
1159 return;
1160 }
1161 let mut new_lo = lo;
1162 let mut new_hi = hi;
1163 let mut i = 0;
1164 while i < self.intervals.len() {
1165 let (il, ih) = self.intervals[i];
1166 if ih < new_lo - 1 {
1167 i += 1;
1168 continue;
1169 }
1170 if il > new_hi + 1 {
1171 break;
1172 }
1173 new_lo = new_lo.min(il);
1174 new_hi = new_hi.max(ih);
1175 self.intervals.remove(i);
1176 }
1177 self.intervals.insert(i, (new_lo, new_hi));
1178 }
1179 pub fn contains(&self, x: i64) -> bool {
1181 self.intervals.iter().any(|&(lo, hi)| x >= lo && x <= hi)
1182 }
1183 pub fn num_intervals(&self) -> usize {
1185 self.intervals.len()
1186 }
1187 pub fn cardinality(&self) -> i64 {
1189 self.intervals.iter().map(|&(lo, hi)| hi - lo + 1).sum()
1190 }
1191}
1192#[allow(dead_code)]
1194pub struct MemoryRegionRegistry {
1195 regions: Vec<MemoryRegion>,
1196}
1197#[allow(dead_code)]
1198impl MemoryRegionRegistry {
1199 pub fn new() -> Self {
1201 Self {
1202 regions: Vec::new(),
1203 }
1204 }
1205 pub fn add(&mut self, region: MemoryRegion) {
1207 self.regions.push(region);
1208 }
1209 pub fn find(&self, addr: usize) -> Option<&MemoryRegion> {
1211 self.regions.iter().find(|r| r.contains(addr))
1212 }
1213 pub fn len(&self) -> usize {
1215 self.regions.len()
1216 }
1217 pub fn is_empty(&self) -> bool {
1219 self.regions.is_empty()
1220 }
1221}
1222#[derive(Debug, Default)]
1227pub struct DoubleArena<A, B> {
1228 pub first: Arena<A>,
1230 pub second: Arena<B>,
1232}
1233impl<A, B> DoubleArena<A, B> {
1234 pub fn new() -> Self {
1236 Self {
1237 first: Arena::new(),
1238 second: Arena::new(),
1239 }
1240 }
1241 pub fn alloc_pair(&mut self, a: A, b: B) -> (Idx<A>, Idx<B>) {
1246 let ia = self.first.alloc(a);
1247 let ib = self.second.alloc(b);
1248 (ia, ib)
1249 }
1250 pub fn total_len(&self) -> usize {
1252 self.first.len() + self.second.len()
1253 }
1254}
1255#[allow(dead_code)]
1257#[allow(missing_docs)]
1258pub struct MemoryRegion {
1259 pub label: String,
1261 pub base: usize,
1263 pub size: usize,
1265 pub active: bool,
1267}
1268#[allow(dead_code)]
1269impl MemoryRegion {
1270 pub fn new(label: impl Into<String>, base: usize, size: usize) -> Self {
1272 Self {
1273 label: label.into(),
1274 base,
1275 size,
1276 active: false,
1277 }
1278 }
1279 pub fn activate(&mut self) {
1281 self.active = true;
1282 }
1283 pub fn deactivate(&mut self) {
1285 self.active = false;
1286 }
1287 pub fn end(&self) -> usize {
1289 self.base + self.size
1290 }
1291 pub fn contains(&self, addr: usize) -> bool {
1293 addr >= self.base && addr < self.end()
1294 }
1295}
1296#[allow(dead_code)]
1298pub struct SparseBitSet {
1299 words: Vec<u64>,
1300}
1301#[allow(dead_code)]
1302impl SparseBitSet {
1303 pub fn new(capacity: usize) -> Self {
1305 let words = capacity.div_ceil(64);
1306 Self {
1307 words: vec![0u64; words],
1308 }
1309 }
1310 pub fn set(&mut self, i: usize) {
1312 let word = i / 64;
1313 let bit = i % 64;
1314 if word < self.words.len() {
1315 self.words[word] |= 1u64 << bit;
1316 }
1317 }
1318 pub fn clear(&mut self, i: usize) {
1320 let word = i / 64;
1321 let bit = i % 64;
1322 if word < self.words.len() {
1323 self.words[word] &= !(1u64 << bit);
1324 }
1325 }
1326 pub fn get(&self, i: usize) -> bool {
1328 let word = i / 64;
1329 let bit = i % 64;
1330 self.words.get(word).is_some_and(|w| w & (1u64 << bit) != 0)
1331 }
1332 pub fn count_ones(&self) -> u32 {
1334 self.words.iter().map(|w| w.count_ones()).sum()
1335 }
1336 pub fn union(&self, other: &SparseBitSet) -> SparseBitSet {
1338 let len = self.words.len().max(other.words.len());
1339 let mut result = SparseBitSet {
1340 words: vec![0u64; len],
1341 };
1342 for i in 0..self.words.len() {
1343 result.words[i] |= self.words[i];
1344 }
1345 for i in 0..other.words.len() {
1346 result.words[i] |= other.words[i];
1347 }
1348 result
1349 }
1350}
1351#[allow(dead_code)]
1353pub struct WorkQueue<T> {
1354 items: std::collections::VecDeque<T>,
1355}
1356#[allow(dead_code)]
1357impl<T> WorkQueue<T> {
1358 pub fn new() -> Self {
1360 Self {
1361 items: std::collections::VecDeque::new(),
1362 }
1363 }
1364 pub fn enqueue(&mut self, item: T) {
1366 self.items.push_back(item);
1367 }
1368 pub fn dequeue(&mut self) -> Option<T> {
1370 self.items.pop_front()
1371 }
1372 pub fn is_empty(&self) -> bool {
1374 self.items.is_empty()
1375 }
1376 pub fn len(&self) -> usize {
1378 self.items.len()
1379 }
1380}
1381#[allow(dead_code)]
1383pub struct FrequencyTable<T: std::hash::Hash + Eq + Clone> {
1384 counts: std::collections::HashMap<T, u64>,
1385}
1386#[allow(dead_code)]
1387impl<T: std::hash::Hash + Eq + Clone> FrequencyTable<T> {
1388 pub fn new() -> Self {
1390 Self {
1391 counts: std::collections::HashMap::new(),
1392 }
1393 }
1394 pub fn record(&mut self, item: T) {
1396 *self.counts.entry(item).or_insert(0) += 1;
1397 }
1398 pub fn freq(&self, item: &T) -> u64 {
1400 self.counts.get(item).copied().unwrap_or(0)
1401 }
1402 pub fn most_frequent(&self) -> Option<(&T, u64)> {
1404 self.counts
1405 .iter()
1406 .max_by_key(|(_, &v)| v)
1407 .map(|(k, &v)| (k, v))
1408 }
1409 pub fn total(&self) -> u64 {
1411 self.counts.values().sum()
1412 }
1413 pub fn distinct(&self) -> usize {
1415 self.counts.len()
1416 }
1417}
1418#[allow(dead_code)]
1420#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1421pub struct TypedId<T> {
1422 pub(super) id: u32,
1423 _phantom: std::marker::PhantomData<T>,
1424}
1425#[allow(dead_code)]
1426impl<T> TypedId<T> {
1427 pub const fn new(id: u32) -> Self {
1429 Self {
1430 id,
1431 _phantom: std::marker::PhantomData,
1432 }
1433 }
1434 pub fn raw(&self) -> u32 {
1436 self.id
1437 }
1438}
1439#[allow(dead_code)]
1441pub struct ScopedArenaExt {
1442 pub(crate) inner: LinearArena,
1443 watermarks: Vec<usize>,
1444}
1445#[allow(dead_code)]
1446impl ScopedArenaExt {
1447 pub fn new(capacity: usize) -> Self {
1449 Self {
1450 inner: LinearArena::new(capacity),
1451 watermarks: Vec::new(),
1452 }
1453 }
1454 pub fn push_scope(&mut self) {
1456 self.watermarks.push(self.inner.used());
1457 }
1458 pub fn pop_scope(&mut self) {
1461 let wm = self.watermarks.pop().expect("ScopedArena: no active scope");
1462 self.inner.top = wm;
1463 }
1464 pub fn alloc(&mut self, size: usize, align: usize) -> Option<usize> {
1466 self.inner.alloc(size, align)
1467 }
1468 pub fn scope_depth(&self) -> usize {
1470 self.watermarks.len()
1471 }
1472}
1473#[allow(dead_code)]
1475pub struct WorkStack<T> {
1476 items: Vec<T>,
1477}
1478#[allow(dead_code)]
1479impl<T> WorkStack<T> {
1480 pub fn new() -> Self {
1482 Self { items: Vec::new() }
1483 }
1484 pub fn push(&mut self, item: T) {
1486 self.items.push(item);
1487 }
1488 pub fn pop(&mut self) -> Option<T> {
1490 self.items.pop()
1491 }
1492 pub fn is_empty(&self) -> bool {
1494 self.items.is_empty()
1495 }
1496 pub fn len(&self) -> usize {
1498 self.items.len()
1499 }
1500}
1501#[allow(dead_code)]
1505pub struct ArenaVec<T: Copy> {
1506 base: usize,
1507 length: usize,
1508 _t: std::marker::PhantomData<T>,
1509}
1510#[allow(dead_code)]
1511impl<T: Copy> ArenaVec<T> {
1512 pub fn new(arena: &mut LinearArena, capacity: usize) -> Option<Self> {
1514 let base = arena.alloc(
1515 capacity * std::mem::size_of::<T>(),
1516 std::mem::align_of::<T>(),
1517 )?;
1518 Some(Self {
1519 base,
1520 length: 0,
1521 _t: std::marker::PhantomData,
1522 })
1523 }
1524 pub fn len(&self) -> usize {
1526 self.length
1527 }
1528 pub fn is_empty(&self) -> bool {
1530 self.length == 0
1531 }
1532}
1533#[allow(dead_code)]
1535#[allow(missing_docs)]
1536pub struct ArenaStatsExt {
1537 pub bytes_allocated: usize,
1539 pub alloc_count: usize,
1541 pub chunk_count: usize,
1543 pub wasted_bytes: usize,
1545}
1546#[allow(dead_code)]
1547impl ArenaStatsExt {
1548 pub fn new() -> Self {
1550 Self {
1551 bytes_allocated: 0,
1552 alloc_count: 0,
1553 chunk_count: 0,
1554 wasted_bytes: 0,
1555 }
1556 }
1557 pub fn avg_alloc_size(&self) -> f64 {
1559 if self.alloc_count == 0 {
1560 return 0.0;
1561 }
1562 self.bytes_allocated as f64 / self.alloc_count as f64
1563 }
1564 pub fn fragmentation(&self) -> f64 {
1566 let total = self.bytes_allocated + self.wasted_bytes;
1567 if total == 0 {
1568 return 0.0;
1569 }
1570 self.wasted_bytes as f64 / total as f64
1571 }
1572}
1573#[allow(dead_code)]
1575pub struct PoolArena {
1576 slot_size: usize,
1577 capacity: usize,
1578 free_list: Vec<usize>,
1579 data: Vec<u8>,
1580}
1581#[allow(dead_code)]
1582impl PoolArena {
1583 pub fn new(slot_size: usize, capacity: usize) -> Self {
1585 let data = vec![0u8; slot_size * capacity];
1586 let free_list: Vec<usize> = (0..capacity).collect();
1587 Self {
1588 slot_size,
1589 capacity,
1590 free_list,
1591 data,
1592 }
1593 }
1594 pub fn alloc_slot(&mut self) -> Option<usize> {
1596 self.free_list.pop()
1597 }
1598 pub fn free_slot(&mut self, idx: usize) {
1600 if idx < self.capacity {
1601 self.free_list.push(idx);
1602 }
1603 }
1604 pub fn available(&self) -> usize {
1606 self.free_list.len()
1607 }
1608 pub fn capacity(&self) -> usize {
1610 self.capacity
1611 }
1612 pub fn slot_size(&self) -> usize {
1614 self.slot_size
1615 }
1616}
1617#[derive(Debug)]
1621pub struct SlabArena<T> {
1622 data: Vec<Option<T>>,
1623 free_list: Vec<u32>,
1624}
1625impl<T> SlabArena<T> {
1626 pub fn new() -> Self {
1628 Self {
1629 data: Vec::new(),
1630 free_list: Vec::new(),
1631 }
1632 }
1633 pub fn with_capacity(cap: usize) -> Self {
1635 Self {
1636 data: Vec::with_capacity(cap),
1637 free_list: Vec::new(),
1638 }
1639 }
1640 pub fn alloc(&mut self, value: T) -> Idx<T> {
1642 if let Some(idx) = self.free_list.pop() {
1643 self.data[idx as usize] = Some(value);
1644 Idx::new(idx)
1645 } else {
1646 let idx = self.data.len() as u32;
1647 assert!(idx < u32::MAX, "slab arena overflow");
1648 self.data.push(Some(value));
1649 Idx::new(idx)
1650 }
1651 }
1652 pub fn free(&mut self, idx: Idx<T>) -> Option<T> {
1656 let slot = self.data.get_mut(idx.raw as usize)?;
1657 let value = slot.take()?;
1658 self.free_list.push(idx.raw);
1659 Some(value)
1660 }
1661 pub fn get(&self, idx: Idx<T>) -> Option<&T> {
1665 self.data.get(idx.raw as usize)?.as_ref()
1666 }
1667 pub fn get_mut(&mut self, idx: Idx<T>) -> Option<&mut T> {
1669 self.data.get_mut(idx.raw as usize)?.as_mut()
1670 }
1671 pub fn len(&self) -> usize {
1673 self.data.iter().filter(|s| s.is_some()).count()
1674 }
1675 pub fn capacity_slots(&self) -> usize {
1677 self.data.len()
1678 }
1679 pub fn is_empty(&self) -> bool {
1681 self.len() == 0
1682 }
1683 pub fn free_count(&self) -> usize {
1685 self.free_list.len()
1686 }
1687 pub fn iter_live(&self) -> impl Iterator<Item = (Idx<T>, &T)> {
1689 self.data
1690 .iter()
1691 .enumerate()
1692 .filter_map(|(i, slot)| slot.as_ref().map(|v| (Idx::new(i as u32), v)))
1693 }
1694}
1695#[derive(Clone, Copy)]
1700pub struct Idx<T> {
1701 pub(super) raw: u32,
1702 _marker: PhantomData<T>,
1703}
1704impl<T> Idx<T> {
1705 #[inline]
1710 pub(crate) fn new(raw: u32) -> Self {
1711 Self {
1712 raw,
1713 _marker: PhantomData,
1714 }
1715 }
1716 #[inline]
1718 pub fn raw(&self) -> u32 {
1719 self.raw
1720 }
1721 pub fn cast<U>(self) -> Idx<U> {
1726 Idx::new(self.raw)
1727 }
1728 pub fn is_first(self) -> bool {
1730 self.raw == 0
1731 }
1732 pub fn next(self) -> Self {
1734 Self::new(self.raw + 1)
1735 }
1736 pub fn to_usize(self) -> usize {
1738 self.raw as usize
1739 }
1740}
1741#[allow(dead_code)]
1743pub struct EventCounter {
1744 counts: std::collections::HashMap<String, u64>,
1745}
1746#[allow(dead_code)]
1747impl EventCounter {
1748 pub fn new() -> Self {
1750 Self {
1751 counts: std::collections::HashMap::new(),
1752 }
1753 }
1754 pub fn inc(&mut self, event: &str) {
1756 *self.counts.entry(event.to_string()).or_insert(0) += 1;
1757 }
1758 pub fn add(&mut self, event: &str, n: u64) {
1760 *self.counts.entry(event.to_string()).or_insert(0) += n;
1761 }
1762 pub fn get(&self, event: &str) -> u64 {
1764 self.counts.get(event).copied().unwrap_or(0)
1765 }
1766 pub fn total(&self) -> u64 {
1768 self.counts.values().sum()
1769 }
1770 pub fn reset(&mut self) {
1772 self.counts.clear();
1773 }
1774 pub fn event_names(&self) -> Vec<&str> {
1776 self.counts.keys().map(|s| s.as_str()).collect()
1777 }
1778}
1779#[cfg(test)]
1780mod typed_arena_tests;