Skip to main content

oxilean_kernel/arena/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use std::marker::PhantomData;
6
7use std::collections::{HashMap, VecDeque};
8
9/// A chained-block arena that grows by adding new blocks on overflow.
10#[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    /// Creates a chained arena with the given initial block size.
19    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    /// Allocates `bytes` bytes with `align` alignment.
28    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    /// Returns the total number of blocks.
45    pub fn num_blocks(&self) -> usize {
46        self.blocks.len()
47    }
48    /// Returns total bytes allocated (excluding padding).
49    pub fn total_allocated(&self) -> usize {
50        self.total_alloc
51    }
52}
53/// A dense map from arena indices to values.
54///
55/// Backed by a `Vec<Option<V>>` aligned with an arena, allowing O(1) lookup
56/// by index.
57#[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    /// Create an empty `ArenaMap`.
64    pub fn new() -> Self {
65        Self {
66            data: Vec::new(),
67            _marker: PhantomData,
68        }
69    }
70    /// Insert a value for `idx`, growing the map if necessary.
71    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    /// Get a reference to the value for `idx`.
79    pub fn get(&self, idx: Idx<T>) -> Option<&V> {
80        self.data.get(idx.to_usize())?.as_ref()
81    }
82    /// Get a mutable reference to the value for `idx`.
83    pub fn get_mut(&mut self, idx: Idx<T>) -> Option<&mut V> {
84        self.data.get_mut(idx.to_usize())?.as_mut()
85    }
86    /// Remove the value at `idx`.
87    pub fn remove(&mut self, idx: Idx<T>) -> Option<V> {
88        self.data.get_mut(idx.to_usize())?.take()
89    }
90    /// Check whether `idx` has a value.
91    pub fn contains(&self, idx: Idx<T>) -> bool {
92        self.get(idx).is_some()
93    }
94    /// Number of non-empty entries.
95    pub fn count(&self) -> usize {
96        self.data.iter().filter(|e| e.is_some()).count()
97    }
98    /// Iterate over all (index, value) pairs.
99    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/// A simple stack-based scope tracker.
107#[allow(dead_code)]
108pub struct ScopeStack {
109    names: Vec<String>,
110}
111#[allow(dead_code)]
112impl ScopeStack {
113    /// Creates a new empty scope stack.
114    pub fn new() -> Self {
115        Self { names: Vec::new() }
116    }
117    /// Pushes a scope name.
118    pub fn push(&mut self, name: impl Into<String>) {
119        self.names.push(name.into());
120    }
121    /// Pops the current scope.
122    pub fn pop(&mut self) -> Option<String> {
123        self.names.pop()
124    }
125    /// Returns the current (innermost) scope name, or `None`.
126    pub fn current(&self) -> Option<&str> {
127        self.names.last().map(|s| s.as_str())
128    }
129    /// Returns the depth of the scope stack.
130    pub fn depth(&self) -> usize {
131        self.names.len()
132    }
133    /// Returns `true` if the stack is empty.
134    pub fn is_empty(&self) -> bool {
135        self.names.is_empty()
136    }
137    /// Returns the full path as a dot-separated string.
138    pub fn path(&self) -> String {
139        self.names.join(".")
140    }
141}
142/// Interns strings to save memory (each unique string stored once).
143#[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    /// Creates a new string interner.
151    pub fn new() -> Self {
152        Self {
153            strings: Vec::new(),
154            map: std::collections::HashMap::new(),
155        }
156    }
157    /// Interns `s` and returns its ID.
158    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    /// Returns the string for `id`.
168    pub fn get(&self, id: u32) -> Option<&str> {
169        self.strings.get(id as usize).map(|s| s.as_str())
170    }
171    /// Returns the total number of interned strings.
172    pub fn len(&self) -> usize {
173        self.strings.len()
174    }
175    /// Returns `true` if empty.
176    pub fn is_empty(&self) -> bool {
177        self.strings.is_empty()
178    }
179}
180/// A key-value store for diagnostic metadata.
181#[allow(dead_code)]
182pub struct DiagMeta {
183    pub(super) entries: Vec<(String, String)>,
184}
185#[allow(dead_code)]
186impl DiagMeta {
187    /// Creates an empty metadata store.
188    pub fn new() -> Self {
189        Self {
190            entries: Vec::new(),
191        }
192    }
193    /// Adds a key-value pair.
194    pub fn add(&mut self, key: impl Into<String>, val: impl Into<String>) {
195        self.entries.push((key.into(), val.into()));
196    }
197    /// Returns the value for `key`, or `None`.
198    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    /// Returns the number of entries.
205    pub fn len(&self) -> usize {
206        self.entries.len()
207    }
208    /// Returns `true` if empty.
209    pub fn is_empty(&self) -> bool {
210        self.entries.is_empty()
211    }
212}
213/// A counted-access cache that tracks hit and miss statistics.
214#[allow(dead_code)]
215#[allow(missing_docs)]
216pub struct StatCache<K: std::hash::Hash + Eq + Clone, V: Clone> {
217    /// The inner LRU cache.
218    pub inner: SimpleLruCache<K, V>,
219    /// Number of cache hits.
220    pub hits: u64,
221    /// Number of cache misses.
222    pub misses: u64,
223}
224#[allow(dead_code)]
225impl<K: std::hash::Hash + Eq + Clone, V: Clone> StatCache<K, V> {
226    /// Creates a new stat cache with the given capacity.
227    pub fn new(capacity: usize) -> Self {
228        Self {
229            inner: SimpleLruCache::new(capacity),
230            hits: 0,
231            misses: 0,
232        }
233    }
234    /// Performs a lookup, tracking hit/miss.
235    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    /// Inserts a key-value pair.
245    pub fn put(&mut self, key: K, val: V) {
246        self.inner.put(key, val);
247    }
248    /// Returns the hit rate.
249    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/// A two-generation arena (nursery + stable) for generational allocation.
258#[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    /// Creates a new two-generation arena.
267    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    /// Allocates in the nursery generation.
275    pub fn alloc_nursery(&mut self, size: usize, align: usize) -> usize {
276        self.nursery.alloc(size, align)
277    }
278    /// Promotes an allocation from nursery to stable generation.
279    pub fn promote(&mut self, size: usize, align: usize) -> usize {
280        self.promotions += 1;
281        self.stable.alloc(size, align)
282    }
283    /// Clears the nursery (minor GC).
284    pub fn minor_gc(&mut self) {
285        self.nursery.reset();
286    }
287    /// Returns the number of promotions performed.
288    pub fn num_promotions(&self) -> usize {
289        self.promotions
290    }
291}
292/// A savepoint that can be used to roll back an arena to a prior state.
293#[allow(dead_code)]
294#[allow(missing_docs)]
295pub struct ArenaCheckpoint {
296    /// The watermark position at checkpoint time.
297    pub watermark: usize,
298}
299#[allow(dead_code)]
300impl ArenaCheckpoint {
301    /// Creates a checkpoint at the current position in `arena`.
302    pub fn create(arena: &LinearArena) -> Self {
303        Self {
304            watermark: arena.used(),
305        }
306    }
307    /// Rolls back `arena` to this checkpoint.
308    pub fn restore(self, arena: &mut LinearArena) {
309        arena.top = self.watermark;
310    }
311}
312/// A monotonic timestamp in microseconds.
313#[allow(dead_code)]
314#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
315pub struct Timestamp(u64);
316#[allow(dead_code)]
317impl Timestamp {
318    /// Creates a timestamp from microseconds.
319    pub const fn from_us(us: u64) -> Self {
320        Self(us)
321    }
322    /// Returns the timestamp in microseconds.
323    pub fn as_us(self) -> u64 {
324        self.0
325    }
326    /// Returns the duration between two timestamps.
327    pub fn elapsed_since(self, earlier: Timestamp) -> u64 {
328        self.0.saturating_sub(earlier.0)
329    }
330}
331/// An arena that supports checkpointing and rollback.
332///
333/// By saving a checkpoint (the current length), the arena can be rolled back
334/// to discard all allocations made after that point.
335#[derive(Debug)]
336pub struct ScopedArena<T> {
337    inner: Arena<T>,
338}
339impl<T> ScopedArena<T> {
340    /// Create a new empty scoped arena.
341    pub fn new() -> Self {
342        Self {
343            inner: Arena::new(),
344        }
345    }
346    /// Allocate a value.
347    pub fn alloc(&mut self, value: T) -> Idx<T> {
348        self.inner.alloc(value)
349    }
350    /// Get a reference to the value at `idx`.
351    pub fn get(&self, idx: Idx<T>) -> &T {
352        self.inner.get(idx)
353    }
354    /// Create a checkpoint (the current length).
355    pub fn checkpoint(&self) -> u32 {
356        self.inner.len() as u32
357    }
358    /// Rollback to a previously saved checkpoint.
359    ///
360    /// All allocations after `checkpoint` are dropped.
361    pub fn rollback(&mut self, checkpoint: u32) {
362        self.inner.data.truncate(checkpoint as usize);
363    }
364    /// Current number of allocated values.
365    pub fn len(&self) -> usize {
366        self.inner.len()
367    }
368    /// Returns `true` if empty.
369    pub fn is_empty(&self) -> bool {
370        self.inner.is_empty()
371    }
372}
373/// A simple linear (bump) arena allocator over a fixed backing buffer.
374#[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    /// Creates a new arena with `capacity` bytes.
383    pub fn new(capacity: usize) -> Self {
384        Self {
385            buf: vec![0u8; capacity],
386            top: 0,
387            stats: ArenaStatsExt::new(),
388        }
389    }
390    /// Allocates `size` bytes with `align` alignment.
391    /// Returns the offset into the backing buffer, or `None` if full.
392    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    /// Resets the arena without releasing the backing buffer.
406    pub fn reset(&mut self) {
407        self.top = 0;
408        self.stats = ArenaStatsExt::new();
409    }
410    /// Returns the number of used bytes.
411    pub fn used(&self) -> usize {
412        self.top
413    }
414    /// Returns the total capacity.
415    pub fn capacity(&self) -> usize {
416        self.buf.len()
417    }
418    /// Returns a reference to the collected statistics.
419    pub fn stats(&self) -> &ArenaStatsExt {
420        &self.stats
421    }
422}
423/// Statistics about an arena's memory usage.
424#[derive(Debug, Clone, Copy, PartialEq, Eq)]
425pub struct ArenaStats {
426    /// Number of allocated values.
427    pub len: usize,
428    /// Current capacity (number of values that fit without reallocation).
429    pub capacity: usize,
430}
431impl ArenaStats {
432    /// Fraction of capacity used (0.0 to 1.0).
433    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    /// Number of free slots remaining before reallocation.
441    pub fn free(&self) -> usize {
442        self.capacity.saturating_sub(self.len)
443    }
444}
445/// A key-value annotation table for arbitrary metadata.
446#[allow(dead_code)]
447pub struct AnnotationTable {
448    map: std::collections::HashMap<String, Vec<String>>,
449}
450#[allow(dead_code)]
451impl AnnotationTable {
452    /// Creates an empty annotation table.
453    pub fn new() -> Self {
454        Self {
455            map: std::collections::HashMap::new(),
456        }
457    }
458    /// Adds an annotation value for the given key.
459    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    /// Returns all annotations for `key`.
463    pub fn get_all(&self, key: &str) -> &[String] {
464        self.map.get(key).map(|v| v.as_slice()).unwrap_or(&[])
465    }
466    /// Returns the number of distinct annotation keys.
467    pub fn num_keys(&self) -> usize {
468        self.map.len()
469    }
470    /// Returns `true` if the table has any annotations for `key`.
471    pub fn has(&self, key: &str) -> bool {
472        self.map.contains_key(key)
473    }
474}
475/// A simple bump allocator for byte slices.
476///
477/// Memory is allocated sequentially; deallocation of individual items is not
478/// supported. The entire arena can be reset at once.
479#[derive(Debug)]
480pub struct BumpArena {
481    buf: Vec<u8>,
482    pos: usize,
483}
484impl BumpArena {
485    /// Create a bump arena with the given capacity in bytes.
486    pub fn with_capacity(cap: usize) -> Self {
487        Self {
488            buf: vec![0u8; cap],
489            pos: 0,
490        }
491    }
492    /// Allocate `size` bytes, returning the start offset.
493    ///
494    /// Returns `None` if there is not enough space.
495    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    /// Write bytes at the given offset.
505    pub fn write_at(&mut self, offset: usize, data: &[u8]) {
506        self.buf[offset..offset + data.len()].copy_from_slice(data);
507    }
508    /// Read bytes from the given offset.
509    pub fn read_at(&self, offset: usize, len: usize) -> &[u8] {
510        &self.buf[offset..offset + len]
511    }
512    /// Reset the bump pointer without zeroing memory.
513    pub fn reset(&mut self) {
514        self.pos = 0;
515    }
516    /// Bytes used.
517    pub fn used(&self) -> usize {
518        self.pos
519    }
520    /// Total capacity in bytes.
521    pub fn capacity(&self) -> usize {
522        self.buf.len()
523    }
524    /// Remaining bytes.
525    pub fn remaining(&self) -> usize {
526        self.buf.len().saturating_sub(self.pos)
527    }
528}
529/// A pool of recycled arenas.
530///
531/// Allows arena instances to be reused across phases, reducing allocations.
532#[derive(Debug)]
533pub struct ArenaPool<T> {
534    pub(super) pool: Vec<Arena<T>>,
535}
536impl<T> ArenaPool<T> {
537    /// Create an empty pool.
538    pub fn new() -> Self {
539        Self { pool: Vec::new() }
540    }
541    /// Retrieve an arena from the pool (creating one if empty).
542    pub fn acquire(&mut self) -> Arena<T> {
543        self.pool.pop().unwrap_or_default()
544    }
545    /// Return an arena to the pool after clearing it.
546    pub fn release(&mut self, mut arena: Arena<T>) {
547        arena.clear();
548        self.pool.push(arena);
549    }
550    /// Number of arenas currently in the pool.
551    pub fn pool_size(&self) -> usize {
552        self.pool.len()
553    }
554}
555/// A simple LRU cache backed by a linked list + hash map.
556#[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    /// Creates a new LRU cache with the given capacity.
567    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    /// Inserts or updates a key-value pair.
578    pub fn put(&mut self, key: K, val: V) {
579        // `keys`, `vals` and `order` keep one length, with `order` holding
580        // each slot index once (most recently used first) and the length at
581        // most `capacity`, also when a call unwinds out of user code (`Clone`,
582        // `Hash` or `Eq` of `K`, the drop of a `K` or a `V`): `new` starts
583        // them empty, and every change below to a length or to `order` is a
584        // step that runs no user code and cannot fail, with its branch's user
585        // code (and the `reserve`s, which may panic) before the first such
586        // step or after the last. Every index in `map` is a slot index.
587        if let Some(&idx) = self.map.get(&key) {
588            // `map.get` ran `Hash` / `Eq` before any change. The old value's
589            // drop runs in this assignment and changes no length.
590            self.vals[idx] = val;
591            // `idx` is in `order` once, so `retain` removes one index and
592            // `insert` puts it back without growing the buffer.
593            self.order.retain(|&x| x != idx);
594            self.order.insert(0, idx);
595            return;
596        }
597        match self.order.last() {
598            // A full cache has `order.len() == keys.len() >= capacity > 0`
599            // (`new` asserts `capacity > 0`), so its least recently used slot
600            // is `order.last()`.
601            Some(&evict_idx) if self.keys.len() >= self.capacity => {
602                // The user code that comes before any change: the clone that
603                // goes into the map, and `Hash` / `Eq` in removing the evicted
604                // key from the map (a panic there leaves the map as it was).
605                // The removed key is held and dropped at the end.
606                let map_key = key.clone();
607                let removed = self.map.remove_entry(&self.keys[evict_idx]);
608                // Moves that run no user code: the slot takes the new key and
609                // value, and `rotate_right` takes the evicted index from the
610                // back of `order` to the front. No length changes.
611                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                // The user code that comes after: `Hash` / `Eq` in the map's
615                // insertion, then the drops of the evicted key and value.
616                self.map.insert(map_key, evict_idx);
617                drop((removed, old_key, old_val));
618            }
619            // Not full: a new slot. (With the lengths equal, `order` is never
620            // empty while `keys.len() >= capacity`.)
621            _ => {
622                let map_key = key.clone();
623                let idx = self.keys.len();
624                // Reserving first, the three appends below allocate nothing
625                // and cannot fail, so the lists grow together; `Hash` / `Eq`
626                // in the map's insertion run after them.
627                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    /// Returns a reference to the value for `key`, promoting it.
638    pub fn get(&mut self, key: &K) -> Option<&V> {
639        // `map.get` runs `Hash` / `Eq` before any change; `idx` is in `order`
640        // once (see `put`), so `retain` and `insert` change no length.
641        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    /// Returns the number of entries.
647    pub fn len(&self) -> usize {
648        self.keys.len()
649    }
650    /// Returns `true` if empty.
651    pub fn is_empty(&self) -> bool {
652        self.keys.is_empty()
653    }
654}
655/// A counter that dispenses monotonically increasing `TypedId` values.
656#[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    /// Creates a new dispenser starting from zero.
664    pub fn new() -> Self {
665        Self {
666            next: 0,
667            _phantom: std::marker::PhantomData,
668        }
669    }
670    /// Dispenses the next ID.
671    #[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    /// Returns the number of IDs dispensed.
678    pub fn count(&self) -> u32 {
679        self.next
680    }
681}
682/// A growable arena that reallocates its backing buffer when full.
683#[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    /// Creates a new growable arena with `initial` bytes.
692    pub fn new(initial: usize) -> Self {
693        Self {
694            data: vec![0u8; initial.max(16)],
695            top: 0,
696            count: 0,
697        }
698    }
699    /// Allocates `size` bytes, growing the backing buffer if needed.
700    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    /// Returns total bytes used.
712    pub fn used(&self) -> usize {
713        self.top
714    }
715    /// Returns total allocation count.
716    pub fn count(&self) -> usize {
717        self.count
718    }
719    /// Resets the arena.
720    pub fn reset(&mut self) {
721        self.top = 0;
722        self.count = 0;
723    }
724}
725/// A type-parameterised arena allocator that stores `T` values.
726#[allow(dead_code)]
727pub struct TypedArena<T> {
728    /// Every item allocated before the most recent one, in allocation order.
729    items: Vec<T>,
730    /// The most recently allocated item; `None` exactly when the arena is empty.
731    last: Option<T>,
732}
733#[allow(dead_code)]
734impl<T> TypedArena<T> {
735    /// Creates a new typed arena.
736    pub fn new() -> Self {
737        Self {
738            items: Vec::new(),
739            last: None,
740        }
741    }
742    /// Allocates `val` and returns a reference with the arena's lifetime.
743    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    /// Returns the number of allocated items.
750    pub fn len(&self) -> usize {
751        self.items.len() + usize::from(self.last.is_some())
752    }
753    /// Returns `true` if no items have been allocated.
754    pub fn is_empty(&self) -> bool {
755        self.last.is_none()
756    }
757    /// Clears all items.
758    pub fn clear(&mut self) {
759        // The latest item leaves the arena before any drop runs and is
760        // dropped last, after the earlier ones in allocation order; if an
761        // item's drop unwinds, the arena is already empty.
762        let last = self.last.take();
763        self.items.clear();
764        drop(last);
765    }
766}
767/// A slot that can hold a value, with lazy initialization.
768#[allow(dead_code)]
769pub struct Slot<T> {
770    inner: Option<T>,
771}
772#[allow(dead_code)]
773impl<T> Slot<T> {
774    /// Creates an empty slot.
775    pub fn empty() -> Self {
776        Self { inner: None }
777    }
778    /// Fills the slot with `val`.  Panics if already filled.
779    pub fn fill(&mut self, val: T) {
780        assert!(self.inner.is_none(), "Slot: already filled");
781        self.inner = Some(val);
782    }
783    /// Returns the slot's value, or `None`.
784    pub fn get(&self) -> Option<&T> {
785        self.inner.as_ref()
786    }
787    /// Returns `true` if the slot is filled.
788    pub fn is_filled(&self) -> bool {
789        self.inner.is_some()
790    }
791    /// Takes the value out of the slot.
792    pub fn take(&mut self) -> Option<T> {
793        self.inner.take()
794    }
795    /// Fills the slot if empty, returning a reference to the value.
796    pub fn get_or_fill_with(&mut self, f: impl FnOnce() -> T) -> &T {
797        self.inner.get_or_insert_with(f)
798    }
799}
800/// A contiguous range of typed indices `[start, end)`.
801///
802/// Used to represent a batch of values allocated together in an arena.
803#[derive(Clone, Copy)]
804pub struct IdxRange<T> {
805    /// Inclusive start index.
806    pub start: Idx<T>,
807    /// Exclusive end index.
808    pub end: Idx<T>,
809}
810impl<T> IdxRange<T> {
811    /// Create a new range.
812    pub fn new(start: Idx<T>, end: Idx<T>) -> Self {
813        Self { start, end }
814    }
815    /// Create an empty range starting at `idx`.
816    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    /// Length of the range.
824    pub fn len(self) -> usize {
825        (self.end.raw as usize).saturating_sub(self.start.raw as usize)
826    }
827    /// Returns `true` if the range is empty.
828    pub fn is_empty(self) -> bool {
829        self.start.raw >= self.end.raw
830    }
831    /// Check whether `idx` is in this range.
832    pub fn contains(self, idx: Idx<T>) -> bool {
833        idx.raw >= self.start.raw && idx.raw < self.end.raw
834    }
835    /// Iterate over all indices in this range.
836    pub fn iter(self) -> impl Iterator<Item = Idx<T>> {
837        (self.start.raw..self.end.raw).map(Idx::new)
838    }
839}
840/// A fixed-size block in a chained-block arena.
841#[allow(dead_code)]
842pub struct ArenaBlock {
843    data: Vec<u8>,
844    used: usize,
845}
846#[allow(dead_code)]
847impl ArenaBlock {
848    /// Creates a block with `size` bytes capacity.
849    pub fn new(size: usize) -> Self {
850        Self {
851            data: vec![0u8; size],
852            used: 0,
853        }
854    }
855    /// Tries to allocate `bytes` with alignment `align`.
856    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    /// Returns remaining capacity.
866    pub fn remaining(&self) -> usize {
867        self.data.len() - self.used
868    }
869    /// Returns the size of the block.
870    pub fn block_size(&self) -> usize {
871        self.data.len()
872    }
873}
874/// An arena that interns values, returning the same index for equal values.
875///
876/// If a value was previously allocated, its existing index is returned
877/// instead of allocating a new copy.
878#[derive(Debug)]
879pub struct InterningArena<T: PartialEq + Clone> {
880    inner: Arena<T>,
881}
882impl<T: PartialEq + Clone> InterningArena<T> {
883    /// Create a new empty interning arena.
884    pub fn new() -> Self {
885        Self {
886            inner: Arena::new(),
887        }
888    }
889    /// Allocate or retrieve an existing value.
890    ///
891    /// If `value` is already present, returns its existing index.
892    /// Otherwise allocates a new copy.
893    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    /// Get a reference to the interned value at `idx`.
902    pub fn get(&self, idx: Idx<T>) -> &T {
903        self.inner.get(idx)
904    }
905    /// Number of distinct values stored.
906    pub fn len(&self) -> usize {
907        self.inner.len()
908    }
909    /// Returns `true` if the arena is empty.
910    pub fn is_empty(&self) -> bool {
911        self.inner.is_empty()
912    }
913    /// Check whether `value` is already interned.
914    pub fn contains(&self, value: &T) -> bool {
915        self.inner.data.iter().any(|v| v == value)
916    }
917    /// Collect statistics.
918    pub fn stats(&self) -> ArenaStats {
919        self.inner.stats()
920    }
921}
922/// A clock that measures elapsed time in a loop.
923#[allow(dead_code)]
924pub struct LoopClock {
925    start: crate::wall_clock::Instant,
926    iters: u64,
927}
928#[allow(dead_code)]
929impl LoopClock {
930    /// Starts the clock.
931    pub fn start() -> Self {
932        Self {
933            start: crate::wall_clock::Instant::now(),
934            iters: 0,
935        }
936    }
937    /// Records one iteration.
938    pub fn tick(&mut self) {
939        self.iters += 1;
940    }
941    /// Returns the elapsed time in microseconds.
942    pub fn elapsed_us(&self) -> f64 {
943        self.start.elapsed().as_secs_f64() * 1e6
944    }
945    /// Returns the average microseconds per iteration.
946    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    /// Returns the number of iterations.
953    pub fn iters(&self) -> u64 {
954        self.iters
955    }
956}
957/// A memoized computation slot that stores a cached value.
958#[allow(dead_code)]
959pub struct MemoSlot<T: Clone> {
960    cached: Option<T>,
961}
962#[allow(dead_code)]
963impl<T: Clone> MemoSlot<T> {
964    /// Creates an uncomputed memo slot.
965    pub fn new() -> Self {
966        Self { cached: None }
967    }
968    /// Returns the cached value, computing it with `f` if absent.
969    pub fn get_or_compute(&mut self, f: impl FnOnce() -> T) -> &T {
970        self.cached.get_or_insert_with(f)
971    }
972    /// Invalidates the cached value.
973    pub fn invalidate(&mut self) {
974        self.cached = None;
975    }
976    /// Returns `true` if the value has been computed.
977    pub fn is_cached(&self) -> bool {
978        self.cached.is_some()
979    }
980}
981/// A typed arena for storing values contiguously.
982///
983/// Values are never moved once allocated, so references remain valid
984/// for the lifetime of the arena.
985#[derive(Debug)]
986pub struct Arena<T> {
987    data: Vec<T>,
988}
989impl<T> Arena<T> {
990    /// Create a new empty arena.
991    #[inline]
992    pub fn new() -> Self {
993        Self { data: Vec::new() }
994    }
995    /// Create a new arena with the specified capacity.
996    #[inline]
997    pub fn with_capacity(capacity: usize) -> Self {
998        Self {
999            data: Vec::with_capacity(capacity),
1000        }
1001    }
1002    /// Allocate a value in the arena and return its index.
1003    #[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    /// Allocate multiple values at once, returning the index range.
1011    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    /// Get a reference to the value at the given index.
1018    ///
1019    /// # Panics
1020    /// Panics if the index is out of bounds (in debug mode).
1021    #[inline]
1022    pub fn get(&self, idx: Idx<T>) -> &T {
1023        &self.data[idx.raw as usize]
1024    }
1025    /// Get a mutable reference to the value at the given index.
1026    #[inline]
1027    pub fn get_mut(&mut self, idx: Idx<T>) -> &mut T {
1028        &mut self.data[idx.raw as usize]
1029    }
1030    /// Get a slice of values for the given range.
1031    pub fn get_range(&self, range: IdxRange<T>) -> &[T] {
1032        &self.data[range.start.to_usize()..range.end.to_usize()]
1033    }
1034    /// Get the number of values in the arena.
1035    #[inline]
1036    pub fn len(&self) -> usize {
1037        self.data.len()
1038    }
1039    /// Check if the arena is empty.
1040    #[inline]
1041    pub fn is_empty(&self) -> bool {
1042        self.data.is_empty()
1043    }
1044    /// Get the index that would be assigned to the next allocation.
1045    pub fn next_idx(&self) -> Idx<T> {
1046        Idx::new(self.data.len() as u32)
1047    }
1048    /// Iterate over all (index, value) pairs.
1049    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    /// Iterate over all values.
1056    pub fn iter(&self) -> impl Iterator<Item = &T> {
1057        self.data.iter()
1058    }
1059    /// Collect the current size statistics.
1060    pub fn stats(&self) -> ArenaStats {
1061        ArenaStats {
1062            len: self.data.len(),
1063            capacity: self.data.capacity(),
1064        }
1065    }
1066    /// Shrink the arena's backing storage to fit.
1067    pub fn shrink_to_fit(&mut self) {
1068        self.data.shrink_to_fit();
1069    }
1070    /// Reset the arena, dropping all values.
1071    pub fn clear(&mut self) {
1072        self.data.clear();
1073    }
1074}
1075/// A bidirectional map between two types.
1076#[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    /// Creates an empty bidirectional map.
1084    pub fn new() -> Self {
1085        Self {
1086            forward: std::collections::HashMap::new(),
1087            backward: std::collections::HashMap::new(),
1088        }
1089    }
1090    /// Inserts a pair `(a, b)`.
1091    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    /// Looks up `b` for a given `a`.
1096    pub fn get_b(&self, a: &A) -> Option<&B> {
1097        self.forward.get(a)
1098    }
1099    /// Looks up `a` for a given `b`.
1100    pub fn get_a(&self, b: &B) -> Option<&A> {
1101        self.backward.get(b)
1102    }
1103    /// Returns the number of pairs.
1104    pub fn len(&self) -> usize {
1105        self.forward.len()
1106    }
1107    /// Returns `true` if empty.
1108    pub fn is_empty(&self) -> bool {
1109        self.forward.is_empty()
1110    }
1111}
1112/// A string slice stored in an arena (UTF-8, null-terminated).
1113#[allow(dead_code)]
1114pub struct ArenaString {
1115    pub(crate) offset: usize,
1116    len: usize,
1117}
1118#[allow(dead_code)]
1119impl ArenaString {
1120    /// Stores `s` in `arena` and returns a handle.
1121    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    /// Returns the length of the string in bytes.
1135    pub fn len(&self) -> usize {
1136        self.len
1137    }
1138    /// Returns `true` if the string is empty.
1139    pub fn is_empty(&self) -> bool {
1140        self.len == 0
1141    }
1142}
1143/// A set of non-overlapping integer intervals.
1144#[allow(dead_code)]
1145pub struct IntervalSet {
1146    intervals: Vec<(i64, i64)>,
1147}
1148#[allow(dead_code)]
1149impl IntervalSet {
1150    /// Creates an empty interval set.
1151    pub fn new() -> Self {
1152        Self {
1153            intervals: Vec::new(),
1154        }
1155    }
1156    /// Adds the interval `[lo, hi]` to the set.
1157    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    /// Returns `true` if `x` is in the set.
1180    pub fn contains(&self, x: i64) -> bool {
1181        self.intervals.iter().any(|&(lo, hi)| x >= lo && x <= hi)
1182    }
1183    /// Returns the number of intervals.
1184    pub fn num_intervals(&self) -> usize {
1185        self.intervals.len()
1186    }
1187    /// Returns the total count of integers covered.
1188    pub fn cardinality(&self) -> i64 {
1189        self.intervals.iter().map(|&(lo, hi)| hi - lo + 1).sum()
1190    }
1191}
1192/// A registry of memory regions.
1193#[allow(dead_code)]
1194pub struct MemoryRegionRegistry {
1195    regions: Vec<MemoryRegion>,
1196}
1197#[allow(dead_code)]
1198impl MemoryRegionRegistry {
1199    /// Creates an empty registry.
1200    pub fn new() -> Self {
1201        Self {
1202            regions: Vec::new(),
1203        }
1204    }
1205    /// Adds a region.
1206    pub fn add(&mut self, region: MemoryRegion) {
1207        self.regions.push(region);
1208    }
1209    /// Returns the region containing `addr`, or `None`.
1210    pub fn find(&self, addr: usize) -> Option<&MemoryRegion> {
1211        self.regions.iter().find(|r| r.contains(addr))
1212    }
1213    /// Returns the total number of regions.
1214    pub fn len(&self) -> usize {
1215        self.regions.len()
1216    }
1217    /// Returns `true` if empty.
1218    pub fn is_empty(&self) -> bool {
1219        self.regions.is_empty()
1220    }
1221}
1222/// Two arenas paired together, useful for storing interrelated values.
1223///
1224/// Allocations in each arena are independent, but the two are kept together
1225/// for lifetime management.
1226#[derive(Debug, Default)]
1227pub struct DoubleArena<A, B> {
1228    /// The first arena.
1229    pub first: Arena<A>,
1230    /// The second arena.
1231    pub second: Arena<B>,
1232}
1233impl<A, B> DoubleArena<A, B> {
1234    /// Create an empty `DoubleArena`.
1235    pub fn new() -> Self {
1236        Self {
1237            first: Arena::new(),
1238            second: Arena::new(),
1239        }
1240    }
1241    /// Allocate a pair of related values atomically.
1242    ///
1243    /// Returns `(idx_a, idx_b)` where `idx_a.raw() == idx_b.raw()` is NOT
1244    /// guaranteed — the arenas may have different lengths.
1245    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    /// Total allocations across both arenas.
1251    pub fn total_len(&self) -> usize {
1252        self.first.len() + self.second.len()
1253    }
1254}
1255/// Represents a named memory region used by the arena system.
1256#[allow(dead_code)]
1257#[allow(missing_docs)]
1258pub struct MemoryRegion {
1259    /// Human-readable label.
1260    pub label: String,
1261    /// Base offset.
1262    pub base: usize,
1263    /// Size in bytes.
1264    pub size: usize,
1265    /// Whether the region is currently in use.
1266    pub active: bool,
1267}
1268#[allow(dead_code)]
1269impl MemoryRegion {
1270    /// Creates a new memory region.
1271    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    /// Activates the region.
1280    pub fn activate(&mut self) {
1281        self.active = true;
1282    }
1283    /// Deactivates the region.
1284    pub fn deactivate(&mut self) {
1285        self.active = false;
1286    }
1287    /// Returns the exclusive end of the region.
1288    pub fn end(&self) -> usize {
1289        self.base + self.size
1290    }
1291    /// Returns `true` if `addr` is within the region.
1292    pub fn contains(&self, addr: usize) -> bool {
1293        addr >= self.base && addr < self.end()
1294    }
1295}
1296/// A simple sparse bit set.
1297#[allow(dead_code)]
1298pub struct SparseBitSet {
1299    words: Vec<u64>,
1300}
1301#[allow(dead_code)]
1302impl SparseBitSet {
1303    /// Creates a new bit set that can hold at least `capacity` bits.
1304    pub fn new(capacity: usize) -> Self {
1305        let words = capacity.div_ceil(64);
1306        Self {
1307            words: vec![0u64; words],
1308        }
1309    }
1310    /// Sets bit `i`.
1311    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    /// Clears bit `i`.
1319    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    /// Returns `true` if bit `i` is set.
1327    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    /// Returns the number of set bits.
1333    pub fn count_ones(&self) -> u32 {
1334        self.words.iter().map(|w| w.count_ones()).sum()
1335    }
1336    /// Returns the union with another bit set.
1337    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/// A FIFO work queue.
1352#[allow(dead_code)]
1353pub struct WorkQueue<T> {
1354    items: std::collections::VecDeque<T>,
1355}
1356#[allow(dead_code)]
1357impl<T> WorkQueue<T> {
1358    /// Creates a new empty queue.
1359    pub fn new() -> Self {
1360        Self {
1361            items: std::collections::VecDeque::new(),
1362        }
1363    }
1364    /// Enqueues a work item.
1365    pub fn enqueue(&mut self, item: T) {
1366        self.items.push_back(item);
1367    }
1368    /// Dequeues the next work item.
1369    pub fn dequeue(&mut self) -> Option<T> {
1370        self.items.pop_front()
1371    }
1372    /// Returns `true` if empty.
1373    pub fn is_empty(&self) -> bool {
1374        self.items.is_empty()
1375    }
1376    /// Returns the number of pending items.
1377    pub fn len(&self) -> usize {
1378        self.items.len()
1379    }
1380}
1381/// Tracks the frequency of items.
1382#[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    /// Creates a new empty frequency table.
1389    pub fn new() -> Self {
1390        Self {
1391            counts: std::collections::HashMap::new(),
1392        }
1393    }
1394    /// Records one occurrence of `item`.
1395    pub fn record(&mut self, item: T) {
1396        *self.counts.entry(item).or_insert(0) += 1;
1397    }
1398    /// Returns the frequency of `item`.
1399    pub fn freq(&self, item: &T) -> u64 {
1400        self.counts.get(item).copied().unwrap_or(0)
1401    }
1402    /// Returns the item with the highest frequency.
1403    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    /// Returns the total number of recordings.
1410    pub fn total(&self) -> u64 {
1411        self.counts.values().sum()
1412    }
1413    /// Returns the number of distinct items.
1414    pub fn distinct(&self) -> usize {
1415        self.counts.len()
1416    }
1417}
1418/// A type-safe wrapper around a `u32` identifier.
1419#[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    /// Creates a new typed ID.
1428    pub const fn new(id: u32) -> Self {
1429        Self {
1430            id,
1431            _phantom: std::marker::PhantomData,
1432        }
1433    }
1434    /// Returns the raw `u32` ID.
1435    pub fn raw(&self) -> u32 {
1436        self.id
1437    }
1438}
1439/// A scoped arena that tracks a watermark for bulk deallocation.
1440#[allow(dead_code)]
1441pub struct ScopedArenaExt {
1442    pub(crate) inner: LinearArena,
1443    watermarks: Vec<usize>,
1444}
1445#[allow(dead_code)]
1446impl ScopedArenaExt {
1447    /// Creates a scoped arena with `capacity` bytes.
1448    pub fn new(capacity: usize) -> Self {
1449        Self {
1450            inner: LinearArena::new(capacity),
1451            watermarks: Vec::new(),
1452        }
1453    }
1454    /// Pushes a scope: records the current allocation watermark.
1455    pub fn push_scope(&mut self) {
1456        self.watermarks.push(self.inner.used());
1457    }
1458    /// Pops a scope: resets allocation to the saved watermark.
1459    /// Panics if no scope is active.
1460    pub fn pop_scope(&mut self) {
1461        let wm = self.watermarks.pop().expect("ScopedArena: no active scope");
1462        self.inner.top = wm;
1463    }
1464    /// Allocates `size` bytes.
1465    pub fn alloc(&mut self, size: usize, align: usize) -> Option<usize> {
1466        self.inner.alloc(size, align)
1467    }
1468    /// Returns the current depth of nested scopes.
1469    pub fn scope_depth(&self) -> usize {
1470        self.watermarks.len()
1471    }
1472}
1473/// A simple LIFO work queue.
1474#[allow(dead_code)]
1475pub struct WorkStack<T> {
1476    items: Vec<T>,
1477}
1478#[allow(dead_code)]
1479impl<T> WorkStack<T> {
1480    /// Creates a new empty stack.
1481    pub fn new() -> Self {
1482        Self { items: Vec::new() }
1483    }
1484    /// Pushes a work item.
1485    pub fn push(&mut self, item: T) {
1486        self.items.push(item);
1487    }
1488    /// Pops the next work item.
1489    pub fn pop(&mut self) -> Option<T> {
1490        self.items.pop()
1491    }
1492    /// Returns `true` if empty.
1493    pub fn is_empty(&self) -> bool {
1494        self.items.is_empty()
1495    }
1496    /// Returns the number of pending work items.
1497    pub fn len(&self) -> usize {
1498        self.items.len()
1499    }
1500}
1501/// A growable array stored entirely within a `LinearArena`.
1502///
1503/// Does NOT support drop (elements must be `Copy`).
1504#[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    /// Creates a new `ArenaVec` with `capacity` elements in `arena`.
1513    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    /// Returns the number of elements.
1525    pub fn len(&self) -> usize {
1526        self.length
1527    }
1528    /// Returns `true` if the vec is empty.
1529    pub fn is_empty(&self) -> bool {
1530        self.length == 0
1531    }
1532}
1533/// Statistics collected from an arena allocator.
1534#[allow(dead_code)]
1535#[allow(missing_docs)]
1536pub struct ArenaStatsExt {
1537    /// Total bytes allocated.
1538    pub bytes_allocated: usize,
1539    /// Total number of allocations performed.
1540    pub alloc_count: usize,
1541    /// Number of chunks allocated.
1542    pub chunk_count: usize,
1543    /// Wasted bytes due to alignment padding.
1544    pub wasted_bytes: usize,
1545}
1546#[allow(dead_code)]
1547impl ArenaStatsExt {
1548    /// Creates a zeroed stats record.
1549    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    /// Returns the average allocation size in bytes.
1558    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    /// Returns the fragmentation ratio (wasted / total).
1565    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/// A fixed-size object pool backed by a free-list.
1574#[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    /// Creates a pool that holds `capacity` objects of `slot_size` bytes each.
1584    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    /// Allocates one slot.  Returns the slot index or `None` if exhausted.
1595    pub fn alloc_slot(&mut self) -> Option<usize> {
1596        self.free_list.pop()
1597    }
1598    /// Frees a slot by returning it to the free list.
1599    pub fn free_slot(&mut self, idx: usize) {
1600        if idx < self.capacity {
1601            self.free_list.push(idx);
1602        }
1603    }
1604    /// Returns the number of available (free) slots.
1605    pub fn available(&self) -> usize {
1606        self.free_list.len()
1607    }
1608    /// Returns the total pool capacity in slots.
1609    pub fn capacity(&self) -> usize {
1610        self.capacity
1611    }
1612    /// Returns the slot size in bytes.
1613    pub fn slot_size(&self) -> usize {
1614        self.slot_size
1615    }
1616}
1617/// An arena with O(1) deallocation via a free list.
1618///
1619/// Freed slots are tracked and reused on the next allocation.
1620#[derive(Debug)]
1621pub struct SlabArena<T> {
1622    data: Vec<Option<T>>,
1623    free_list: Vec<u32>,
1624}
1625impl<T> SlabArena<T> {
1626    /// Create a new empty slab arena.
1627    pub fn new() -> Self {
1628        Self {
1629            data: Vec::new(),
1630            free_list: Vec::new(),
1631        }
1632    }
1633    /// Create a slab arena with the given initial capacity.
1634    pub fn with_capacity(cap: usize) -> Self {
1635        Self {
1636            data: Vec::with_capacity(cap),
1637            free_list: Vec::new(),
1638        }
1639    }
1640    /// Allocate a value, reusing a freed slot if available.
1641    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    /// Free the value at `idx`, returning it.
1653    ///
1654    /// Returns `None` if the slot was already free.
1655    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    /// Get a reference to the value at `idx`.
1662    ///
1663    /// Returns `None` if the slot is free.
1664    pub fn get(&self, idx: Idx<T>) -> Option<&T> {
1665        self.data.get(idx.raw as usize)?.as_ref()
1666    }
1667    /// Get a mutable reference to the value at `idx`.
1668    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    /// Number of live (non-free) slots.
1672    pub fn len(&self) -> usize {
1673        self.data.iter().filter(|s| s.is_some()).count()
1674    }
1675    /// Total number of slots (including free ones).
1676    pub fn capacity_slots(&self) -> usize {
1677        self.data.len()
1678    }
1679    /// Returns `true` if there are no live values.
1680    pub fn is_empty(&self) -> bool {
1681        self.len() == 0
1682    }
1683    /// Number of slots on the free list.
1684    pub fn free_count(&self) -> usize {
1685        self.free_list.len()
1686    }
1687    /// Iterate over all live (non-free) (index, value) pairs.
1688    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/// A typed index into an arena.
1696///
1697/// This is a zero-cost abstraction over `u32` that provides type safety.
1698/// Equality checks are O(1) pointer comparisons.
1699#[derive(Clone, Copy)]
1700pub struct Idx<T> {
1701    pub(super) raw: u32,
1702    _marker: PhantomData<T>,
1703}
1704impl<T> Idx<T> {
1705    /// Create a new index from a raw u32 value.
1706    ///
1707    /// # Safety
1708    /// The caller must ensure the index is valid for the target arena.
1709    #[inline]
1710    pub(crate) fn new(raw: u32) -> Self {
1711        Self {
1712            raw,
1713            _marker: PhantomData,
1714        }
1715    }
1716    /// Get the raw index value.
1717    #[inline]
1718    pub fn raw(&self) -> u32 {
1719        self.raw
1720    }
1721    /// Cast to a different type without changing the raw index.
1722    ///
1723    /// # Safety
1724    /// The caller must ensure the reinterpreted index is valid.
1725    pub fn cast<U>(self) -> Idx<U> {
1726        Idx::new(self.raw)
1727    }
1728    /// Check whether this index is the first (index 0).
1729    pub fn is_first(self) -> bool {
1730        self.raw == 0
1731    }
1732    /// Increment the index by 1 (without bounds checking).
1733    pub fn next(self) -> Self {
1734        Self::new(self.raw + 1)
1735    }
1736    /// Convert to `usize` for slice indexing.
1737    pub fn to_usize(self) -> usize {
1738        self.raw as usize
1739    }
1740}
1741/// A simple event counter with named events.
1742#[allow(dead_code)]
1743pub struct EventCounter {
1744    counts: std::collections::HashMap<String, u64>,
1745}
1746#[allow(dead_code)]
1747impl EventCounter {
1748    /// Creates a new empty counter.
1749    pub fn new() -> Self {
1750        Self {
1751            counts: std::collections::HashMap::new(),
1752        }
1753    }
1754    /// Increments the counter for `event`.
1755    pub fn inc(&mut self, event: &str) {
1756        *self.counts.entry(event.to_string()).or_insert(0) += 1;
1757    }
1758    /// Adds `n` to the counter for `event`.
1759    pub fn add(&mut self, event: &str, n: u64) {
1760        *self.counts.entry(event.to_string()).or_insert(0) += n;
1761    }
1762    /// Returns the count for `event`.
1763    pub fn get(&self, event: &str) -> u64 {
1764        self.counts.get(event).copied().unwrap_or(0)
1765    }
1766    /// Returns the total count across all events.
1767    pub fn total(&self) -> u64 {
1768        self.counts.values().sum()
1769    }
1770    /// Resets all counters.
1771    pub fn reset(&mut self) {
1772        self.counts.clear();
1773    }
1774    /// Returns all event names.
1775    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;