diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2024-04-08 14:31:11 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-04-08 14:31:11 +0200 |
| commit | 17c94b5f121ce05547ba5e47bfb1bfd6da317ee2 (patch) | |
| tree | d846b5b650afe287ef0b18ee59d28e2a36f8f293 | |
| parent | 98fbf86af9aa425a273d7e28f94a52cef61231da (diff) | |
| parent | 7a2678de7d3c0caa169542bd56a4fbf41b73a5b5 (diff) | |
| download | rust-17c94b5f121ce05547ba5e47bfb1bfd6da317ee2.tar.gz rust-17c94b5f121ce05547ba5e47bfb1bfd6da317ee2.zip | |
Rollup merge of #123089 - Philippe-Cholet:vecdeque_pop_assume_cap, r=Nilstrieb
Add invariant to VecDeque::pop_* that len < cap if pop successful Similar to #114370 for VecDeque instead of Vec. I initially come from https://github.com/rust-itertools/itertools/pull/899 where we noticed that `pop_front;push_back;` was slower than expected so `@scottmcm` suggested I file an issue which lead to https://internals.rust-lang.org/t/vecdeque-pop-front-push-back/20483 where **kornel** mentionned #114334 (fixed by #114370). This is my first time with codegen tests, I based the test on what was done for Vec.
| -rw-r--r-- | library/alloc/src/collections/vec_deque/mod.rs | 10 | ||||
| -rw-r--r-- | tests/codegen/vecdeque_pop_push.rs | 67 |
2 files changed, 75 insertions, 2 deletions
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index e2fc320f280..693ecb0b6b4 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1614,7 +1614,10 @@ impl<T, A: Allocator> VecDeque<T, A> { let old_head = self.head; self.head = self.to_physical_idx(1); self.len -= 1; - Some(unsafe { self.buffer_read(old_head) }) + unsafe { + core::hint::assert_unchecked(self.len < self.capacity()); + Some(self.buffer_read(old_head)) + } } } @@ -1638,7 +1641,10 @@ impl<T, A: Allocator> VecDeque<T, A> { None } else { self.len -= 1; - Some(unsafe { self.buffer_read(self.to_physical_idx(self.len)) }) + unsafe { + core::hint::assert_unchecked(self.len < self.capacity()); + Some(self.buffer_read(self.to_physical_idx(self.len))) + } } } diff --git a/tests/codegen/vecdeque_pop_push.rs b/tests/codegen/vecdeque_pop_push.rs new file mode 100644 index 00000000000..040d5a279dc --- /dev/null +++ b/tests/codegen/vecdeque_pop_push.rs @@ -0,0 +1,67 @@ +//@ compile-flags: -O + +#![crate_type = "lib"] + +use std::collections::VecDeque; + +#[no_mangle] +// CHECK-LABEL: @noop_back( +pub fn noop_back(v: &mut VecDeque<u8>) { + // CHECK-NOT: grow + // CHECK: tail call void @llvm.assume + // CHECK-NOT: grow + // CHECK: ret + if let Some(x) = v.pop_back() { + v.push_back(x); + } +} + +#[no_mangle] +// CHECK-LABEL: @noop_front( +pub fn noop_front(v: &mut VecDeque<u8>) { + // CHECK-NOT: grow + // CHECK: tail call void @llvm.assume + // CHECK-NOT: grow + // CHECK: ret + if let Some(x) = v.pop_front() { + v.push_front(x); + } +} + +#[no_mangle] +// CHECK-LABEL: @move_byte_front_to_back( +pub fn move_byte_front_to_back(v: &mut VecDeque<u8>) { + // CHECK-NOT: grow + // CHECK: tail call void @llvm.assume + // CHECK-NOT: grow + // CHECK: ret + if let Some(x) = v.pop_front() { + v.push_back(x); + } +} + +#[no_mangle] +// CHECK-LABEL: @move_byte_back_to_front( +pub fn move_byte_back_to_front(v: &mut VecDeque<u8>) { + // CHECK-NOT: grow + // CHECK: tail call void @llvm.assume + // CHECK-NOT: grow + // CHECK: ret + if let Some(x) = v.pop_back() { + v.push_front(x); + } +} + +#[no_mangle] +// CHECK-LABEL: @push_back_byte( +pub fn push_back_byte(v: &mut VecDeque<u8>) { + // CHECK: call {{.*}}grow + v.push_back(3); +} + +#[no_mangle] +// CHECK-LABEL: @push_front_byte( +pub fn push_front_byte(v: &mut VecDeque<u8>) { + // CHECK: call {{.*}}grow + v.push_front(3); +} |
