generic-array icon indicating copy to clipboard operation
generic-array copied to clipboard

Unchecked versions of GenericArray::from_[mut_]slice

Open eggyal opened this issue 3 years ago • 4 comments

Minor point, but would it be possible to expose an unsafe version of these functions that doesn't perform any length-check?

eggyal avatar May 30 '22 14:05 eggyal

Not exactly ergonomic, but you could do something like this in your own code where necessary:

use generic_array::{GenericArray, typenum::{U24, Unsigned}};

pub fn from_mut_slice(x: &mut [u8]) -> &mut GenericArray<u8, U24> {
    if x.len() != U24::USIZE {
        unsafe { std::hint::unreachable_unchecked() }
    }
    GenericArray::from_mut_slice(x)
}

novacrazy avatar May 30 '22 15:05 novacrazy

Additional notes based on deleted comment:

If the goal is optimization, then the unreachable_unchecked tells the compiler there is no other option than to succeed and will remove the panic machinery.

Click here to open example
pub fn version_a(x: &mut [u8]) -> &mut GenericArray<u8, U24> {
    if x.len() != U24::USIZE {
        unsafe { std::hint::unreachable_unchecked() }
    }
    GenericArray::from_mut_slice(x)
}

pub fn version_b(x: &mut [u8]) -> &mut GenericArray<u8, U24> {
    GenericArray::from_mut_slice(x)
}

compiles down to

playground::version_a:
	movq	%rdi, %rax
	retq

playground::version_b:
	subq	$56, %rsp
	movq	%rsi, (%rsp)
	cmpq	$24, %rsi
	jne	.LBB4_1
	movq	%rdi, %rax
	addq	$56, %rsp
	retq

.LBB4_1:
	movq	$0, 8(%rsp)
	movq	%rsp, %rdi
	leaq	8(%rsp), %rsi
	callq	core::panicking::assert_failed
	ud2

If the goal is to just be unsafe for the sake of being unsafe, that's just asking for trouble.

novacrazy avatar May 31 '22 05:05 novacrazy

Thank you, this does (unergonomically, as you say) compile down to what I need. However, it also relies on:

  1. GenericArray::from_mut_slice being inlined (its #[inline] attribute is only a hint, which the compiler can ignore); and

  2. an optimisation pass recognising that both tests (that in my fn and that in GenericArray::from_mut_slice) can thus be omitted.

I'm quite happy with this workaround if exposing _unchecked methods is unacceptable to this library. Feel free to close. Thanks again!

eggyal avatar May 31 '22 06:05 eggyal

As of 1.0, unsafe { GenericArray::try_from_mut_slice(slice).unwrap_unchecked() } should be sufficient. Still relies on the optimizations, but I've marked everything involved with that as #[inline(always)].

novacrazy avatar Sep 13 '23 02:09 novacrazy