Rust快速栈实现没有不必要的memset?



我需要Rust中的快速堆栈。每秒需要创建/销毁数百万个这样的内容,每个内容只需要一个固定的深度。我在尽可能加快速度。我想出了以下方法(基本上是教科书式的堆栈实现):

const L: usize = 1024;
pub struct Stack {
xs: [(u64, u64, u64, u64); L],
sz: usize
}
impl Stack {
pub fn new() -> Self {
Self { xs: [(0, 0 ,0, 0); L], sz: 0 }
}

pub fn push(&mut self, item: (u64, u64, u64, u64)) -> bool {
if (self.sz + 1) <= L {
self.xs[self.sz] = item;
self.sz += 1;
true
} else {
false
}
}

pub fn pop(&mut self) -> Option<(u64, u64, u64, u64)> {
(self.sz > 0).then(|| {
self.sz -= 1;
self.xs[self.sz]
})
}
}

问题是memset,不需要。所以我试着删掉它:

pub fn new2() -> Self {
let xs = std::array::from_fn(|_| unsafe { MaybeUninit::uninit().assume_init() });
Self { xs, sz: 0 }
}

这去掉了memset,但是现在我有一个警告:

|
18 |         let xs = std::array::from_fn(|_| unsafe { MaybeUninit::uninit().assume_init() });
|                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|                                                   |
|                                                   this code causes undefined behavior when executed
|                                                   help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
|
= note: integers must not be uninitialized
= note: `#[warn(invalid_value)]` on by default

如果未初始化的整数导致未定义的行为,是否有可能创建这种堆栈,其中堆栈的逻辑保证正确的行为,并避免不必要的内存操作?

你需要一直使用MaybeUninit。将数组更改为MaybeUninits数组:

use std::mem::MaybeUninit;
const L: usize = 1024;
pub struct Stack {
xs: [MaybeUninit<(u64, u64, u64, u64)>; L],
sz: usize
}
// From standard library
// https://doc.rust-lang.org/stable/src/core/mem/maybe_uninit.rs.html#350-353
#[must_use]
#[inline(always)]
pub const fn uninit_array<const N: usize, T>() -> [MaybeUninit<T>; N] {
// SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid.
unsafe { MaybeUninit::<[MaybeUninit<T>; N]>::uninit().assume_init() }
}
impl Stack {
pub fn new() -> Self {
Self { xs: uninit_array(), sz: 0 }
}

pub fn push(&mut self, item: (u64, u64, u64, u64)) -> bool {
if (self.sz + 1) <= L {
self.xs[self.sz].write(item);
self.sz += 1;
true
} else {
false
}
}

pub fn pop(&mut self) -> Option<(u64, u64, u64, u64)> {
(self.sz > 0).then(|| {
self.sz -= 1;
// Safety: The value has been initialized
unsafe {
self.xs[self.sz].assume_init()
}
})
}
}

最新更新