我正在Rust中编写一个解释器,用于特定于域的语言,该语言应该允许高性能的实现 . 堆的相关属性是:

  • 程序很短(但很多都是执行的)

  • 我知道,在执行开始之前,需要的最大内存量

  • 所需的内存很小

  • 在程序终止之前不需要取消分配

  • 创建后,所有数据都是不可变的

  • 语言是静态类型检查的,因此没有访问未初始化内存的风险

  • 语言是单线程的,因此没有共享内存

我在堆中的元素有一个固定的结构:

pub enum Data {
    Adt(u16, Vec<u64>),
    Prim(Vec<u64>),
}

Vec<u64> 包含指向其他元素或原始数据的指针 . 我首先考虑用枚举直接表示它 .

这需要在运行时进行大量分配,并且需要 Vec 的不必要的间接 . 它还浪费了容量和大小字段的空间(因为数据是不可变的,并且大小是静态的) .

我对Rust来说相对较新,并且让自己远离不安全的代码,但我认为它可以帮到这里 . 我首先尝试表达我想要的功能:

#[derive(Copy, Clone)]
struct Data(u64);
struct DataStore(Vec<u64>);

impl DataStore {
    fn alloc(max_size: u64) -> Self {
        DataStore(Vec::with_capacity(max_size as usize))
    }

    fn new_adt(&mut self, tag: u16) -> Data {
        let start = self.0.len() as u64;
        let header = tag as u64;
        self.0.push(header);
        Data(start)
    }

    fn new_primitive(&mut self, data: &[u64]) -> Data {
        let start = self.0.len() as u64;
        for e in data {
            self.0.push(*e)
        }
        Data(start)
    }

    fn init_adt_field(&mut self, Data(ptr): Data) {
        self.0.push(ptr);
    }

    fn get_field(&self, Data(start): Data, index: u32) -> Data {
        Data(self.0[(start + 1 + (index as u64)) as usize])
    }

    fn get_tag(&self, Data(start): Data) -> u16 {
        self.0[start as usize] as u16
    }
}

这可以以某种方式比 Vec 更有效地实施吗?我看了 TypedArena ,但不知道在这种情况下是否以及如何使用它 . 它会比 Vec 更快吗? Vec 将永远不会增长,因为它被初始化为静态证明足够的容量 .

是否可以只分配一个内存blob,然后使用不安全的指针?我有什么选择?