rust 什么是安全memset的等价物?

qjp7pelc  于 2023-05-07  发布在  其他
关注(0)|答案(2)|浏览(212)

在许多情况下,我需要清除缓冲区区域或将切片设置为特定值。当地人推荐的方法是什么?
这是无效的Rust,但我想做类似的事情:

let mut some_buffer = vec![0u8; 100];
buffer[10..20].set(0xFF)

我可以使用for循环,但我觉得我错过了一些东西,因为我是Rust的新手。
在C++中,我会这样做:

std::array<int,6> foobar;
foobar.fill(5);

在Python中,它类似于:

tmp = np.zeros(10)
tmp[3:6]=2
sqxo8psd

sqxo8psd1#

更新:现在有了slice::fill方法。
原文回答:
你这是本末倒置。你真的在乎它调用memset吗?我想不是,只是它很有效。Rust的一大吸引力在于编译器可以在构建时“丢弃”许多抽象。例如,当一些CPU指令将做同样的事情时,为什么要调用一个函数?

pub fn thing(buffer: &mut [u8]) {
    for i in &mut buffer[10..20] { *i = 42 }
}
playground::thing:
    pushq   %rax
    cmpq    $19, %rsi
    jbe .LBB0_1
    movabsq $3038287259199220266, %rax
    movq    %rax, 10(%rdi)
    movw    $10794, 18(%rdi)
    popq    %rax
    retq

.LBB0_1:
    movl    $20, %edi
    callq   core::slice::slice_index_len_fail@PLT
    ud2
pub fn thing(buffer: &mut [u8]) {
    for i in &mut buffer[10..200] { *i = 99 }
}
.LCPI0_0:
    .zero   16,99

playground::thing:
    pushq   %rax
    cmpq    $199, %rsi
    jbe .LBB0_1
    movaps  .LCPI0_0(%rip), %xmm0
    movups  %xmm0, 184(%rdi)
    movups  %xmm0, 170(%rdi)
    movups  %xmm0, 154(%rdi)
    movups  %xmm0, 138(%rdi)
    movups  %xmm0, 122(%rdi)
    movups  %xmm0, 106(%rdi)
    movups  %xmm0, 90(%rdi)
    movups  %xmm0, 74(%rdi)
    movups  %xmm0, 58(%rdi)
    movups  %xmm0, 42(%rdi)
    movups  %xmm0, 26(%rdi)
    movups  %xmm0, 10(%rdi)
    popq    %rax
    retq

.LBB0_1:
    movl    $200, %edi
    callq   core::slice::slice_index_len_fail@PLT
    ud2

正如kazemakase指出的,当set区域变得“足够大”时,优化器切换到使用memset,而不是内联指令:

pub fn thing(buffer: &mut [u8]) {
    for i in &mut buffer[11..499] { *i = 240 }
}
playground::thing:
    pushq   %rax
    cmpq    $498, %rsi
    jbe .LBB0_1
    addq    $11, %rdi
    movl    $240, %esi
    movl    $488, %edx
    callq   memset@PLT
    popq    %rax
    retq

.LBB0_1:
    movl    $499, %edi
    callq   core::slice::slice_index_len_fail@PLT
    ud2

如果你愿意,你可以将这个函数 Package 在一个扩展trait中:

trait FillExt<T> {
    fn fill(&mut self, v: T);
}

impl FillExt<u8> for [u8] {
    fn fill(&mut self, v: u8) {
        for i in self {
            *i = v
        }
    }
}

pub fn thing(buffer: &mut [u8], val: u8) {
    buffer[10..20].fill(val)
}

参见:

gkl3eglg

gkl3eglg2#

从2021年2月11日发布的Rust 1.50.0开始,slice::fill现在是稳定的,这意味着如果您更改函数名称,您的示例现在可以工作:

let mut buffer = vec![0u8; 20];
buffer[5..10].fill(0xFF);
println!("{:?}", buffer);

将打印[0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

相关问题