diff --git a/src/db/db/dbCommonReader.cc b/src/db/db/dbCommonReader.cc index b1becdcfb..003fac6fb 100644 --- a/src/db/db/dbCommonReader.cc +++ b/src/db/db/dbCommonReader.cc @@ -146,8 +146,6 @@ CommonReaderBase::name_for_id (size_t id) const void CommonReaderBase::rename_cell (db::Layout &layout, size_t id, const std::string &cn) { - m_name_for_id.insert (std::make_pair (id, cn)); - std::map >::iterator iid = m_id_map.find (id); std::map >::iterator iname = m_name_map.find (cn); @@ -156,9 +154,22 @@ CommonReaderBase::rename_cell (db::Layout &layout, size_t id, const std::string } if (iname != m_name_map.end () && iname->second.first != null_id && iname->second.first != id) { - common_reader_error (tl::sprintf (tl::to_string (tr ("Same cell name %s, but different IDs: %ld and %ld")), cn, id, iname->second.first)); + + // picking a different name on name clash (issue #2088) + std::string cn_new = cn + "_id$" + tl::to_string (id); + for (size_t i = 0; m_name_map.find (cn_new) != m_name_map.end (); ++i) { + cn_new = cn + "_id$" + tl::to_string (id) + "$" + tl::to_string (i); + } + + common_reader_warn (tl::sprintf (tl::to_string (tr ("Same cell name %s, but different IDs: %ld and %ld, renaming first to %s")), cn, id, iname->second.first, cn_new)); + rename_cell (layout, id, cn_new); + + return; + } + m_name_for_id.insert (std::make_pair (id, cn)); + if (iid != m_id_map.end () && iname != m_name_map.end ()) { if (iname->second.second != iid->second.second) { diff --git a/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.cc b/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.cc index 548a4e447..204514649 100644 --- a/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.cc +++ b/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.cc @@ -26,6 +26,7 @@ #include "tlDeflate.h" #include "tlMath.h" +#include "tlUniqueName.h" #include @@ -1334,7 +1335,7 @@ OASISWriter::write_cellname_table (size_t &cellnames_table_pos, const std::vecto begin_table (cellnames_table_pos); write_record_id (sequential ? 3 : 4); - write_nstring (layout.cell_name (*cell)); + write_nstring (cell_nstring (*cell)); if (! sequential) { write ((unsigned long) *cell); } @@ -1476,6 +1477,31 @@ static bool skip_cell_body (const db::Cell &cref) return cref.is_ghost_cell () && cref.empty (); } +void +OASISWriter::create_cell_nstrings (const db::Layout &layout, const std::set &cell_set) +{ + m_cell_nstrings.clear (); + + std::set names; + + for (auto c = cell_set.begin (); c != cell_set.end (); ++c) { + + std::string cn = make_nstring (layout.cell_name (*c)); + cn = tl::unique_name (cn, names); + + m_cell_nstrings.insert (std::make_pair (*c, cn)); + names.insert (cn); + + } +} + +const char * +OASISWriter::cell_nstring (db::cell_index_type cell_index) +{ + auto n = m_cell_nstrings.find (cell_index); + tl_assert (n != m_cell_nstrings.end ()); + return n->second.c_str (); +} void OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLayoutOptions &options) @@ -1510,6 +1536,8 @@ OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::Save std::set cell_set; options.get_cells (layout, cell_set, layers); + create_cell_nstrings (layout, cell_set); + // create a cell index vector sorted bottom-up std::vector cells, cells_by_index; @@ -1602,7 +1630,7 @@ OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::Save is_top = (cell_set.find (*p) == cell_set.end ()); } if (is_top) { - write_property_def (s_top_cell_name, tl::Variant (make_nstring (layout.cell_name (*cell))), true); + write_property_def (s_top_cell_name, tl::Variant (cell_nstring (*cell)), true); } } diff --git a/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.h b/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.h index 9c7fbf491..0ba4a6283 100644 --- a/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.h +++ b/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.h @@ -216,6 +216,7 @@ private: std::map m_textstrings; std::map m_propnames; std::map m_propstrings; + std::map m_cell_nstrings; typedef std::vector property_value_list; @@ -248,6 +249,9 @@ private: OASISWriterOptions m_options; tl::AbsoluteProgress m_progress; + void create_cell_nstrings (const db::Layout &layout, const std::set &cell_set); + const char *cell_nstring(db::cell_index_type cell_index); + void write_record_id (char b); void write_byte (char b); void write_bytes (const char *b, size_t n); diff --git a/src/plugins/streamers/oasis/unit_tests/dbOASISReaderTests.cc b/src/plugins/streamers/oasis/unit_tests/dbOASISReaderTests.cc index 02d1f8a3c..cf2194257 100644 --- a/src/plugins/streamers/oasis/unit_tests/dbOASISReaderTests.cc +++ b/src/plugins/streamers/oasis/unit_tests/dbOASISReaderTests.cc @@ -662,20 +662,16 @@ TEST(Bug_1799) EXPECT_EQ (ps2.value (pn).to_string (), "hello, world!"); } +// Modified in #2088 to give a warning TEST(DuplicateCellname) { db::Manager m (false); db::Layout layout (&m); - try { - tl::InputStream file (tl::testdata () + "/oasis/duplicate_cellname.oas"); - db::OASISReader reader (file); - reader.read (layout); - EXPECT_EQ (false, true); - } catch (tl::CancelException &ex) { - // Seen when private test data is not installed - throw; - } catch (tl::Exception &ex) { - EXPECT_EQ (ex.msg ().find ("Same cell name TOP, but different IDs: 3 and 0 (position=1070, cell=)"), size_t (0)); - } + tl::InputStream file (tl::testdata () + "/oasis/duplicate_cellname.oas"); + db::OASISReader reader (file); + reader.read (layout); + + std::string fn_au (tl::testdata () + "/oasis/duplicate_cellname_au.oas"); + db::compare_layouts (_this, layout, fn_au, db::NoNormalization, 1); } diff --git a/src/plugins/streamers/oasis/unit_tests/dbOASISWriterTests.cc b/src/plugins/streamers/oasis/unit_tests/dbOASISWriterTests.cc index 3332e6e87..1621dddb0 100644 --- a/src/plugins/streamers/oasis/unit_tests/dbOASISWriterTests.cc +++ b/src/plugins/streamers/oasis/unit_tests/dbOASISWriterTests.cc @@ -2072,3 +2072,31 @@ TEST(130d) run_test130 (_this, true, true); } +// Issue #2088 (name duplication) +TEST(140) +{ + db::Layout layout_org; + + layout_org.add_cell ("X X"); + layout_org.add_cell ("X*X"); + + std::string tmp_file = tl::TestBase::tmp_file (tl::sprintf ("tmp_dbOASISWriter140.oas")); + + { + tl::OutputStream out (tmp_file); + db::SaveLayoutOptions options; + options.set_format ("OASIS"); + db::Writer writer (options); + writer.write (layout_org, out); + } + + { + tl::InputStream in (tmp_file); + db::Reader reader (in); + db::Layout gg; + reader.set_warnings_as_errors (true); + reader.read (gg); + + db::compare_layouts (_this, gg, tl::testdata () + "/oasis/dbOASISWriter40_au.gds", db::NoNormalization); + } +} diff --git a/testdata/oasis/dbOASISWriter40_au.gds b/testdata/oasis/dbOASISWriter40_au.gds new file mode 100644 index 000000000..e7cceb60f Binary files /dev/null and b/testdata/oasis/dbOASISWriter40_au.gds differ diff --git a/testdata/oasis/duplicate_cellname_au.oas b/testdata/oasis/duplicate_cellname_au.oas new file mode 100644 index 000000000..e3a32581f Binary files /dev/null and b/testdata/oasis/duplicate_cellname_au.oas differ