@@ -859,6 +859,57 @@ 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
+ 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
+ }
862
913
}
863
914
864
915
/// This drops all "unreachable" elements in `self_` given the data pointer and data length.
@@ -1016,3 +1067,70 @@ where D: Dimension
1016
1067
}
1017
1068
}
1018
1069
}
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