Skip to content

Commit 76eaef4

Browse files
committed
Simplify array formatting code
1 parent 49948c2 commit 76eaef4

File tree

1 file changed

+65
-81
lines changed

1 file changed

+65
-81
lines changed

src/arrayformat.rs

+65-81
Original file line numberDiff line numberDiff line change
@@ -11,53 +11,54 @@ use std::fmt;
1111

1212
const PRINT_ELEMENTS_LIMIT: Ix = 3;
1313

14-
fn format_1d_array<A, S, F>(
15-
view: &ArrayBase<S, Ix1>,
14+
const ELLIPSIS: &str = "...";
15+
16+
/// Formats the contents of a list of items, using an ellipsis to indicate when
17+
/// the length of the list is greater than `2 * limit`.
18+
///
19+
/// # Parameters
20+
///
21+
/// * `f`: The formatter.
22+
/// * `length`: The length of the list.
23+
/// * `limit`: Half the maximum number of items before indicating overflow with
24+
/// an ellipsis. Also, the number of items on either side of the ellipsis.
25+
/// * `separator`: Separator to write between items.
26+
/// * `ellipsis`: Ellipsis for indicating overflow.
27+
/// * `fmt_elem`: A function that formats an element in the list, given the
28+
/// formatter and the index of the item in the list.
29+
fn format_with_overflow<F>(
1630
f: &mut fmt::Formatter<'_>,
17-
mut format: F,
18-
limit: Ix,
31+
length: usize,
32+
limit: usize,
33+
separator: &str,
34+
ellipsis: &str,
35+
mut fmt_elem: F,
1936
) -> fmt::Result
2037
where
21-
F: FnMut(&A, &mut fmt::Formatter<'_>) -> fmt::Result,
22-
S: Data<Elem = A>,
38+
F: FnMut(&mut fmt::Formatter<'_>, usize) -> fmt::Result,
2339
{
24-
let to_be_printed = to_be_printed(view.len(), limit);
25-
26-
let n_to_be_printed = to_be_printed.len();
27-
28-
write!(f, "[")?;
29-
for (j, index) in to_be_printed.into_iter().enumerate() {
30-
match index {
31-
PrintableCell::ElementIndex(i) => {
32-
format(&view[i], f)?;
33-
if j != n_to_be_printed - 1 {
34-
write!(f, ", ")?;
35-
}
36-
}
37-
PrintableCell::Ellipses => write!(f, "..., ")?,
38-
}
39-
}
40-
write!(f, "]")?;
41-
Ok(())
42-
}
43-
44-
enum PrintableCell {
45-
ElementIndex(usize),
46-
Ellipses,
47-
}
48-
49-
// Returns what indexes should be printed for a certain axis.
50-
// If the axis is longer than 2 * limit, a `Ellipses` is inserted
51-
// where indexes are being omitted.
52-
fn to_be_printed(length: usize, limit: usize) -> Vec<PrintableCell> {
53-
if length <= 2 * limit {
54-
(0..length).map(PrintableCell::ElementIndex).collect()
40+
if length == 0 {
41+
// no-op
42+
} else if length <= 2 * limit {
43+
fmt_elem(f, 0)?;
44+
(1..length).try_for_each(|i| {
45+
f.write_str(separator)?;
46+
fmt_elem(f, i)
47+
})?;
5548
} else {
56-
let mut v: Vec<PrintableCell> = (0..limit).map(PrintableCell::ElementIndex).collect();
57-
v.push(PrintableCell::Ellipses);
58-
v.extend((length - limit..length).map(PrintableCell::ElementIndex));
59-
v
49+
fmt_elem(f, 0)?;
50+
(1..limit).try_for_each(|i| {
51+
f.write_str(separator)?;
52+
fmt_elem(f, i)
53+
})?;
54+
f.write_str(separator)?;
55+
f.write_str(ellipsis)?;
56+
(length - limit..length).try_for_each(|i| {
57+
f.write_str(separator)?;
58+
fmt_elem(f, i)
59+
})?;
6060
}
61+
Ok(())
6162
}
6263

6364
fn format_array<A, S, D, F>(
@@ -80,54 +81,37 @@ where
8081
}
8182
match view.shape() {
8283
// If it's 0 dimensional, we just print out the scalar
83-
[] => format(view.iter().next().unwrap(), f)?,
84-
// We delegate 1-dimensional arrays to a specialized function
85-
[_] => format_1d_array(
86-
&view.view().into_dimensionality::<Ix1>().unwrap(),
87-
f,
88-
format,
89-
limit,
90-
)?,
84+
&[] => format(view.iter().next().unwrap(), f)?,
85+
// We handle 1-D arrays as a special case
86+
&[len] => {
87+
let view = view.view().into_dimensionality::<Ix1>().unwrap();
88+
f.write_str("[")?;
89+
format_with_overflow(f, len, limit, ", ", ELLIPSIS, |f, index| {
90+
format(&view[index], f)
91+
})?;
92+
f.write_str("]")?;
93+
}
9194
// For n-dimensional arrays, we proceed recursively
9295
shape => {
9396
// Cast into a dynamically dimensioned view
9497
// This is required to be able to use `index_axis`
9598
let view = view.view().into_dyn();
96-
// We start by checking what indexes from the first axis should be printed
97-
// We put a `None` in the middle if we are omitting elements
98-
let to_be_printed = to_be_printed(shape[0], limit);
99-
100-
let n_to_be_printed = to_be_printed.len();
10199

102100
let blank_lines = "\n".repeat(shape.len() - 2);
103101
let indent = " ".repeat(depth + 1);
104-
105-
write!(f, "[")?;
106-
for (j, index) in to_be_printed.into_iter().enumerate() {
107-
match index {
108-
PrintableCell::ElementIndex(i) => {
109-
// Indent all but the first line.
110-
if j != 0 {
111-
write!(f, "{}", indent)?;
112-
}
113-
// Proceed recursively with the (n-1)-dimensional slice
114-
format_array(
115-
&view.index_axis(Axis(0), i),
116-
f,
117-
format.clone(),
118-
limit,
119-
depth + 1,
120-
)?;
121-
// We need to add a separator after each slice,
122-
// apart from the last one
123-
if j != n_to_be_printed - 1 {
124-
write!(f, ",\n{}", blank_lines)?
125-
}
126-
}
127-
PrintableCell::Ellipses => write!(f, "{}...,\n{}", indent, blank_lines)?,
128-
}
129-
}
130-
write!(f, "]")?;
102+
let separator = format!(",\n{}{}", blank_lines, indent);
103+
104+
f.write_str("[")?;
105+
format_with_overflow(f, shape[0], limit, &separator, ELLIPSIS, |f, index| {
106+
format_array(
107+
&view.index_axis(Axis(0), index),
108+
f,
109+
format.clone(),
110+
limit,
111+
depth + 1,
112+
)
113+
})?;
114+
f.write_str("]")?;
131115
}
132116
}
133117
Ok(())

0 commit comments

Comments
 (0)