jacg
March 8, 2023, 9:31am
1
Given a pair of indices lo
and hi
I would like to take a slice between those limits, but if hi
is out of bounds, then automatically limit it to stay within bounds. This is easily done like this
&v[lo..hi.min(v.len())]
but I was wondering whether there is a more concise or higher-level way of writing this, whether by idiom or through the use of some utility.
jbe
March 8, 2023, 10:34am
2
The only other option I could think of is this:
v.get(lo..hi).unwrap_or(&v[lo..])
(Playground )
It's longer, but maybe a bit easier to read?
Note that both your original approach as well as the approach above panic if lo
is exceeding the boundary. Not sure if that's what you intended.
Interesting that unwrap_or()
variant gives better assembly and completely avoids panic somehow. Rust Playground
1 Like
jbe
March 8, 2023, 10:44am
4
If you want to automatically limit lo
as well, you could do this:
pub fn foo<T>(v: &[T], lo: usize, hi: usize) -> &[T] {
let m = v.len();
&v[lo.min(m)..hi.min(m)]
}
pub fn bar<T>(v: &[T], lo: usize, hi: usize) -> &[T] {
v.get(lo..hi).or(v.get(lo..)).unwrap_or(&[])
}
(Playground )
Not sure if that could be written nicer yet.
jacg
March 8, 2023, 11:11am
5
Does it?
I'm no assembly maven, so it's not at all clear to me when looking at this godbolt output.
Your playground link appears to suggest the opposite: both versions panic.
jbe
March 8, 2023, 4:58pm
6
I get this on playground:
playground::foo:
cmpq $4, %rdi
movl $4, %eax
cmovbq %rdi, %rax
testq %rax, %rax
je .LBB7_1
decq %rax
retq
.LBB7_1:
pushq %rax
leaq .L__unnamed_7(%rip), %rdx
movl $1, %edi
xorl %esi, %esi
callq *core::slice::index::slice_index_order_fail@GOTPCREL(%rip)
ud2
playground::bar:
leaq -1(%rdi), %rax
cmpq $5, %rdi
movl $3, %edx
cmovbq %rax, %rdx
leaq .L__unnamed_8+4(%rip), %rax
retq
And this following your godbolt link:
example::aaa:
cmp rcx, rsi
cmovb rsi, rcx
mov rcx, rsi
sub rcx, rdx
jb .LBB0_1
lea rax, [rdi + 4*rdx]
mov rdx, rcx
ret
.LBB0_1:
push rax
lea rax, [rip + .L__unnamed_1]
mov rdi, rdx
mov rdx, rax
call qword ptr [rip + core::slice::index::slice_index_order_fail@GOTPCREL]
ud2
example::bbb:
mov r9, rsi
sub r9, rdx
jb .LBB1_1
mov r8, rcx
sub r8, rdx
cmp rcx, rsi
cmova r8, r9
cmp rcx, rdx
lea rax, [rdi + 4*rdx]
cmovb r8, r9
mov rdx, r8
ret
.LBB1_1:
push rax
lea rax, [rip + .L__unnamed_2]
mov rdi, rdx
mov rdx, rax
call qword ptr [rip + core::slice::index::slice_start_index_len_fail@GOTPCREL]
ud2
jacg
March 8, 2023, 5:15pm
7
Hmm, I couldn't immediately find how to generate ASM on playground and thought I'd imagined that the possibility existed ...
OK, so the playground gives much cleaner code than godbolt (even on the highest OPT level).
Moral of the story: look at Rust-generated ASM on playground, not godbolt?
(But both approaches panic, or have I missed something there too?)
jbe
March 8, 2023, 5:25pm
8
Yes, bar
should panic (and does panic), but I don't see how the assembler output from Playground can panic. Maybe someone with more assembly experience could check on that.
1 Like
system
Closed
June 6, 2023, 5:25pm
9
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.