mirror of
https://github.com/storytold/gridcraft.git
synced 2026-11-07 02:51:33 +00:00
XLSX: form controls find their VML shapes through an index
Each control listed in <controls> looked for its VML shape by scanning every shape, so a sheet of 10,000 controls took over 8 s to open. The shapes are now indexed by number once, and the same sheet opens in about 0.4 s.
This commit is contained in:
1 parent
0e631e20da
commit
cc68d71ac2
2 files changed
+30
-2
No files matched your search
@@ -12,7 +12,7 @@
|
||||
//! list boxes, drop-downs, ActiveX controls) are left to pass-through (`passthrough.rs`), which
|
||||
//! keeps them unchanged; a sheet can hold both, in one `<controls>` element and one VML drawing.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fmt::Write as _;
|
||||
|
||||
use gridcraft_core::CellRef;
|
||||
@@ -404,7 +404,14 @@ pub fn read(cx: &mut Ctx<'_>, controls: Option<&El>, rels: &[Rel], sheet: &mut S
|
||||
None => None,
|
||||
};
|
||||
let shapes: Vec<&El> = vml.as_ref().map(|v| v.kids("shape").collect()).unwrap_or_default();
|
||||
let shape_of = |n: u64| shapes.iter().copied().find(|s| number_of(s) == Some(n));
|
||||
// Looked up once per listed control: an index keeps a sheet of many controls linear.
|
||||
let mut by_number: HashMap<u64, &El> = HashMap::with_capacity(shapes.len());
|
||||
for s in &shapes {
|
||||
if let Some(n) = number_of(s) {
|
||||
by_number.entry(n).or_insert(s);
|
||||
}
|
||||
}
|
||||
let shape_of = |n: u64| by_number.get(&n).copied();
|
||||
// Every shape the sheet lists, read here or not.
|
||||
let mut listed: HashSet<u64> = HashSet::new();
|
||||
for ctl in controls.map(controls_in).unwrap_or_default() {
|
||||
|
||||
@@ -282,3 +282,24 @@ fn hostile_form_controls_are_capped_and_repaired() {
|
||||
let (back, _) = read_xlsx(&write_xlsx(&wb).unwrap()).unwrap();
|
||||
assert_eq!(back.sheet(0).unwrap().controls.len(), c.len());
|
||||
}
|
||||
|
||||
/// Each listed control finds its VML shape through an index, so a sheet of many controls reads in
|
||||
/// linear time (it used to scan every shape for every control).
|
||||
#[test]
|
||||
#[allow(clippy::disallowed_methods)] // a native-only timing test: the clock is read off wasm
|
||||
fn many_listed_controls_read_in_linear_time() {
|
||||
let mut wb = Workbook::default();
|
||||
if let Some(sh) = wb.sheet_mut(0) {
|
||||
for i in 0..10_000u32 {
|
||||
let a = anchor(&format!("B{}", i + 1), 60.0, 18.0);
|
||||
sh.controls.push(FormControl { id: i + 1, kind: ControlKind::Spin, anchor: a, ..Default::default() });
|
||||
}
|
||||
}
|
||||
let bytes = write_xlsx(&wb).unwrap();
|
||||
let t0 = std::time::Instant::now();
|
||||
let (back, _) = read_xlsx(&bytes).unwrap();
|
||||
let took = t0.elapsed();
|
||||
assert_eq!(back.sheet(0).unwrap().controls.len(), 10_000);
|
||||
// About 0.4 s here; scanning every shape for every control took over 8 s.
|
||||
assert!(took < std::time::Duration::from_secs(3), "{took:?}");
|
||||
}
|
||||
Reference in new issue
Block a user