FIX: Fix .extend() for ArrayVec with zero-sized type elements
The raw pointer walk did not do the right thing for ZST, because when offsets are zero, the start and end pointer would be the same and the loop ends before incrementing the length correctly.
This commit is contained in:
+22
-4
@@ -926,8 +926,8 @@ impl<A: Array> Extend<A::Item> for ArrayVec<A> {
|
|||||||
let take = self.capacity() - self.len();
|
let take = self.capacity() - self.len();
|
||||||
unsafe {
|
unsafe {
|
||||||
let len = self.len();
|
let len = self.len();
|
||||||
let mut ptr = self.as_mut_ptr().offset(len as isize);
|
let mut ptr = raw_ptr_add(self.as_mut_ptr(), len);
|
||||||
let end_ptr = ptr.offset(take as isize);
|
let end_ptr = raw_ptr_add(ptr, take);
|
||||||
// Keep the length in a separate variable, write it back on scope
|
// Keep the length in a separate variable, write it back on scope
|
||||||
// exit. To help the compiler with alias analysis and stuff.
|
// exit. To help the compiler with alias analysis and stuff.
|
||||||
// We update the length to handle panic in the iteration of the
|
// We update the length to handle panic in the iteration of the
|
||||||
@@ -943,8 +943,8 @@ impl<A: Array> Extend<A::Item> for ArrayVec<A> {
|
|||||||
loop {
|
loop {
|
||||||
if ptr == end_ptr { break; }
|
if ptr == end_ptr { break; }
|
||||||
if let Some(elt) = iter.next() {
|
if let Some(elt) = iter.next() {
|
||||||
ptr::write(ptr, elt);
|
raw_ptr_write(ptr, elt);
|
||||||
ptr = ptr.offset(1);
|
ptr = raw_ptr_add(ptr, 1);
|
||||||
guard.data += 1;
|
guard.data += 1;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
@@ -954,6 +954,24 @@ impl<A: Array> Extend<A::Item> for ArrayVec<A> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Rawptr add but uses arithmetic distance for ZST
|
||||||
|
unsafe fn raw_ptr_add<T>(ptr: *mut T, offset: usize) -> *mut T {
|
||||||
|
if mem::size_of::<T>() == 0 {
|
||||||
|
// Special case for ZST
|
||||||
|
(ptr as usize).wrapping_add(offset) as _
|
||||||
|
} else {
|
||||||
|
ptr.offset(offset as isize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn raw_ptr_write<T>(ptr: *mut T, value: T) {
|
||||||
|
if mem::size_of::<T>() == 0 {
|
||||||
|
/* nothing */
|
||||||
|
} else {
|
||||||
|
ptr::write(ptr, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Create an `ArrayVec` from an iterator.
|
/// Create an `ArrayVec` from an iterator.
|
||||||
///
|
///
|
||||||
/// Does not extract more items than there is space for. No error
|
/// Does not extract more items than there is space for. No error
|
||||||
|
|||||||
Reference in New Issue
Block a user