@@ -859,6 +859,57 @@ 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+ let guard = AbortIfPanic ( & "shrink_to_fit: owned repr not in consistent state" ) ;
904+ unsafe {
905+ let front_slop = logical_ptr. offset_from ( data_ptr) as usize - offset_to_logical;
906+ let new_low_ptr = self
907+ . data
908+ . preserve_range_and_shrink ( front_slop..( front_slop + span) ) ;
909+ self . ptr = new_low_ptr. add ( offset_to_logical) ;
910+ }
911+ guard. defuse ( ) ;
912+ }
862913}
863914
864915/// This drops all "unreachable" elements in `self_` given the data pointer and data length.
@@ -1016,3 +1067,70 @@ where D: Dimension
10161067 }
10171068 }
10181069}
1070+
1071+ #[ cfg( test) ]
1072+ mod tests
1073+ {
1074+ use crate :: Array ;
1075+ use crate :: Array2 ;
1076+ use crate :: Slice ;
1077+ use core:: fmt:: Debug ;
1078+ use core:: mem:: size_of;
1079+
1080+ #[ test]
1081+ fn test_shrink_to_fit ( )
1082+ {
1083+ fn assert_shrink_before_after < T > ( mut a : Array2 < T > , s1 : Slice , s2 : Slice , new_capacity : usize )
1084+ where T : Debug + Clone + Eq
1085+ {
1086+ let initial_len = a. len ( ) ;
1087+ if size_of :: < T > ( ) > 0 {
1088+ assert_eq ! ( a. data. capacity( ) , initial_len) ;
1089+ }
1090+ a = a. slice_move ( s ! [ s1, s2] ) ;
1091+ let before_value = a. clone ( ) ;
1092+ let before_strides = a. strides ( ) . to_vec ( ) ;
1093+ #[ cfg( feature = "std" ) ]
1094+ println ! ( "{:?}, {}, {:?}" , a, a. len( ) , a. data) ;
1095+ a. shrink_to_fit ( ) ;
1096+ #[ cfg( feature = "std" ) ]
1097+ println ! ( "{:?}, {}, {:?}" , a, a. len( ) , a. data) ;
1098+
1099+ assert_eq ! ( before_value, a) ;
1100+ assert_eq ! ( before_strides, a. strides( ) ) ;
1101+
1102+ if size_of :: < T > ( ) > 0 {
1103+ assert ! ( a. data. capacity( ) < initial_len) ;
1104+ assert ! ( a. data. capacity( ) >= a. len( ) ) ;
1105+ }
1106+ assert_eq ! ( a. data. capacity( ) , new_capacity) ;
1107+ }
1108+
1109+ let a = Array :: from_iter ( 0 ..56 )
1110+ . into_shape_with_order ( ( 8 , 7 ) )
1111+ . unwrap ( ) ;
1112+ assert_shrink_before_after ( a, Slice :: new ( 1 , Some ( -1 ) , 1 ) , Slice :: new ( 0 , None , 2 ) , 42 ) ;
1113+
1114+ let a = Array :: from_iter ( 0 ..56 )
1115+ . into_shape_with_order ( ( 8 , 7 ) )
1116+ . unwrap ( ) ;
1117+ assert_shrink_before_after ( a, Slice :: new ( 1 , Some ( -1 ) , -1 ) , Slice :: new ( 0 , None , -1 ) , 42 ) ;
1118+
1119+ let a = Array :: from_iter ( 0 ..56 )
1120+ . into_shape_with_order ( ( 8 , 7 ) )
1121+ . unwrap ( ) ;
1122+ assert_shrink_before_after ( a, Slice :: new ( 1 , Some ( 3 ) , 1 ) , Slice :: new ( 1 , None , -2 ) , 12 ) ;
1123+
1124+ // empty but still has some allocation to allow offsetting along each stride
1125+ let a = Array :: from_iter ( 0 ..56 )
1126+ . into_shape_with_order ( ( 8 , 7 ) )
1127+ . unwrap ( ) ;
1128+ assert_shrink_before_after ( a, Slice :: new ( 1 , Some ( 1 ) , 1 ) , Slice :: new ( 1 , None , 1 ) , 6 ) ;
1129+
1130+ // Test ZST
1131+ let a = Array :: from_iter ( ( 0 ..56 ) . map ( |_| ( ) ) )
1132+ . into_shape_with_order ( ( 8 , 7 ) )
1133+ . unwrap ( ) ;
1134+ assert_shrink_before_after ( a, Slice :: new ( 1 , Some ( 3 ) , 1 ) , Slice :: new ( 1 , None , -2 ) , usize:: MAX ) ;
1135+ }
1136+ }
0 commit comments