@@ -859,6 +859,61 @@ where D: Dimension
859
859
860
860
Ok ( ( ) )
861
861
}
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
+ }
862
917
}
863
918
864
919
/// This drops all "unreachable" elements in `self_` given the data pointer and data length.
@@ -1016,3 +1071,70 @@ where D: Dimension
1016
1071
}
1017
1072
}
1018
1073
}
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