@@ -462,8 +462,8 @@ unsafe impl<A: Array + Sync> Sync for SmallVecData<A> {}
462
462
/// ```
463
463
pub struct SmallVec < A : Array > {
464
464
// 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.
467
467
capacity : usize ,
468
468
data : SmallVecData < A > ,
469
469
}
@@ -506,7 +506,7 @@ impl<A: Array> SmallVec<A> {
506
506
507
507
/// Construct a new `SmallVec` from a `Vec<A::Item>`.
508
508
///
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 ().
510
510
///
511
511
/// ```rust
512
512
/// use smallvec::SmallVec;
@@ -518,7 +518,7 @@ impl<A: Array> SmallVec<A> {
518
518
/// ```
519
519
#[ inline]
520
520
pub fn from_vec ( mut vec : Vec < A :: Item > ) -> SmallVec < A > {
521
- if vec. capacity ( ) <= A :: size ( ) {
521
+ if vec. capacity ( ) <= Self :: inline_capacity ( ) {
522
522
unsafe {
523
523
let mut data = SmallVecData :: < A > :: from_inline ( MaybeUninit :: uninit ( ) ) ;
524
524
let len = vec. len ( ) ;
@@ -611,10 +611,30 @@ impl<A: Array> SmallVec<A> {
611
611
* len_ptr = new_len;
612
612
}
613
613
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
+
614
634
/// The maximum number of elements this vector can hold inline
615
635
#[ inline]
616
636
pub fn inline_size ( & self ) -> usize {
617
- A :: size ( )
637
+ Self :: inline_capacity ( )
618
638
}
619
639
620
640
/// The number of elements stored in the vector
@@ -644,7 +664,7 @@ impl<A: Array> SmallVec<A> {
644
664
let ( ptr, len) = self . data . heap ( ) ;
645
665
( ptr, len, self . capacity )
646
666
} else {
647
- ( self . data . inline ( ) , self . capacity , A :: size ( ) )
667
+ ( self . data . inline ( ) , self . capacity , Self :: inline_capacity ( ) )
648
668
}
649
669
}
650
670
}
@@ -657,15 +677,15 @@ impl<A: Array> SmallVec<A> {
657
677
let & mut ( ptr, ref mut len_ptr) = self . data . heap_mut ( ) ;
658
678
( ptr, len_ptr, self . capacity )
659
679
} else {
660
- ( self . data . inline_mut ( ) , & mut self . capacity , A :: size ( ) )
680
+ ( self . data . inline_mut ( ) , & mut self . capacity , Self :: inline_capacity ( ) )
661
681
}
662
682
}
663
683
}
664
684
665
685
/// Returns `true` if the data has spilled into a separate heap-allocated buffer.
666
686
#[ inline]
667
687
pub fn spilled ( & self ) -> bool {
668
- self . capacity > A :: size ( )
688
+ self . capacity > Self :: inline_capacity ( )
669
689
}
670
690
671
691
/// Creates a draining iterator that removes the specified range in the vector
@@ -770,6 +790,7 @@ impl<A: Array> SmallVec<A> {
770
790
deallocate ( ptr, cap) ;
771
791
} else if new_cap != cap {
772
792
let layout = layout_array :: < A :: Item > ( new_cap) ?;
793
+ debug_assert ! ( layout. size( ) > 0 ) ;
773
794
let new_alloc;
774
795
if unspilled {
775
796
new_alloc = NonNull :: new ( alloc:: alloc:: alloc ( layout) )
@@ -1029,7 +1050,7 @@ impl<A: Array> SmallVec<A> {
1029
1050
/// This method returns `Err(Self)` if the SmallVec is too short (and the `A` contains uninitialized elements),
1030
1051
/// or if the SmallVec is too long (and all the elements were spilled to the heap).
1031
1052
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
1033
1054
Err ( self )
1034
1055
} else {
1035
1056
unsafe {
@@ -1219,7 +1240,7 @@ impl<A: Array> SmallVec<A> {
1219
1240
/// }
1220
1241
#[ inline]
1221
1242
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 ( ) ) ;
1223
1244
SmallVec {
1224
1245
capacity,
1225
1246
data : SmallVecData :: from_heap ( ptr, length) ,
@@ -1236,7 +1257,7 @@ where
1236
1257
/// For slices of `Copy` types, this is more efficient than `SmallVec::from(slice)`.
1237
1258
pub fn from_slice ( slice : & [ A :: Item ] ) -> Self {
1238
1259
let len = slice. len ( ) ;
1239
- if len <= A :: size ( ) {
1260
+ if len <= Self :: inline_capacity ( ) {
1240
1261
SmallVec {
1241
1262
capacity : len,
1242
1263
data : SmallVecData :: from_inline ( unsafe {
@@ -1317,7 +1338,7 @@ where
1317
1338
/// assert_eq!(v, SmallVec::from_buf(['d', 'd']));
1318
1339
/// ```
1319
1340
pub fn from_elem ( elem : A :: Item , n : usize ) -> Self {
1320
- if n > A :: size ( ) {
1341
+ if n > Self :: inline_capacity ( ) {
1321
1342
vec ! [ elem; n] . into ( )
1322
1343
} else {
1323
1344
let mut v = SmallVec :: < A > :: new ( ) ;
@@ -2731,4 +2752,9 @@ mod tests {
2731
2752
fn empty_macro ( ) {
2732
2753
let _v: SmallVec < [ u8 ; 1 ] > = smallvec ! [ ] ;
2733
2754
}
2755
+
2756
+ #[ test]
2757
+ fn zero_size_items ( ) {
2758
+ SmallVec :: < [ ( ) ; 0 ] > :: new ( ) . push ( ( ) ) ;
2759
+ }
2734
2760
}
0 commit comments