88use std:: fmt;
99use super :: {
1010 ArrayBase ,
11+ Axis ,
1112 Data ,
1213 Dimension ,
1314 NdProducer ,
15+ Ix
1416} ;
15- use crate :: dimension:: IntoDimension ;
16-
17- fn format_array < A , S , D , F > ( view : & ArrayBase < S , D > , f : & mut fmt:: Formatter ,
18- mut format : F )
19- -> fmt:: Result
20- where F : FnMut ( & A , & mut fmt:: Formatter ) -> fmt:: Result ,
21- D : Dimension ,
22- S : Data < Elem =A > ,
17+ use crate :: aliases:: Ix1 ;
18+
19+ const PRINT_ELEMENTS_LIMIT : Ix = 3 ;
20+
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 > ,
2329{
24- let ndim = view. dim . slice ( ) . len ( ) ;
25- /* private nowadays
26- if ndim > 0 && f.width.is_none() {
27- f.width = Some(4)
28- }
29- */
30- // None will be an empty iter.
31- let mut last_index = match view. dim . first_index ( ) {
32- None => view. dim . clone ( ) ,
33- Some ( ix) => ix,
34- } ;
35- for _ in 0 ..ndim {
36- write ! ( f, "[" ) ?;
37- }
38- let mut first = true ;
39- // Simply use the indexed iterator, and take the index wraparounds
40- // as cues for when to add []'s and how many to add.
41- for ( index, elt) in view. indexed_iter ( ) {
42- let index = index. into_dimension ( ) ;
43- let take_n = if ndim == 0 { 1 } else { ndim - 1 } ;
44- let mut update_index = false ;
45- for ( i, ( a, b) ) in index. slice ( )
46- . iter ( )
47- . take ( take_n)
48- . zip ( last_index. slice ( ) . iter ( ) )
49- . enumerate ( ) {
50- if a != b {
51- // New row.
52- // # of ['s needed
53- let n = ndim - i - 1 ;
54- for _ in 0 ..n {
55- write ! ( f, "]" ) ?;
56- }
57- write ! ( f, "," ) ?;
58- write ! ( f, "\n " ) ?;
59- for _ in 0 ..ndim - n {
60- write ! ( f, " " ) ?;
61- }
62- for _ in 0 ..n {
63- write ! ( f, "[" ) ?;
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, ", " ) ?;
6441 }
65- first = true ;
66- update_index = true ;
67- break ;
68- }
69- }
70- if !first {
71- write ! ( f, ", " ) ?;
42+ } ,
43+ PrintableCell :: Ellipses => write ! ( f, "..., " ) ?,
7244 }
73- first = false ;
74- format ( elt, f) ?;
45+ }
46+ write ! ( f, "]" ) ?;
47+ Ok ( ( ) )
48+ }
7549
76- if update_index {
77- last_index = index;
78- }
50+ enum PrintableCell {
51+ ElementIndex ( usize ) ,
52+ Ellipses ,
53+ }
54+
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
7966 }
80- for _ in 0 ..ndim {
81- write ! ( f, "]" ) ?;
67+ }
68+
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 > ,
78+ {
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 ( ( ) )
84+ }
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 " ) ?
116+ }
117+ }
118+ write ! ( f, "]" ) ?;
119+ }
82120 }
83121 Ok ( ( ) )
84122}
@@ -92,7 +130,7 @@ impl<'a, A: fmt::Display, S, D: Dimension> fmt::Display for ArrayBase<S, D>
92130 where S : Data < Elem =A > ,
93131{
94132 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
95- format_array ( self , f, <_ >:: fmt)
133+ format_array ( self , f, <_ >:: fmt, PRINT_ELEMENTS_LIMIT )
96134 }
97135}
98136
@@ -105,7 +143,7 @@ impl<'a, A: fmt::Debug, S, D: Dimension> fmt::Debug for ArrayBase<S, D>
105143{
106144 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
107145 // Add extra information for Debug
108- format_array ( self , f, <_ >:: fmt) ?;
146+ format_array ( self , f, <_ >:: fmt, PRINT_ELEMENTS_LIMIT ) ?;
109147 write ! ( f, " shape={:?}, strides={:?}, layout={:?}" ,
110148 self . shape( ) , self . strides( ) , layout=self . view( ) . layout( ) ) ?;
111149 match D :: NDIM {
@@ -124,7 +162,7 @@ impl<'a, A: fmt::LowerExp, S, D: Dimension> fmt::LowerExp for ArrayBase<S, D>
124162 where S : Data < Elem =A > ,
125163{
126164 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
127- format_array ( self , f, <_ >:: fmt)
165+ format_array ( self , f, <_ >:: fmt, PRINT_ELEMENTS_LIMIT )
128166 }
129167}
130168
@@ -136,7 +174,7 @@ impl<'a, A: fmt::UpperExp, S, D: Dimension> fmt::UpperExp for ArrayBase<S, D>
136174 where S : Data < Elem =A > ,
137175{
138176 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
139- format_array ( self , f, <_ >:: fmt)
177+ format_array ( self , f, <_ >:: fmt, PRINT_ELEMENTS_LIMIT )
140178 }
141179}
142180/// Format the array using `LowerHex` and apply the formatting parameters used
@@ -147,7 +185,7 @@ impl<'a, A: fmt::LowerHex, S, D: Dimension> fmt::LowerHex for ArrayBase<S, D>
147185 where S : Data < Elem =A > ,
148186{
149187 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
150- format_array ( self , f, <_ >:: fmt)
188+ format_array ( self , f, <_ >:: fmt, PRINT_ELEMENTS_LIMIT )
151189 }
152190}
153191
@@ -159,6 +197,161 @@ impl<'a, A: fmt::Binary, S, D: Dimension> fmt::Binary for ArrayBase<S, D>
159197 where S : Data < Elem =A > ,
160198{
161199 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
162- format_array ( self , f, <_ >:: fmt)
200+ format_array ( self , f, <_ >:: fmt, PRINT_ELEMENTS_LIMIT )
201+ }
202+ }
203+
204+ #[ cfg( test) ]
205+ mod formatting_with_omit {
206+ use crate :: prelude:: * ;
207+ use super :: * ;
208+
209+ fn print_output_diff ( expected : & str , actual : & str ) {
210+ println ! ( "Expected output:\n {}\n Actual output:\n {}" , expected, actual) ;
211+ }
212+
213+ #[ test]
214+ fn empty_arrays ( ) {
215+ let a: Array2 < u32 > = arr2 ( & [ [ ] , [ ] ] ) ;
216+ let actual_output = format ! ( "{}" , a) ;
217+ let expected_output = String :: from ( "[[]]" ) ;
218+ print_output_diff ( & expected_output, & actual_output) ;
219+ assert_eq ! ( expected_output, actual_output) ;
220+ }
221+
222+ #[ test]
223+ fn zero_length_axes ( ) {
224+ let a = Array3 :: < f32 > :: zeros ( ( 3 , 0 , 4 ) ) ;
225+ let actual_output = format ! ( "{}" , a) ;
226+ let expected_output = String :: from ( "[[[]]]" ) ;
227+ print_output_diff ( & expected_output, & actual_output) ;
228+ assert_eq ! ( expected_output, actual_output) ;
229+ }
230+
231+ #[ test]
232+ fn dim_0 ( ) {
233+ let element = 12 ;
234+ let a = arr0 ( element) ;
235+ let actual_output = format ! ( "{}" , a) ;
236+ let expected_output = format ! ( "{}" , element) ;
237+ print_output_diff ( & expected_output, & actual_output) ;
238+ assert_eq ! ( expected_output, actual_output) ;
239+ }
240+
241+ #[ test]
242+ fn dim_1 ( ) {
243+ let overflow: usize = 5 ;
244+ let a = Array1 :: from_elem ( ( PRINT_ELEMENTS_LIMIT * 2 + overflow, ) , 1 ) ;
245+ let mut expected_output = String :: from ( "[" ) ;
246+ a. iter ( )
247+ . take ( PRINT_ELEMENTS_LIMIT )
248+ . for_each ( |elem| { expected_output. push_str ( format ! ( "{}, " , elem) . as_str ( ) ) } ) ;
249+ expected_output. push_str ( "..." ) ;
250+ a. iter ( )
251+ . skip ( PRINT_ELEMENTS_LIMIT + overflow)
252+ . for_each ( |elem| { expected_output. push_str ( format ! ( ", {}" , elem) . as_str ( ) ) } ) ;
253+ expected_output. push ( ']' ) ;
254+ let actual_output = format ! ( "{}" , a) ;
255+
256+ print_output_diff ( & expected_output, & actual_output) ;
257+ assert_eq ! ( actual_output, expected_output) ;
258+ }
259+
260+ #[ test]
261+ fn dim_2_last_axis_overflow ( ) {
262+ let overflow: usize = 3 ;
263+ let a = Array2 :: from_elem ( ( PRINT_ELEMENTS_LIMIT , PRINT_ELEMENTS_LIMIT * 2 + overflow) , 1 ) ;
264+ let mut expected_output = String :: from ( "[" ) ;
265+
266+ for i in 0 ..PRINT_ELEMENTS_LIMIT {
267+ expected_output. push_str ( format ! ( "[{}" , a[ ( i, 0 ) ] ) . as_str ( ) ) ;
268+ for j in 1 ..PRINT_ELEMENTS_LIMIT {
269+ expected_output. push_str ( format ! ( ", {}" , a[ ( i, j) ] ) . as_str ( ) ) ;
270+ }
271+ expected_output. push_str ( ", ..." ) ;
272+ for j in PRINT_ELEMENTS_LIMIT + overflow..PRINT_ELEMENTS_LIMIT * 2 + overflow {
273+ expected_output. push_str ( format ! ( ", {}" , a[ ( i, j) ] ) . as_str ( ) ) ;
274+ }
275+ expected_output. push_str ( if i < PRINT_ELEMENTS_LIMIT - 1 { "],\n " } else { "]" } ) ;
276+ }
277+ expected_output. push ( ']' ) ;
278+ let actual_output = format ! ( "{}" , a) ;
279+
280+ print_output_diff ( & expected_output, & actual_output) ;
281+ assert_eq ! ( actual_output, expected_output) ;
282+ }
283+
284+ #[ test]
285+ fn dim_2_non_last_axis_overflow ( ) {
286+ let overflow: usize = 5 ;
287+ let a = Array2 :: from_elem ( ( PRINT_ELEMENTS_LIMIT * 2 + overflow, PRINT_ELEMENTS_LIMIT ) , 1 ) ;
288+ let mut expected_output = String :: from ( "[" ) ;
289+
290+ for i in 0 ..PRINT_ELEMENTS_LIMIT {
291+ expected_output. push_str ( format ! ( "[{}" , a[ ( i, 0 ) ] ) . as_str ( ) ) ;
292+ for j in 1 ..PRINT_ELEMENTS_LIMIT {
293+ expected_output. push_str ( format ! ( ", {}" , a[ ( i, j) ] ) . as_str ( ) ) ;
294+ }
295+ expected_output. push_str ( "],\n " ) ;
296+ }
297+ expected_output. push_str ( "...,\n " ) ;
298+ for i in PRINT_ELEMENTS_LIMIT + overflow..PRINT_ELEMENTS_LIMIT * 2 + overflow {
299+ expected_output. push_str ( format ! ( "[{}" , a[ ( i, 0 ) ] ) . as_str ( ) ) ;
300+ for j in 1 ..PRINT_ELEMENTS_LIMIT {
301+ expected_output. push_str ( format ! ( ", {}" , a[ ( i, j) ] ) . as_str ( ) ) ;
302+ }
303+ expected_output. push_str ( if i == PRINT_ELEMENTS_LIMIT * 2 + overflow - 1 {
304+ "]"
305+ } else {
306+ "],\n "
307+ } ) ;
308+ }
309+ expected_output. push ( ']' ) ;
310+ let actual_output = format ! ( "{}" , a) ;
311+
312+ print_output_diff ( & expected_output, & actual_output) ;
313+ assert_eq ! ( actual_output, expected_output) ;
314+ }
315+
316+ #[ test]
317+ fn dim_2_multi_directional_overflow ( ) {
318+ let overflow: usize = 5 ;
319+ let a = Array2 :: from_elem (
320+ ( PRINT_ELEMENTS_LIMIT * 2 + overflow, PRINT_ELEMENTS_LIMIT * 2 + overflow) , 1
321+ ) ;
322+ let mut expected_output = String :: from ( "[" ) ;
323+
324+ for i in 0 ..PRINT_ELEMENTS_LIMIT {
325+ expected_output. push_str ( format ! ( "[{}" , a[ ( i, 0 ) ] ) . as_str ( ) ) ;
326+ for j in 1 ..PRINT_ELEMENTS_LIMIT {
327+ expected_output. push_str ( format ! ( ", {}" , a[ ( i, j) ] ) . as_str ( ) ) ;
328+ }
329+ expected_output. push_str ( ", ..." ) ;
330+ for j in PRINT_ELEMENTS_LIMIT + overflow..PRINT_ELEMENTS_LIMIT * 2 + overflow {
331+ expected_output. push_str ( format ! ( ", {}" , a[ ( i, j) ] ) . as_str ( ) ) ;
332+ }
333+ expected_output. push_str ( "],\n " ) ;
334+ }
335+ expected_output. push_str ( "...,\n " ) ;
336+ for i in PRINT_ELEMENTS_LIMIT + overflow..PRINT_ELEMENTS_LIMIT * 2 + overflow {
337+ expected_output. push_str ( format ! ( "[{}" , a[ ( i, 0 ) ] ) . as_str ( ) ) ;
338+ for j in 1 ..PRINT_ELEMENTS_LIMIT {
339+ expected_output. push_str ( format ! ( ", {}" , a[ ( i, j) ] ) . as_str ( ) ) ;
340+ }
341+ expected_output. push_str ( ", ..." ) ;
342+ for j in PRINT_ELEMENTS_LIMIT + overflow..PRINT_ELEMENTS_LIMIT * 2 + overflow {
343+ expected_output. push_str ( format ! ( ", {}" , a[ ( i, j) ] ) . as_str ( ) ) ;
344+ }
345+ expected_output. push_str ( if i == PRINT_ELEMENTS_LIMIT * 2 + overflow - 1 {
346+ "]"
347+ } else {
348+ "],\n "
349+ } ) ;
350+ }
351+ expected_output. push ( ']' ) ;
352+ let actual_output = format ! ( "{}" , a) ;
353+
354+ print_output_diff ( & expected_output, & actual_output) ;
355+ assert_eq ! ( actual_output, expected_output) ;
163356 }
164357}
0 commit comments