diff --git a/crates/xlsx/src/styles.rs b/crates/xlsx/src/styles.rs index e80f5928e..f25424d59 100644 --- a/crates/xlsx/src/styles.rs +++ b/crates/xlsx/src/styles.rs @@ -393,12 +393,14 @@ pub fn read_styles(root: &El, checkboxes: &[bool], minor_font: &str) -> StylesIn } } } - let dxfs = root.child("dxfs").map(|d| d.kids("dxf").map(|x| read_dxf(x, &palette, &shared_fmts)).collect()).unwrap_or_default(); + // Inline dxf format codes are interned: a code repeated by many dxfs is one allocation. + let mut inline_fmts = HashMap::new(); + let dxfs = root.child("dxfs").map(|d| d.kids("dxf").map(|x| read_dxf(x, &palette, &shared_fmts, &mut inline_fmts)).collect()).unwrap_or_default(); StylesIn { xfs, dxfs, palette, named, num_fmts: fmts } } /// One differential format (`dxf`): the style it sets over a cell's own. -fn read_dxf(x: &El, palette: &[u32], fmts: &HashMap) -> Style { +fn read_dxf<'a>(x: &'a El, palette: &[u32], fmts: &HashMap, inline_fmts: &mut HashMap<&'a str, NumFmt>) -> Style { let mut s = Style::default(); if let Some(e) = x.child("font") { let f = read_font(e, palette); @@ -421,7 +423,7 @@ fn read_dxf(x: &El, palette: &[u32], fmts: &HashMap) -> Style { } if let Some(n) = x.child("numFmt") { if let Some(code) = n.attr("formatCode") { - s.num_fmt = NumFmt::new(code); + s.num_fmt = inline_fmts.entry(code).or_insert_with(|| NumFmt::new(code)).clone(); } else if let Some(id) = n.attr_u32("numFmtId") { s.num_fmt = num_fmt_code(id, fmts); } diff --git a/crates/xlsx/src/tests/fixtures.rs b/crates/xlsx/src/tests/fixtures.rs index 76f40851b..7a5cc5676 100644 --- a/crates/xlsx/src/tests/fixtures.rs +++ b/crates/xlsx/src/tests/fixtures.rs @@ -869,3 +869,17 @@ fn every_skipped_drawing_object_is_reported() { assert_eq!(hits, 1, "object {n}: {:?}", rep.warnings); } } + +/// A number format code repeated by many differential formats is read into one allocation. +#[test] +fn inline_dxf_number_formats_are_shared() { + let code = format!("0.00{}", " \"x\"".repeat(50)); + let dxfs: String = (0..3).map(|_| format!(r#""#, code.replace('"', """))).collect(); + let styles = + format!(r#"{dxfs}"#); + let root = crate::xml::parse(styles.as_bytes()).unwrap(); + let read = crate::styles::read_styles(&root, &[], "Calibri"); + assert_eq!(read.dxfs.len(), 3); + assert_eq!(read.dxfs[0].num_fmt.as_str(), code); + assert!(read.dxfs.iter().all(|d| std::sync::Arc::ptr_eq(&d.num_fmt.0, &read.dxfs[0].num_fmt.0))); +}