#arena-allocation #allocation #memory #arena

nightly no-std zone-alloc

基于区域的(也称为区域或竞技场)数据分配的容器

13个不稳定版本 (3个破坏性更改)

0.4.0 2023年12月24日
0.3.5 2023年11月24日
0.2.2 2023年11月14日
0.1.2 2023年9月18日

208内存管理 中排名 #208

Download history 4/week @ 2024-03-12 1/week @ 2024-03-26 49/week @ 2024-04-02 1/week @ 2024-04-23 205/week @ 2024-04-30

152 每月下载
用于 2 crate

MIT 许可证

110KB
2.5K SLoC

zone-alloc

Latest Version

此crate提供基于区域(也称为基于区域或基于竞技场)的数据分配的数据类型。区域分配是一种内存管理类型,其中分配的对象被分配到特定的区域。区域中的数据在区域的生命周期内保持有效和可用,并在使用后一起释放区域中的所有数据。

此crate还提供“注册表”,这是一种提供竞技场分配元素和内部可变性的容器类型,具有简单的运行时借用检查。

[dependencies]
zone-alloc = "0.3"

用法

此crate定义了三个容器

  • Arena<T> - 可以用于分配特定类型值的竞技场分配容器。
  • Registry<T> - Arena<T> 的扩展,提供分配数据的整数句柄。
  • StrongRegistry<H, T> - Registry<T> 的扩展,提供分配数据的强类型句柄。
  • KeyedArena<K, T> - Arena<T> 的扩展,维护键到值的映射。

其他Crates

  • zone-alloc-strong-handle-derive - 当与 StrongRegistry 一起工作时,在简单的 Handle 类型包装器上生成 StrongHandle 接口的过程宏。

功能

虽然crate默认使用Rust标准库构建,但可以移除此功能以用于无std环境。

  • default - std
  • std - 依赖于Rust标准库。
  • may-dangle - 在 #[may_dangle] 属性上使用 Drop 实现的 ElementRefElementRefMut

示例

使用 Arena<T> 的链表节点

use zone_alloc::Arena;

#[derive(Debug, PartialEq, Eq)]
struct Node<'a, T> {
    parent: Option<&'a Node<'a, T>>,
    value: T,
}

impl<'a, T> Node<'a, T> {
    pub fn new(parent: Option<&'a Node<'a, T>>, value: T) -> Self {
        Self { parent, value }
    }
}

fn main() {
    let arena = Arena::new();
    let node = arena.alloc(Node::new(None, 1));
    let node = arena.alloc(Node::new(Some(node), 2));
    let node = arena.alloc(Node::new(Some(node), 3));

    assert_eq!(node.value, 3);
    assert_eq!(node.parent.unwrap().value, 2);
    assert_eq!(node.parent.unwrap().parent.unwrap().value, 1);
    assert_eq!(node.parent.unwrap().parent.unwrap().parent, None);
}

使用 Registry<T> 的循环引用

use zone_alloc::{
    Handle,
    Registry,
};

#[derive(Debug, PartialEq, Eq)]
struct Node<T> {
    parent: Option<Handle>,
    value: T,
}

impl<T> Node<T> {
    pub fn new(parent: Option<Handle>, value: T) -> Self {
        Self { parent, value }
    }
}

fn main() {
    let registry = Registry::new();
    let root_handle = registry.register(Node::new(None, "first"));
    let handle = registry.register(Node::new(Some(root_handle), "second"));
    let handle = registry.register(Node::new(Some(handle), "third"));
    registry.get_mut_unchecked(root_handle).parent = Some(handle);

    let node = registry.get(handle).unwrap();
    assert_eq!(node.value, "third");
    let node = registry.get(node.parent.unwrap()).unwrap();
    assert_eq!(node.value, "second");
    let node = registry.get(node.parent.unwrap()).unwrap();
    assert_eq!(node.value, "first");
    let node = registry.get(node.parent.unwrap()).unwrap();
    assert_eq!(node.value, "third");
}

使用 KeyedRegistry<T> 的循环引用

#[cfg(not(feature = "std"))]
extern crate alloc;

#[cfg(not(feature = "std"))]
use alloc::borrow::ToOwned;

use zone_alloc::KeyedRegistry;

#[derive(Debug, PartialEq, Eq)]
struct Node<K, V> {
    parent: Option<K>,
    value: V,
}

impl<K, V> Node<K, V> {
    pub fn new(parent: Option<K>, value: V) -> Self {
        Self { parent, value }
    }
}

fn main() {
    let registry = KeyedRegistry::new();
    registry.register("node-1".to_owned(), Node::new(None, "first"));
    registry.register(
        "node-2".to_owned(),
        Node::new(Some("node-1".to_owned()), "second"),
    );
    registry.register(
        "node-3".to_owned(),
        Node::new(Some("node-2".to_owned()), "third"),
    );
    registry.get_mut_unchecked("node-1").parent = Some("node-3".to_owned());

    let node = registry.get("node-3").unwrap();
    assert_eq!(node.value, "third");
    let node = registry.get(node.parent.as_ref().unwrap()).unwrap();
    assert_eq!(node.value, "second");
    let node = registry.get(node.parent.as_ref().unwrap()).unwrap();
    assert_eq!(node.value, "first");
    let node = registry.get(node.parent.as_ref().unwrap()).unwrap();
    assert_eq!(node.value, "third");
}

运行时借用检查

use zone_alloc::{
    BorrowError,
    Registry,
};

fn main() {
    let registry = Registry::new();
    registry.register_extend(100..200);

    // Multiple immutable borrows on the same element.
    let borrow_1 = registry.get(16);
    let borrow_2 = registry.get(16);
    let borrow_3 = registry.get(16);
    assert!(borrow_1.as_ref().is_ok_and(|i| i.eq(&116)));
    assert!(borrow_2.as_ref().is_ok_and(|i| i.eq(&116)));
    assert!(borrow_3.as_ref().is_ok_and(|i| i.eq(&116)));

    // Mutable borrow fails.
    assert_eq!(
        registry.get_mut(16).err(),
        Some(BorrowError::AlreadyBorrowed)
    );

    // Another element can be borrowed independently.
    let borrow_4 = registry.get(32);
    assert!(borrow_4.as_ref().is_ok_and(|i| i.eq(&132)));
    assert!(borrow_1.as_ref().is_ok_and(|i| i.eq(&116)));

    // Only one mutable borrow allowed.
    let mut borrow_5 = registry.get_mut(64).unwrap();
    assert!(borrow_5.eq(&164));
    *borrow_5 *= 2;
    assert!(borrow_5.eq(&328));
    assert_eq!(
        registry.get_mut(64).err(),
        Some(BorrowError::AlreadyBorrowed)
    );
    assert_eq!(registry.get(64).err(), Some(BorrowError::AlreadyBorrowed));

    // Refetch to show updated value, and show that previous borrows are still valid.
    drop(borrow_5);
    let borrow_5 = registry.get(64);
    assert!(borrow_5.as_ref().is_ok_and(|i| i.eq(&328)));
    assert!(borrow_4.as_ref().is_ok_and(|i| i.eq(&132)));
    assert!(borrow_1.as_ref().is_ok_and(|i| i.eq(&116)));
}

依赖

~2MB
~25K SLoC