@@ -462,8 +462,8 @@ unsafe impl<A: Array + Sync> Sync for SmallVecData<A> {}
462462/// ```
463463pub struct SmallVec < A : Array > {
464464 // The capacity field is used to determine which of the storage variants is active:
465- // If capacity <= A::size () then the inline variant is used and capacity holds the current length of the vector (number of elements actually in use).
466- // If capacity > A::size () then the heap variant is used and capacity holds the size of the memory allocation.
465+ // If capacity <= Self::inline_capacity () then the inline variant is used and capacity holds the current length of the vector (number of elements actually in use).
466+ // If capacity > Self::inline_capacity () then the heap variant is used and capacity holds the size of the memory allocation.
467467 capacity : usize ,
468468 data : SmallVecData < A > ,
469469}
@@ -506,7 +506,7 @@ impl<A: Array> SmallVec<A> {
506506
507507 /// Construct a new `SmallVec` from a `Vec<A::Item>`.
508508 ///
509- /// Elements will be copied to the inline buffer if vec.capacity() <= A::size ().
509+ /// Elements will be copied to the inline buffer if vec.capacity() <= Self::inline_capacity ().
510510 ///
511511 /// ```rust
512512 /// use smallvec::SmallVec;
@@ -518,7 +518,7 @@ impl<A: Array> SmallVec<A> {
518518 /// ```
519519 #[ inline]
520520 pub fn from_vec ( mut vec : Vec < A :: Item > ) -> SmallVec < A > {
521- if vec. capacity ( ) <= A :: size ( ) {
521+ if vec. capacity ( ) <= Self :: inline_capacity ( ) {
522522 unsafe {
523523 let mut data = SmallVecData :: < A > :: from_inline ( MaybeUninit :: uninit ( ) ) ;
524524 let len = vec. len ( ) ;
@@ -611,10 +611,30 @@ impl<A: Array> SmallVec<A> {
611611 * len_ptr = new_len;
612612 }
613613
614+ /// The maximum number of elements this vector can hold inline
615+ #[ inline]
616+ fn inline_capacity ( ) -> usize {
617+ if mem:: size_of :: < A :: Item > ( ) > 0 {
618+ A :: size ( )
619+ } else {
620+ // For zero-size items code like `ptr.add(offset)` always returns the same pointer.
621+ // Therefore all items are at the same address,
622+ // and any array size has capacity for infinitely many items.
623+ // The capacity is limited by the bit width of the length field.
624+ //
625+ // `Vec` also does this:
626+ // https://github.com/rust-lang/rust/blob/1.44.0/src/liballoc/raw_vec.rs#L186
627+ //
628+ // In our case, this also ensures that a smallvec of zero-size items never spills,
629+ // and we never try to allocate zero bytes which `std::alloc::alloc` disallows.
630+ core:: usize:: MAX
631+ }
632+ }
633+
614634 /// The maximum number of elements this vector can hold inline
615635 #[ inline]
616636 pub fn inline_size ( & self ) -> usize {
617- A :: size ( )
637+ Self :: inline_capacity ( )
618638 }
619639
620640 /// The number of elements stored in the vector
@@ -644,7 +664,7 @@ impl<A: Array> SmallVec<A> {
644664 let ( ptr, len) = self . data . heap ( ) ;
645665 ( ptr, len, self . capacity )
646666 } else {
647- ( self . data . inline ( ) , self . capacity , A :: size ( ) )
667+ ( self . data . inline ( ) , self . capacity , Self :: inline_capacity ( ) )
648668 }
649669 }
650670 }
@@ -657,15 +677,15 @@ impl<A: Array> SmallVec<A> {
657677 let & mut ( ptr, ref mut len_ptr) = self . data . heap_mut ( ) ;
658678 ( ptr, len_ptr, self . capacity )
659679 } else {
660- ( self . data . inline_mut ( ) , & mut self . capacity , A :: size ( ) )
680+ ( self . data . inline_mut ( ) , & mut self . capacity , Self :: inline_capacity ( ) )
661681 }
662682 }
663683 }
664684
665685 /// Returns `true` if the data has spilled into a separate heap-allocated buffer.
666686 #[ inline]
667687 pub fn spilled ( & self ) -> bool {
668- self . capacity > A :: size ( )
688+ self . capacity > Self :: inline_capacity ( )
669689 }
670690
671691 /// Creates a draining iterator that removes the specified range in the vector
@@ -770,6 +790,7 @@ impl<A: Array> SmallVec<A> {
770790 deallocate ( ptr, cap) ;
771791 } else if new_cap != cap {
772792 let layout = layout_array :: < A :: Item > ( new_cap) ?;
793+ debug_assert ! ( layout. size( ) > 0 ) ;
773794 let new_alloc;
774795 if unspilled {
775796 new_alloc = NonNull :: new ( alloc:: alloc:: alloc ( layout) )
@@ -1029,7 +1050,7 @@ impl<A: Array> SmallVec<A> {
10291050 /// This method returns `Err(Self)` if the SmallVec is too short (and the `A` contains uninitialized elements),
10301051 /// or if the SmallVec is too long (and all the elements were spilled to the heap).
10311052 pub fn into_inner ( self ) -> Result < A , Self > {
1032- if self . spilled ( ) || self . len ( ) != A :: size ( ) {
1053+ if self . spilled ( ) || self . len ( ) != A :: size ( ) { // Note: A::size, not Self::inline_capacity
10331054 Err ( self )
10341055 } else {
10351056 unsafe {
@@ -1219,7 +1240,7 @@ impl<A: Array> SmallVec<A> {
12191240 /// }
12201241 #[ inline]
12211242 pub unsafe fn from_raw_parts ( ptr : * mut A :: Item , length : usize , capacity : usize ) -> SmallVec < A > {
1222- assert ! ( capacity > A :: size ( ) ) ;
1243+ assert ! ( capacity > Self :: inline_capacity ( ) ) ;
12231244 SmallVec {
12241245 capacity,
12251246 data : SmallVecData :: from_heap ( ptr, length) ,
@@ -1236,7 +1257,7 @@ where
12361257 /// For slices of `Copy` types, this is more efficient than `SmallVec::from(slice)`.
12371258 pub fn from_slice ( slice : & [ A :: Item ] ) -> Self {
12381259 let len = slice. len ( ) ;
1239- if len <= A :: size ( ) {
1260+ if len <= Self :: inline_capacity ( ) {
12401261 SmallVec {
12411262 capacity : len,
12421263 data : SmallVecData :: from_inline ( unsafe {
@@ -1317,7 +1338,7 @@ where
13171338 /// assert_eq!(v, SmallVec::from_buf(['d', 'd']));
13181339 /// ```
13191340 pub fn from_elem ( elem : A :: Item , n : usize ) -> Self {
1320- if n > A :: size ( ) {
1341+ if n > Self :: inline_capacity ( ) {
13211342 vec ! [ elem; n] . into ( )
13221343 } else {
13231344 let mut v = SmallVec :: < A > :: new ( ) ;
@@ -2731,4 +2752,9 @@ mod tests {
27312752 fn empty_macro ( ) {
27322753 let _v: SmallVec < [ u8 ; 1 ] > = smallvec ! [ ] ;
27332754 }
2755+
2756+ #[ test]
2757+ fn zero_size_items ( ) {
2758+ SmallVec :: < [ ( ) ; 0 ] > :: new ( ) . push ( ( ) ) ;
2759+ }
27342760}
0 commit comments