#soa #vec #memory-layout #struct-of-arrays

nightly soa-vec

基于数组结构布局的简单Vec-like API

5个版本 (重大更改)

0.5.0 2019年8月14日
0.4.0 2019年7月14日
0.3.0 2019年6月22日
0.2.0 2019年6月21日
0.1.0 2019年6月16日

#2227 in 数据结构

每月21次 下载

MIT 协议

28KB
531 代码行

Soa2、Soa3、..SoaN 是具有类似元组Vec API的泛型集合,但每个字段存储为独立的切片。这种布局的优势在于在迭代数据时,只需从RAM中加载子集。

这种方法在游戏引擎中很常见,特别是在实体组件系统中,但适用于任何缓存一致性和内存带宽对性能很重要的地方。

示例

# use soa_vec::Soa3;
/// Some 'entity' data.
# #[derive(Copy, Clone)]
struct Position { x: f64, y: f64 }
# #[derive(Copy, Clone)]
struct Velocity { dx: f64, dy: f64 }
struct ColdData { /* Potentially many fields omitted here */ }

# use std::ops::Add;
# impl Add<Velocity> for Position { type Output=Self; fn add(self, other: Velocity) -> Self { Self { x: self.x + other.dx, y: self.y + other.dy } } }
// Create a vec of entities
let mut entities = Soa3::new();
entities.push((Position {x: 1.0, y: 2.0}, Velocity { dx: 0.0, dy: 0.5 }, ColdData {}));
entities.push((Position {x: 0.0, y: 2.0}, Velocity { dx: 0.5, dy: 0.5 }, ColdData {}));

// Update entities. This loop only loads position and velocity data, while skipping over
// the ColdData which is not necessary for the physics simulation.
let (positions, velocities, _cold) = entities.iters_mut();
for (position, velocity) in positions.zip(velocities) {
	*position = *position + *velocity;
}

// Remove an entity
entities.swap_remove(0);

// Sort entities by position on y axis
// The fields are passed by reference, so velocity and cold data are not loaded
// until such time as the items are being swapped which runs in O(N)
# use std::cmp;
entities.sort_unstable_by(
	|(lh_pos, _, _), (rh_pos, _, _)| lh_pos.y.partial_cmp(&rh_pos.y).unwrap()
);

// See individual structs for more methods.

Nightly

此crate对分配和内存布局有严格的要求,因此需要以下nightly功能

  • allocator_api
  • alloc_layout_extra

链接

许可证

MIT

相关

如果你喜欢这个,你可能还会喜欢以下Zac Burns (That3Percent)编写的其他crate

  • second-stack Rust内存分配器,用于大型切片,这些切片不会逃离栈。
  • js-intern 存储每个不同的JavaScript原型的唯一副本
  • js-object 创建JavaScript对象的宏

依赖项

~17KB