Skip to content

Commit 6ed5b7b

Browse files
authored
Merge pull request #130 from bluss/fix-extend-zst
Fix .extend() for arrays of zero-sized type elements
2 parents e68c0c7 + 2a33979 commit 6ed5b7b

File tree

2 files changed

+42
-4
lines changed

2 files changed

+42
-4
lines changed

src/lib.rs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -926,8 +926,8 @@ impl<A: Array> Extend<A::Item> for ArrayVec<A> {
926926
let take = self.capacity() - self.len();
927927
unsafe {
928928
let len = self.len();
929-
let mut ptr = self.as_mut_ptr().offset(len as isize);
930-
let end_ptr = ptr.offset(take as isize);
929+
let mut ptr = raw_ptr_add(self.as_mut_ptr(), len);
930+
let end_ptr = raw_ptr_add(ptr, take);
931931
// Keep the length in a separate variable, write it back on scope
932932
// exit. To help the compiler with alias analysis and stuff.
933933
// 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> {
943943
loop {
944944
if ptr == end_ptr { break; }
945945
if let Some(elt) = iter.next() {
946-
ptr::write(ptr, elt);
947-
ptr = ptr.offset(1);
946+
raw_ptr_write(ptr, elt);
947+
ptr = raw_ptr_add(ptr, 1);
948948
guard.data += 1;
949949
} else {
950950
break;
@@ -954,6 +954,24 @@ impl<A: Array> Extend<A::Item> for ArrayVec<A> {
954954
}
955955
}
956956

957+
/// Rawptr add but uses arithmetic distance for ZST
958+
unsafe fn raw_ptr_add<T>(ptr: *mut T, offset: usize) -> *mut T {
959+
if mem::size_of::<T>() == 0 {
960+
// Special case for ZST
961+
(ptr as usize).wrapping_add(offset) as _
962+
} else {
963+
ptr.offset(offset as isize)
964+
}
965+
}
966+
967+
unsafe fn raw_ptr_write<T>(ptr: *mut T, value: T) {
968+
if mem::size_of::<T>() == 0 {
969+
/* nothing */
970+
} else {
971+
ptr::write(ptr, value)
972+
}
973+
}
974+
957975
/// Create an `ArrayVec` from an iterator.
958976
///
959977
/// Does not extract more items than there is space for. No error

tests/tests.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,3 +640,23 @@ fn test_newish_stable_uses_maybe_uninit() {
640640
assert!(cfg!(has_stable_maybe_uninit));
641641
}
642642
}
643+
644+
#[test]
645+
fn test_extend_zst() {
646+
let mut range = 0..10;
647+
#[derive(Copy, Clone, PartialEq, Debug)]
648+
struct Z; // Zero sized type
649+
650+
let mut array: ArrayVec<[_; 5]> = range.by_ref().map(|_| Z).collect();
651+
assert_eq!(&array[..], &[Z; 5]);
652+
assert_eq!(range.next(), Some(5));
653+
654+
array.extend(range.by_ref().map(|_| Z));
655+
assert_eq!(range.next(), Some(6));
656+
657+
let mut array: ArrayVec<[_; 10]> = (0..3).map(|_| Z).collect();
658+
assert_eq!(&array[..], &[Z; 3]);
659+
array.extend((3..5).map(|_| Z));
660+
assert_eq!(&array[..], &[Z; 5]);
661+
assert_eq!(array.len(), 5);
662+
}

0 commit comments

Comments
 (0)