8
8
use std:: fmt;
9
9
use super :: {
10
10
ArrayBase ,
11
+ Axis ,
11
12
Data ,
12
13
Dimension ,
13
14
NdProducer ,
15
+ Ix
14
16
} ;
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 > ,
23
29
{
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, ", " ) ?;
64
41
}
65
- first = true ;
66
- update_index = true ;
67
- break ;
68
- }
69
- }
70
- if !first {
71
- write ! ( f, ", " ) ?;
42
+ } ,
43
+ PrintableCell :: Ellipses => write ! ( f, "..., " ) ?,
72
44
}
73
- first = false ;
74
- format ( elt, f) ?;
45
+ }
46
+ write ! ( f, "]" ) ?;
47
+ Ok ( ( ) )
48
+ }
75
49
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
79
66
}
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
+ }
82
120
}
83
121
Ok ( ( ) )
84
122
}
@@ -92,7 +130,7 @@ impl<'a, A: fmt::Display, S, D: Dimension> fmt::Display for ArrayBase<S, D>
92
130
where S : Data < Elem =A > ,
93
131
{
94
132
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
95
- format_array ( self , f, <_ >:: fmt)
133
+ format_array ( self , f, <_ >:: fmt, PRINT_ELEMENTS_LIMIT )
96
134
}
97
135
}
98
136
@@ -105,7 +143,7 @@ impl<'a, A: fmt::Debug, S, D: Dimension> fmt::Debug for ArrayBase<S, D>
105
143
{
106
144
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
107
145
// Add extra information for Debug
108
- format_array ( self , f, <_ >:: fmt) ?;
146
+ format_array ( self , f, <_ >:: fmt, PRINT_ELEMENTS_LIMIT ) ?;
109
147
write ! ( f, " shape={:?}, strides={:?}, layout={:?}" ,
110
148
self . shape( ) , self . strides( ) , layout=self . view( ) . layout( ) ) ?;
111
149
match D :: NDIM {
@@ -124,7 +162,7 @@ impl<'a, A: fmt::LowerExp, S, D: Dimension> fmt::LowerExp for ArrayBase<S, D>
124
162
where S : Data < Elem =A > ,
125
163
{
126
164
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
127
- format_array ( self , f, <_ >:: fmt)
165
+ format_array ( self , f, <_ >:: fmt, PRINT_ELEMENTS_LIMIT )
128
166
}
129
167
}
130
168
@@ -136,7 +174,7 @@ impl<'a, A: fmt::UpperExp, S, D: Dimension> fmt::UpperExp for ArrayBase<S, D>
136
174
where S : Data < Elem =A > ,
137
175
{
138
176
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
139
- format_array ( self , f, <_ >:: fmt)
177
+ format_array ( self , f, <_ >:: fmt, PRINT_ELEMENTS_LIMIT )
140
178
}
141
179
}
142
180
/// 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>
147
185
where S : Data < Elem =A > ,
148
186
{
149
187
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
150
- format_array ( self , f, <_ >:: fmt)
188
+ format_array ( self , f, <_ >:: fmt, PRINT_ELEMENTS_LIMIT )
151
189
}
152
190
}
153
191
@@ -159,6 +197,161 @@ impl<'a, A: fmt::Binary, S, D: Dimension> fmt::Binary for ArrayBase<S, D>
159
197
where S : Data < Elem =A > ,
160
198
{
161
199
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) ;
163
356
}
164
357
}
0 commit comments