mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-11 02:19:56 -06:00
Merge pull request #5386 from storytold/fix/sec-name-suffix-linear
Brush and library names number repeats without rescanning
This commit is contained in:
@@ -781,10 +781,9 @@ pub fn unique_name(lib: &[Brush], base: &str) -> String {
|
||||
return base.to_string();
|
||||
}
|
||||
// At most `lib.len()` names are taken, so one of the first `lib.len() + 1` candidates is free.
|
||||
(2..=lib.len() + 2)
|
||||
.map(|i| format!("{base} {i}"))
|
||||
.find(|n| !lib.iter().any(|b| &b.name == n))
|
||||
.unwrap_or_else(|| format!("{base} {}", lib.len() + 2))
|
||||
// Each is looked up in a set: scanning the library per candidate is quadratic in its size.
|
||||
let taken: std::collections::HashSet<&str> = lib.iter().map(|b| b.name.as_str()).collect();
|
||||
(2..=lib.len() + 2).map(|i| format!("{base} {i}")).find(|n| !taken.contains(n.as_str())).unwrap_or_else(|| format!("{base} {}", lib.len() + 2))
|
||||
}
|
||||
|
||||
// ---------- geometry ----------
|
||||
|
||||
@@ -448,6 +448,8 @@ fn clip(name: &mut String) {
|
||||
fn uniquify<'a>(names: impl Iterator<Item = &'a mut String>, fallback: &str, sep: &str, fold: bool) {
|
||||
let key = |n: &str| if fold { n.to_lowercase() } else { n.to_string() };
|
||||
let mut seen = HashSet::new();
|
||||
// Per repeated name, the number to try next: a run of one name counts on instead of from 2.
|
||||
let mut next: std::collections::HashMap<String, usize> = std::collections::HashMap::new();
|
||||
for name in names {
|
||||
clip(name);
|
||||
if name.trim().is_empty() {
|
||||
@@ -455,7 +457,12 @@ fn uniquify<'a>(names: impl Iterator<Item = &'a mut String>, fallback: &str, sep
|
||||
}
|
||||
if seen.contains(&key(name)) {
|
||||
let base = name.clone();
|
||||
*name = (2..).map(|n| format!("{base}{sep}{n}")).find(|n| !seen.contains(&key(n))).unwrap_or_default();
|
||||
let n = next.entry(key(&base)).or_insert(2);
|
||||
while seen.contains(&key(&format!("{base}{sep}{n}"))) {
|
||||
*n += 1;
|
||||
}
|
||||
*name = format!("{base}{sep}{n}");
|
||||
*n += 1;
|
||||
}
|
||||
seen.insert(key(name));
|
||||
}
|
||||
|
||||
@@ -821,6 +821,18 @@ fn imported_libraries_are_made_consistent() {
|
||||
);
|
||||
}
|
||||
|
||||
/// A library of one name repeated as often as it may hold numbers the copies in one pass.
|
||||
#[test]
|
||||
fn a_library_of_one_repeated_name_imports_numbered() {
|
||||
let mut s = session();
|
||||
let red = json!({"name": "Red", "color": {"model": "rgb", "r": 1, "g": 0, "b": 0}});
|
||||
let lib = json!({"name": "Many", "colors": vec![red; 10_000]});
|
||||
run(&mut s, "library.import", json!({"data": lib.to_string()}));
|
||||
let got = run(&mut s, "library.get", json!({}));
|
||||
let colors = got["colors"].as_array().unwrap();
|
||||
assert_eq!((colors.len(), colors[1]["name"].as_str(), colors[9_999]["name"].as_str()), (10_000, Some("Red 2"), Some("Red 10000")));
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[test]
|
||||
fn a_library_is_exported_to_a_file_and_imported_from_it() {
|
||||
|
||||
Reference in New Issue
Block a user