diff --git a/libs/gds21/src/write.rs b/libs/gds21/src/write.rs index ff06f87..6af03f4 100644 --- a/libs/gds21/src/write.rs +++ b/libs/gds21/src/write.rs @@ -13,20 +13,24 @@ pub struct GdsWriter<'wr> { impl<'wr> GdsWriter<'wr> { /// Create new [GdsWriter] with destination file `fname` pub fn open(fname: impl AsRef) -> GdsResult { - let file = BufWriter::new(File::create(fname)?); - Ok(Self::new(file)) + Ok(Self::new(File::create(fname)?)) } /// Create a new [GdsWriter] to destination `dest` + /// + /// Writes to `dest` are buffered, since records are encoded a few bytes at a time. pub fn new(dest: impl Write + 'wr) -> Self { Self { - dest: Box::new(dest), + dest: Box::new(BufWriter::new(dest)), } } /// Write [GdsLibrary] `lib` to our destination pub fn write_lib(&mut self, lib: &GdsLibrary) -> GdsResult<()> { // `write_lib` is our typicaly entry point when writing to file. // It quickly dispatches most behavior off to our implementation of the [Encode] trait. - self.encode_lib(lib) + self.encode_lib(lib)?; + // Flush explicitly: dropping the buffer would discard any write error. + self.dest.flush()?; + Ok(()) } /// Helper to write a sequence of [GdsRecord] references fn write_records(&mut self, records: &[GdsRecord]) -> GdsResult<()> { diff --git a/substrate/src/layout/convert/gds.rs b/substrate/src/layout/convert/gds.rs index b386c32..0afd5fe 100644 --- a/substrate/src/layout/convert/gds.rs +++ b/substrate/src/layout/convert/gds.rs @@ -49,6 +49,10 @@ pub struct GdsExporter<'a> { layers: Arc>, backtrace: Vec, names_used: HashSet, + /// The next suffix to try when renaming a cell with a given name. + /// + /// Every lower suffix is already in `names_used`. + next_suffix: HashMap, /// The top level cell. /// /// The name of this cell will be preserved. @@ -82,6 +86,7 @@ impl SubstrateCtx { layers: data.layers(), backtrace: Vec::new(), names_used: HashSet::with_capacity(data.layouts().cells().count()), + next_suffix: HashMap::new(), top: None, export_set: ExportSet::All, names: SecondaryMap::new(), @@ -105,6 +110,7 @@ impl SubstrateCtx { layers: data.layers(), backtrace: Vec::new(), names_used: HashSet::with_capacity(data.layouts().cells().count()), + next_suffix: HashMap::new(), export_set: ExportSet::for_top(&top), top: Some(top), names: SecondaryMap::new(), @@ -536,13 +542,15 @@ impl<'a> GdsExporter<'a> { fn get_cell_name(&mut self, cell: &Arc) -> ArcStr { let name = cell.name(); let name = if self.names_used.contains(name) && !self.is_top(cell) { - let mut i = 1; + // Resume where the previous search for this name stopped. Scanning from 1 + // every time is quadratic in the number of cells sharing a name. + let i = self.next_suffix.entry(name.clone()).or_insert(1); loop { let newname = arcstr::format!("{}_{}", name, i); + *i += 1; if !self.names_used.contains(&newname) { break newname; } - i += 1; } } else { name.clone()