use std::cell::RefCell;
pub struct HeapArena {
generations: Vec<Generation>,
}
struct Generation {
strings: Vec<String>,
buffers: Vec<Vec<u8>>,
}
impl Default for HeapArena {
fn default() -> Self {
Self::new()
}
}
impl HeapArena {
pub fn new() -> Self {
HeapArena {
generations: vec![Generation {
strings: Vec::new(),
buffers: Vec::new(),
}],
}
}
pub fn push(&mut self) {
self.generations.push(Generation {
strings: Vec::new(),
buffers: Vec::new(),
});
}
pub fn pop(&mut self) {
if self.generations.len() > 1 {
self.generations.pop();
}
}
pub fn free_current(&mut self) {
if let Some(gen) = self.generations.last_mut() {
gen.strings.clear();
gen.buffers.clear();
}
}
pub fn alloc_string(&mut self, s: String) -> &str {
if let Some(gen) = self.generations.last_mut() {
gen.strings.push(s);
gen.strings.last().map(|s| s.as_str()).unwrap()
} else {
panic!("No generation available")
}
}
pub fn alloc_bytes(&mut self, bytes: Vec<u8>) -> &[u8] {
if let Some(gen) = self.generations.last_mut() {
gen.buffers.push(bytes);
gen.buffers.last().map(|b| b.as_slice()).unwrap()
} else {
panic!("No generation available")
}
}
pub fn depth(&self) -> usize {
self.generations.len()
}
}
thread_local! {
static HEAP: RefCell<HeapArena> = RefCell::new(HeapArena::new());
}
pub fn pushheap() {
HEAP.with(|h| h.borrow_mut().push());
}
pub fn popheap() {
HEAP.with(|h| h.borrow_mut().pop());
}
pub fn freeheap() {
HEAP.with(|h| h.borrow_mut().free_current());
}
pub fn zalloc<T: Default>() -> Box<T> {
Box::default()
}
pub fn zshcalloc<T: Default>() -> Box<T> {
Box::default()
}
pub fn zrealloc<T>(v: &mut Vec<T>, new_size: usize)
where
T: Default + Clone,
{
v.resize(new_size, T::default());
}
pub fn zfree<T>(_ptr: Box<T>) {
}
pub fn zsfree(_s: String) {
}
pub fn dupstring(s: &str) -> String {
s.to_string()
}
pub fn dupstring_wlen(s: &str, len: usize) -> String {
s.chars().take(len).collect()
}
pub fn zhalloc_string(s: &str) -> String {
s.to_string()
}
pub fn zheapptr<T>(_ptr: &T) -> bool {
true
}
pub fn hrealloc(old: Vec<u8>, new_size: usize) -> Vec<u8> {
let mut v = old;
v.resize(new_size, 0);
v
}
pub fn zarrdup(arr: &[String]) -> Vec<String> {
arr.to_vec()
}
pub fn arrdup_max(arr: &[String], max: usize) -> Vec<String> {
arr.iter().take(max).cloned().collect()
}
pub fn arrlen<T>(arr: &[T]) -> usize {
arr.len()
}
pub fn arrlen_lt<T>(arr: &[T], n: usize) -> bool {
arr.len() < n
}
pub fn arrlen_le<T>(arr: &[T], n: usize) -> bool {
arr.len() <= n
}
pub fn arrlen_eq<T>(arr: &[T], n: usize) -> bool {
arr.len() == n
}
pub fn arrlen_gt<T>(arr: &[T], n: usize) -> bool {
arr.len() > n
}
pub fn sepjoin(arr: &[String], sep: Option<&str>) -> String {
arr.join(sep.unwrap_or(" "))
}
pub fn sepsplit(s: &str, sep: &str, allow_empty: bool) -> Vec<String> {
if allow_empty {
s.split(sep).map(|s| s.to_string()).collect()
} else {
s.split(sep)
.filter(|s| !s.is_empty())
.map(|s| s.to_string())
.collect()
}
}
pub fn zshcalloc_buf(size: usize) -> Vec<u8> {
vec![0u8; size]
}
pub fn zalloc_buf(size: usize) -> Vec<u8> {
Vec::with_capacity(size)
}
pub fn ztrdup(s: &str) -> String {
s.to_string()
}
pub fn ztrduppfx(s: &str, len: usize) -> String {
s.chars().take(len).collect()
}
pub fn bicat(s1: &str, s2: &str) -> String {
format!("{}{}", s1, s2)
}
pub fn tricat(s1: &str, s2: &str, s3: &str) -> String {
format!("{}{}{}", s1, s2, s3)
}
pub fn dyncat(s1: &str, s2: &str) -> String {
format!("{}{}", s1, s2)
}
pub fn strend(s: &str) -> Option<char> {
s.chars().last()
}
pub fn appstr(base: &mut String, append: &str) {
base.push_str(append);
}
#[derive(Default, Debug, Clone)]
pub struct MemStats {
pub heap_count: usize,
pub heap_total: usize,
pub heap_used: usize,
pub alloc_count: usize,
pub free_count: usize,
}
impl MemStats {
pub fn new() -> Self {
Self::default()
}
}
pub fn get_mem_stats() -> MemStats {
MemStats::new()
}
pub struct MemContext {
heap_depth: usize,
}
impl MemContext {
pub fn save() -> Self {
let depth = HEAP.with(|h| h.borrow().depth());
MemContext { heap_depth: depth }
}
pub fn restore(self) {
HEAP.with(|h| {
let mut heap = h.borrow_mut();
while heap.depth() > self.heap_depth {
heap.pop();
}
});
}
}
pub fn zcontext_save() -> MemContext {
MemContext::save()
}
pub fn zcontext_restore(ctx: MemContext) {
ctx.restore();
}
pub fn queue_signals() {}
pub fn unqueue_signals() {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_heap_push_pop() {
let mut arena = HeapArena::new();
assert_eq!(arena.depth(), 1);
arena.push();
assert_eq!(arena.depth(), 2);
arena.alloc_string("test".to_string());
arena.pop();
assert_eq!(arena.depth(), 1);
}
#[test]
fn test_heap_free_current() {
let mut arena = HeapArena::new();
arena.alloc_string("test1".to_string());
arena.alloc_bytes(vec![1, 2, 3]);
arena.free_current();
assert_eq!(arena.depth(), 1);
}
#[test]
fn test_nested_generations() {
let mut arena = HeapArena::new();
arena.alloc_string("level1".to_string());
arena.push();
arena.alloc_string("level2".to_string());
arena.push();
arena.alloc_string("level3".to_string());
assert_eq!(arena.depth(), 3);
arena.pop();
assert_eq!(arena.depth(), 2);
arena.pop();
assert_eq!(arena.depth(), 1);
}
#[test]
fn test_dupstring() {
let s = dupstring("hello");
assert_eq!(s, "hello");
}
#[test]
fn test_dupstring_wlen() {
let s = dupstring_wlen("hello world", 5);
assert_eq!(s, "hello");
}
#[test]
fn test_global_heap() {
pushheap();
pushheap();
popheap();
popheap();
}
}