@@ -859,6 +859,61 @@ where D: Dimension
859859
860860 Ok ( ( ) )
861861 }
862+
863+ /// Shrink Array allocation capacity to be as small as it can be.
864+ pub fn shrink_to_fit ( & mut self )
865+ {
866+ // Example:
867+ // (1) (2) (3) .- len
868+ // Vector: [ x x x x x V x V x V x V x V x V x V x V x V x x x x x x x ] .- capacity
869+ // Allocation: [ m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m ]
870+ //
871+ // x: valid data in OwnedRepr but outside current array slicing
872+ // V: valid data in OwnedRepr and visible in current array slicing
873+ // m: allocated memory
874+ // (1): Lowest address element
875+ // (2): Logical pointer (Element at index zero; normally (1) == (2) but can be
876+ // located anywhere (1) <= (2) <= (3))
877+ // (3): Highest address element
878+ //
879+ // Span: From (1) to (3).
880+ //
881+ // Algorithm: Compute 1, 2, 3.
882+ // Move data so that unused areas before (1) and after (3) are removed from the storage/vector.
883+ // Then shrink the vector's allocation to fit the valid elements.
884+ //
885+ // After:
886+ // (1) (2) (3).- len == capacity
887+ // Vector: [ V x V x V x V x V x V x V x V x V ]
888+ // Allocation: [ m m m m m m m m m m m m m m m m m ]
889+ //
890+
891+ if mem:: size_of :: < A > ( ) == 0 {
892+ return ;
893+ }
894+
895+ let data_ptr = self . data . as_ptr ( ) ;
896+ let logical_ptr = self . as_ptr ( ) ;
897+ let offset_to_logical = dimension:: offset_from_low_addr_ptr_to_logical_ptr ( & self . dim , & self . strides ) ;
898+ let offset_to_high = dimension:: offset_from_logical_ptr_to_high_addr_ptr ( & self . dim , & self . strides ) ;
899+
900+ let span = offset_to_logical + offset_to_high + 1 ;
901+ debug_assert ! ( span >= self . len( ) ) ;
902+
903+ // We are in a panic critical section because: Array/OwnedRepr's destructors rely on
904+ // dimension, strides, and self.ptr to deallocate correctly.
905+ // We could panic here because custom user code is running when removing elements
906+ // (destructors running).
907+ let guard = AbortIfPanic ( & "shrink_to_fit: owned repr not in consistent state" ) ;
908+ unsafe {
909+ let front_slop = logical_ptr. offset_from ( data_ptr) as usize - offset_to_logical;
910+ let new_low_ptr = self
911+ . data
912+ . preserve_range_and_shrink ( front_slop..( front_slop + span) ) ;
913+ self . ptr = new_low_ptr. add ( offset_to_logical) ;
914+ }
915+ guard. defuse ( ) ;
916+ }
862917}
863918
864919/// This drops all "unreachable" elements in `self_` given the data pointer and data length.
@@ -1016,3 +1071,70 @@ where D: Dimension
10161071 }
10171072 }
10181073}
1074+
1075+ #[ cfg( test) ]
1076+ mod tests
1077+ {
1078+ use crate :: Array ;
1079+ use crate :: Array2 ;
1080+ use crate :: Slice ;
1081+ use core:: fmt:: Debug ;
1082+ use core:: mem:: size_of;
1083+
1084+ #[ test]
1085+ fn test_shrink_to_fit ( )
1086+ {
1087+ fn assert_shrink_before_after < T > ( mut a : Array2 < T > , s1 : Slice , s2 : Slice , new_capacity : usize )
1088+ where T : Debug + Clone + Eq
1089+ {
1090+ let initial_len = a. len ( ) ;
1091+ if size_of :: < T > ( ) > 0 {
1092+ assert_eq ! ( a. data. capacity( ) , initial_len) ;
1093+ }
1094+ a = a. slice_move ( s ! [ s1, s2] ) ;
1095+ let before_value = a. clone ( ) ;
1096+ let before_strides = a. strides ( ) . to_vec ( ) ;
1097+ #[ cfg( feature = "std" ) ]
1098+ println ! ( "{:?}, {}, {:?}" , a, a. len( ) , a. data) ;
1099+ a. shrink_to_fit ( ) ;
1100+ #[ cfg( feature = "std" ) ]
1101+ println ! ( "{:?}, {}, {:?}" , a, a. len( ) , a. data) ;
1102+
1103+ assert_eq ! ( before_value, a) ;
1104+ assert_eq ! ( before_strides, a. strides( ) ) ;
1105+
1106+ if size_of :: < T > ( ) > 0 {
1107+ assert ! ( a. data. capacity( ) < initial_len) ;
1108+ assert ! ( a. data. capacity( ) >= a. len( ) ) ;
1109+ }
1110+ assert_eq ! ( a. data. capacity( ) , new_capacity) ;
1111+ }
1112+
1113+ let a = Array :: from_iter ( 0 ..56 )
1114+ . into_shape_with_order ( ( 8 , 7 ) )
1115+ . unwrap ( ) ;
1116+ assert_shrink_before_after ( a, Slice :: new ( 1 , Some ( -1 ) , 1 ) , Slice :: new ( 0 , None , 2 ) , 42 ) ;
1117+
1118+ let a = Array :: from_iter ( 0 ..56 )
1119+ . into_shape_with_order ( ( 8 , 7 ) )
1120+ . unwrap ( ) ;
1121+ assert_shrink_before_after ( a, Slice :: new ( 1 , Some ( -1 ) , -1 ) , Slice :: new ( 0 , None , -1 ) , 42 ) ;
1122+
1123+ let a = Array :: from_iter ( 0 ..56 )
1124+ . into_shape_with_order ( ( 8 , 7 ) )
1125+ . unwrap ( ) ;
1126+ assert_shrink_before_after ( a, Slice :: new ( 1 , Some ( 3 ) , 1 ) , Slice :: new ( 1 , None , -2 ) , 12 ) ;
1127+
1128+ // empty but still has some allocation to allow offsetting along each stride
1129+ let a = Array :: from_iter ( 0 ..56 )
1130+ . into_shape_with_order ( ( 8 , 7 ) )
1131+ . unwrap ( ) ;
1132+ assert_shrink_before_after ( a, Slice :: new ( 1 , Some ( 1 ) , 1 ) , Slice :: new ( 1 , None , 1 ) , 6 ) ;
1133+
1134+ // Test ZST
1135+ let a = Array :: from_iter ( ( 0 ..56 ) . map ( |_| ( ) ) )
1136+ . into_shape_with_order ( ( 8 , 7 ) )
1137+ . unwrap ( ) ;
1138+ assert_shrink_before_after ( a, Slice :: new ( 1 , Some ( 3 ) , 1 ) , Slice :: new ( 1 , None , -2 ) , usize:: MAX ) ;
1139+ }
1140+ }
0 commit comments