88use std:: fmt;
99use super :: {
1010 ArrayBase ,
11+ Axis ,
1112 Data ,
1213 Dimension ,
1314 NdProducer ,
1415 Ix
1516} ;
16- use crate :: dimension :: IntoDimension ;
17+ use crate :: aliases :: Ix1 ;
1718
1819const PRINT_ELEMENTS_LIMIT : Ix = 3 ;
1920
20- fn get_overflow_axes ( shape : & [ Ix ] , limit : usize ) -> Vec < usize > {
21- shape. iter ( )
22- . enumerate ( )
23- . rev ( )
24- . filter ( |( _, axis_size) | * * axis_size > 2 * limit)
25- . map ( |( axis, _) | axis)
26- . collect ( )
21+ fn format_1d_array < A , S , F > (
22+ view : & ArrayBase < S , Ix1 > ,
23+ f : & mut fmt:: Formatter ,
24+ mut format : F ,
25+ limit : Ix ) -> fmt:: Result
26+ where
27+ F : FnMut ( & A , & mut fmt:: Formatter ) -> fmt:: Result ,
28+ S : Data < Elem =A > ,
29+ {
30+ let to_be_printed = to_be_printed ( view. len ( ) , limit) ;
31+
32+ let n_to_be_printed = to_be_printed. len ( ) ;
33+
34+ write ! ( f, "[" ) ?;
35+ for ( j, index) in to_be_printed. into_iter ( ) . enumerate ( ) {
36+ match index {
37+ PrintableCell :: ElementIndex ( i) => {
38+ format ( & view[ i] , f) ?;
39+ if j != n_to_be_printed - 1 {
40+ write ! ( f, ", " ) ?;
41+ }
42+ } ,
43+ PrintableCell :: Ellipses => write ! ( f, "..., " ) ?,
44+ }
45+ }
46+ write ! ( f, "]" ) ?;
47+ Ok ( ( ) )
2748}
2849
29- fn get_highest_axis_to_skip ( overflow_axes : & Vec < usize > ,
30- shape : & [ Ix ] ,
31- index : & [ Ix ] ,
32- limit : & usize ) -> Option < usize > {
33- overflow_axes. iter ( )
34- . filter ( |axis| {
35- if * * axis == shape. len ( ) - 1 {
36- return false
37- } ;
38- let sa_idx_max = shape. iter ( ) . skip ( * * axis) . next ( ) . unwrap ( ) ;
39- let sa_idx_val = index. iter ( ) . skip ( * * axis) . next ( ) . unwrap ( ) ;
40- sa_idx_val >= limit && sa_idx_val < & ( sa_idx_max - limit)
41- } )
42- . min ( )
43- . map ( |v| * v)
50+ enum PrintableCell {
51+ ElementIndex ( usize ) ,
52+ Ellipses ,
4453}
4554
46- fn get_highest_changed_axis ( index : & [ Ix ] , prev_index : & [ Ix ] ) -> Option < usize > {
47- index. iter ( )
48- . take ( index. len ( ) - 1 )
49- . zip ( prev_index. iter ( ) )
50- . enumerate ( )
51- . filter ( |( _, ( a, b) ) | a != b)
52- . map ( |( i, _) | i)
53- . next ( )
55+ // Returns what indexes should be printed for a certain axis.
56+ // If the axis is longer than 2 * limit, a `Ellipses` is inserted
57+ // where indexes are being omitted.
58+ fn to_be_printed ( length : usize , limit : usize ) -> Vec < PrintableCell > {
59+ if length <= 2 * limit {
60+ ( 0 ..length) . map ( |x| PrintableCell :: ElementIndex ( x) ) . collect ( )
61+ } else {
62+ let mut v: Vec < PrintableCell > = ( 0 ..limit) . map ( |x| PrintableCell :: ElementIndex ( x) ) . collect ( ) ;
63+ v. push ( PrintableCell :: Ellipses ) ;
64+ v. extend ( ( length-limit..length) . map ( |x| PrintableCell :: ElementIndex ( x) ) ) ;
65+ v
66+ }
5467}
5568
56- fn format_array < A , S , D , F > ( view : & ArrayBase < S , D > ,
57- f : & mut fmt:: Formatter ,
58- mut format : F ,
59- limit : Ix ) -> fmt:: Result
60- where F : FnMut ( & A , & mut fmt:: Formatter ) -> fmt:: Result ,
61- D : Dimension ,
62- S : Data < Elem =A > ,
69+ fn format_array < A , S , D , F > (
70+ view : & ArrayBase < S , D > ,
71+ f : & mut fmt:: Formatter ,
72+ mut format : F ,
73+ limit : Ix ) -> fmt:: Result
74+ where
75+ F : FnMut ( & A , & mut fmt:: Formatter ) -> fmt:: Result + Clone ,
76+ D : Dimension ,
77+ S : Data < Elem =A > ,
6378{
64- if view. shape ( ) . is_empty ( ) {
65- // Handle 0-dimensional array case first
66- return format ( view. iter ( ) . next ( ) . unwrap ( ) , f)
79+ // If any of the axes has 0 length, we return the same empty array representation
80+ // e.g. [[]] for 2-d arrays
81+ if view. shape ( ) . iter ( ) . any ( |& x| x == 0 ) {
82+ write ! ( f, "{}{}" , "[" . repeat( view. ndim( ) ) , "]" . repeat( view. ndim( ) ) ) ?;
83+ return Ok ( ( ) )
6784 }
68-
69- let overflow_axes: Vec < Ix > = get_overflow_axes ( view. shape ( ) , limit) ;
70-
71- let ndim = view. ndim ( ) ;
72- let nth_idx_max = view. shape ( ) [ ndim-1 ] ;
73-
74- // None will be an empty iter.
75- let mut last_index = match view. dim ( ) . into_dimension ( ) . first_index ( ) {
76- None => view. dim ( ) . into_dimension ( ) . clone ( ) ,
77- Some ( ix) => ix,
78- } ;
79- write ! ( f, "{}" , "[" . repeat( ndim) ) ?;
80- // Shows if ellipses for horizontal split were printed.
81- let mut printed_ellipses_h = vec ! [ false ; ndim] ;
82- // Shows if the row was printed for the first time after horizontal split.
83- let mut no_rows_after_skip_yet = false ;
84-
85- // Simply use the indexed iterator, and take the index wraparounds
86- // as cues for when to add []'s and how many to add.
87- for ( index, elt) in view. indexed_iter ( ) {
88- let index = index. into_dimension ( ) ;
89-
90- let skip_row_for_axis = get_highest_axis_to_skip (
91- & overflow_axes,
92- view. shape ( ) ,
93- index. slice ( ) ,
94- & limit
95- ) ;
96- if skip_row_for_axis. is_some ( ) {
97- no_rows_after_skip_yet = true ;
98- }
99-
100- let max_changed_idx = get_highest_changed_axis ( index. slice ( ) , last_index. slice ( ) ) ;
101- if let Some ( i) = max_changed_idx {
102- printed_ellipses_h. iter_mut ( ) . skip ( i + 1 ) . for_each ( |e| { * e = false ; } ) ;
103-
104- if skip_row_for_axis. is_none ( ) {
105- // New row.
106- // # of ['s needed
107- let n = ndim - i - 1 ;
108- if !no_rows_after_skip_yet {
109- write ! ( f, "{}" , "]" . repeat( n) ) ?;
110- writeln ! ( f, "," ) ?;
85+ match view. shape ( ) {
86+ // If it's 0 dimensional, we just print out the scalar
87+ [ ] => format ( view. iter ( ) . next ( ) . unwrap ( ) , f) ?,
88+ // We delegate 1-dimensional arrays to a specialized function
89+ [ _] => format_1d_array ( & view. view ( ) . into_dimensionality :: < Ix1 > ( ) . unwrap ( ) , f, format, limit) ?,
90+ // For n-dimensional arrays, we proceed recursively
91+ shape => {
92+ // Cast into a dynamically dimensioned view
93+ // This is required to be able to use `index_axis`
94+ let view = view. view ( ) . into_dyn ( ) ;
95+ // We start by checking what indexes from the first axis should be printed
96+ // We put a `None` in the middle if we are omitting elements
97+ let to_be_printed = to_be_printed ( shape[ 0 ] , limit) ;
98+
99+ let n_to_be_printed = to_be_printed. len ( ) ;
100+
101+ write ! ( f, "[" ) ?;
102+ for ( j, index) in to_be_printed. into_iter ( ) . enumerate ( ) {
103+ match index {
104+ PrintableCell :: ElementIndex ( i) => {
105+ // Proceed recursively with the (n-1)-dimensional slice
106+ format_array (
107+ & view. index_axis ( Axis ( 0 ) , i) , f, format. clone ( ) , limit
108+ ) ?;
109+ // We need to add a separator after each slice,
110+ // apart from the last one
111+ if j != n_to_be_printed - 1 {
112+ write ! ( f, ",\n " ) ?
113+ }
114+ } ,
115+ PrintableCell :: Ellipses => write ! ( f, "...,\n " ) ?
111116 }
112- no_rows_after_skip_yet = false ;
113- write ! ( f, "{}" , " " . repeat( ndim - n) ) ?;
114- write ! ( f, "{}" , "[" . repeat( n) ) ?;
115- } else if !printed_ellipses_h[ skip_row_for_axis. unwrap ( ) ] {
116- let ax = skip_row_for_axis. unwrap ( ) ;
117- let n = ndim - i - 1 ;
118- write ! ( f, "{}" , "]" . repeat( n) ) ?;
119- writeln ! ( f, "," ) ?;
120- write ! ( f, "{}" , " " . repeat( ax + 1 ) ) ?;
121- writeln ! ( f, "...," ) ?;
122- printed_ellipses_h[ ax] = true ;
123- }
124- last_index = index. clone ( ) ;
125- }
126-
127- if skip_row_for_axis. is_none ( ) {
128- let nth_idx_op = index. slice ( ) . iter ( ) . last ( ) ;
129- if overflow_axes. contains ( & ( ndim - 1 ) ) {
130- let nth_idx_val = nth_idx_op. unwrap ( ) ;
131- if nth_idx_val >= & limit && nth_idx_val < & ( nth_idx_max - & limit) {
132- if nth_idx_val == & limit {
133- write ! ( f, ", ..." ) ?;
134- }
135- continue ;
136- }
137- }
138-
139- if max_changed_idx. is_none ( ) && !index. slice ( ) . iter ( ) . all ( |x| * x == 0 ) {
140- write ! ( f, ", " ) ?;
141117 }
142- format ( elt , f ) ?;
118+ write ! ( f , "]" ) ?;
143119 }
144120 }
145- write ! ( f, "{}" , "]" . repeat( ndim) ) ?;
146121 Ok ( ( ) )
147122}
148123
@@ -240,15 +215,17 @@ mod formatting_with_omit {
240215 let a: Array2 < u32 > = arr2 ( & [ [ ] , [ ] ] ) ;
241216 let actual_output = format ! ( "{}" , a) ;
242217 let expected_output = String :: from ( "[[]]" ) ;
243- assert_eq ! ( actual_output, expected_output) ;
218+ print_output_diff ( & expected_output, & actual_output) ;
219+ assert_eq ! ( expected_output, actual_output) ;
244220 }
245221
246222 #[ test]
247223 fn zero_length_axes ( ) {
248224 let a = Array3 :: < f32 > :: zeros ( ( 3 , 0 , 4 ) ) ;
249225 let actual_output = format ! ( "{}" , a) ;
250226 let expected_output = String :: from ( "[[[]]]" ) ;
251- assert_eq ! ( actual_output, expected_output) ;
227+ print_output_diff ( & expected_output, & actual_output) ;
228+ assert_eq ! ( expected_output, actual_output) ;
252229 }
253230
254231 #[ test]
@@ -257,7 +234,8 @@ mod formatting_with_omit {
257234 let a = arr0 ( element) ;
258235 let actual_output = format ! ( "{}" , a) ;
259236 let expected_output = format ! ( "{}" , element) ;
260- assert_eq ! ( actual_output, expected_output) ;
237+ print_output_diff ( & expected_output, & actual_output) ;
238+ assert_eq ! ( expected_output, actual_output) ;
261239 }
262240
263241 #[ test]
0 commit comments