diff --git a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc index 2d9c86dca..d87c74e6c 100644 --- a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc +++ b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc @@ -600,6 +600,16 @@ static const char magic_bytes[] = { "%SEMI-OASIS\015\012" }; static const char *klayout_context_propname = "KLAYOUT_CONTEXT"; static const char *s_gds_property_propname = "S_GDS_PROPERTY"; +static LayoutOrCellContextInfo +make_context_info (const std::vector &context_properties) +{ + std::vector context_strings; + context_strings.reserve (context_properties.size ()); + for (auto s = context_properties.begin (); s != context_properties.end (); ++s) { + context_strings.push_back (s->to_string ()); + } + return LayoutOrCellContextInfo::deserialize (context_strings.begin (), context_strings.end ()); +} void OASISReader::do_read (db::Layout &layout) @@ -678,6 +688,8 @@ OASISReader::do_read (db::Layout &layout) m_propstrings.clear (); m_propnames.clear (); + m_context_strings_per_cell.clear (); + m_instances.clear (); m_instances_with_props.clear (); @@ -878,20 +890,28 @@ OASISReader::do_read (db::Layout &layout) // exchange the properties in the repository // first locate all property sets that are affected - std::vector pids; - for (db::PropertiesRepository::iterator p = rep.begin (); p != rep.end (); ++p) { + std::map > cells_by_pid; + for (auto p = rep.begin (); p != rep.end (); ++p) { if (p->second.find (pf->second) != p->second.end ()) { - pids.push_back (p->first); + cells_by_pid.insert (std::make_pair (p->first, std::vector ())); + } + } + + // find cells using a specific pid + for (auto i = layout.begin (); i != layout.end (); ++i) { + auto cc = cells_by_pid.find (i->prop_id ()); + if (cc != cells_by_pid.end ()) { + cc->second.push_back (i->cell_index ()); } } // create new property sets for the ones we found - for (std::vector ::const_iterator pid = pids.begin (); pid != pids.end (); ++pid) { + for (auto pid = cells_by_pid.begin (); pid != cells_by_pid.end (); ++pid) { - const db::PropertiesRepository::properties_set &old_set = rep.properties (*pid); + const db::PropertiesRepository::properties_set &old_set = rep.properties (pid->first); db::PropertiesRepository::properties_set new_set; - for (db::PropertiesRepository::properties_set::const_iterator s = old_set.begin (); s != old_set.end (); ++s) { + for (auto s = old_set.begin (); s != old_set.end (); ++s) { if (s->first == pf->second && is_s_gds_property) { // S_GDS_PROPERTY translation @@ -903,7 +923,9 @@ OASISReader::do_read (db::Layout &layout) } else if (s->first == pf->second && is_klayout_context_property) { - if (*pid == layout.prop_id ()) { + auto pid2c = cells_by_pid.find (pid->first); + + if (pid->first == layout.prop_id ()) { // feed context strings from klayout context property if (s->second.is_list ()) { for (auto l = s->second.begin (); l != s->second.end (); ++l) { @@ -912,9 +934,18 @@ OASISReader::do_read (db::Layout &layout) } else { context_properties.push_back (s->second); } - } else { - // TODO: should update that in cells (in case we encounter forward-referenced context properties - // for cells) + } + + // feed cell-specific context strings from klayout context property + for (auto c = pid2c->second.begin (); c != pid2c->second.end (); ++c) { + std::vector &vl = m_context_strings_per_cell [*c]; + if (s->second.is_list ()) { + for (auto l = s->second.begin (); l != s->second.end (); ++l) { + vl.push_back (*l); + } + } else { + vl.push_back (s->second); + } } } else { @@ -922,7 +953,7 @@ OASISReader::do_read (db::Layout &layout) } } - rep.change_properties (*pid, new_set); + rep.change_properties (pid->first, new_set); } @@ -1207,6 +1238,11 @@ OASISReader::do_read (db::Layout &layout) for (auto i = context_properties.begin (); i != context_properties.end (); ++i) { replace_forward_references_in_variant (*i); } + for (auto c = m_context_strings_per_cell.begin (); c != m_context_strings_per_cell.end (); ++c) { + for (auto i = c->second.begin (); i != c->second.end (); ++i) { + replace_forward_references_in_variant (*i); + } + } for (db::PropertiesRepository::non_const_iterator pi = layout.properties_repository ().begin_non_const (); pi != layout.properties_repository ().end_non_const (); ++pi) { for (db::PropertiesRepository::properties_set::iterator ps = pi->second.begin (); ps != pi->second.end (); ++ps) { @@ -1241,15 +1277,22 @@ OASISReader::do_read (db::Layout &layout) // Restore layout meta info if (! context_properties.empty ()) { - std::vector context_strings; - context_strings.reserve (context_properties.size ()); - for (auto s = context_properties.begin (); s != context_properties.end (); ++s) { - context_strings.push_back (s->to_string ()); - } - LayoutOrCellContextInfo info = LayoutOrCellContextInfo::deserialize (context_strings.begin (), context_strings.end ()); + LayoutOrCellContextInfo info = make_context_info (context_properties); layout.fill_meta_info_from_context (info); } + // Restore proxy cell (link to PCell or Library) and cell meta info + if (! m_context_strings_per_cell.empty ()) { + CommonReaderLayerMapping layer_mapping (this, &layout); + for (auto cc = m_context_strings_per_cell.begin (); cc != m_context_strings_per_cell.end (); ++cc) { + LayoutOrCellContextInfo info = make_context_info (cc->second); + if (info.has_proxy_info ()) { + layout.recover_proxy_as (cc->first, info, &layer_mapping); + } + layout.fill_meta_info_from_context (cc->first, info); + } + } + // Check the table offsets vs. real occurrence if (m_first_cellname != 0 && m_first_cellname != m_table_cellname && m_expect_strict_mode == 1) { warn (tl::sprintf (tl::to_string (tr ("CELLNAME table offset does not match first occurrence of CELLNAME in strict mode - %s vs. %s")), m_table_cellname, m_first_cellname)); @@ -3255,7 +3298,7 @@ OASISReader::do_read_cell (db::cell_index_type cell_index, db::Layout &layout) bool xy_absolute = true; bool has_context = false; - std::vector context_strings; + std::vector context_strings; db::PropertiesRepository::properties_set cell_properties; // read next record @@ -3326,7 +3369,7 @@ OASISReader::do_read_cell (db::cell_index_type cell_index, db::Layout &layout) has_context = true; context_strings.reserve (mm_last_value_list.get ().size ()); for (std::vector::const_iterator v = mm_last_value_list.get ().begin (); v != mm_last_value_list.get ().end (); ++v) { - context_strings.push_back (v->to_string ()); + context_strings.push_back (*v); } } else { // store layout properties @@ -3427,14 +3470,9 @@ OASISReader::do_read_cell (db::cell_index_type cell_index, db::Layout &layout) m_instances_with_props.clear (); } - // Restore proxy cell (link to PCell or Library) and cell meta info + // store the context strings for later if (has_context) { - CommonReaderLayerMapping layer_mapping (this, &layout); - LayoutOrCellContextInfo info = LayoutOrCellContextInfo::deserialize (context_strings.begin (), context_strings.end ()); - if (info.has_proxy_info ()) { - layout.recover_proxy_as (cell_index, info, &layer_mapping); - } - layout.fill_meta_info_from_context (cell_index, info); + m_context_strings_per_cell [cell_index].swap (context_strings); } m_cellname = ""; diff --git a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.h b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.h index 78d6b9c41..3e9ee8bf9 100644 --- a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.h +++ b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.h @@ -172,6 +172,8 @@ private: std::map m_propstrings; std::map m_propnames; + std::map > m_context_strings_per_cell; + tl::vector m_instances; tl::vector m_instances_with_props; diff --git a/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.cc b/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.cc index 0af9dbb65..6e54e9bfd 100644 --- a/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.cc +++ b/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.cc @@ -1691,17 +1691,29 @@ OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::Save write_record_id (28); write_byte (char (0xf6)); + unsigned long pnid = 0; std::map ::const_iterator pni = m_propnames.find (klayout_context_name); - tl_assert (pni != m_propnames.end ()); - write (pni->second); + if (pni == m_propnames.end ()) { + pnid = m_propname_id++; + m_propnames.insert (std::make_pair (klayout_context_name, pnid)); + } else { + pnid = pni->second; + } + write (pnid); write ((unsigned long) context_prop_strings.size ()); for (std::vector ::const_iterator c = context_prop_strings.begin (); c != context_prop_strings.end (); ++c) { write_byte (14); // b-string by reference number + unsigned long psid = 0; std::map ::const_iterator psi = m_propstrings.find (*c); - tl_assert (psi != m_propstrings.end ()); - write (psi->second); + if (psi == m_propstrings.end ()) { + psid = m_propstring_id++; + m_propstrings.insert (std::make_pair (*c, psid)).second; + } else { + psid = psi->second; + } + write (psid); } mm_last_property_name = klayout_context_name; diff --git a/src/plugins/streamers/oasis/unit_tests/dbOASISWriterTests.cc b/src/plugins/streamers/oasis/unit_tests/dbOASISWriterTests.cc index dba15c813..ac574affb 100644 --- a/src/plugins/streamers/oasis/unit_tests/dbOASISWriterTests.cc +++ b/src/plugins/streamers/oasis/unit_tests/dbOASISWriterTests.cc @@ -1870,7 +1870,8 @@ TEST(120_IrregularInstRepetitions) } // Meta info -TEST(130) +static void +run_test130 (tl::TestBase *_this, bool strict, bool tables_at_end) { db::Layout layout_org; @@ -1883,12 +1884,16 @@ TEST(130) layout_org.add_meta_info (ci, "a", db::MetaInfo ("dd", true, true)); layout_org.add_meta_info (ci, "c", db::MetaInfo ("d", -1, true)); - std::string tmp_file = tl::TestBase::tmp_file ("tmp_OASISWriter_130.oas"); + std::string tmp_file = _this->tmp_file ("tmp_OASISWriter1.oas"); { tl::OutputStream out (tmp_file); + db::OASISWriterOptions oasis_options; + oasis_options.strict_mode = strict; + oasis_options.tables_at_end = tables_at_end; db::SaveLayoutOptions options; options.set_format ("OASIS"); + options.set_options (oasis_options); db::Writer writer (options); writer.write (layout_org, out); } @@ -1915,12 +1920,16 @@ TEST(130) EXPECT_EQ (layout_read.meta_info (ci2, "c").value.to_string (), "-1"); EXPECT_EQ (layout_read.meta_info (ci2, "c").description, "d"); - tmp_file = tl::TestBase::tmp_file ("tmp_OASISWriter_130b.oas"); + tmp_file = _this->tmp_file ("tmp_OASISWriter2.oas"); { tl::OutputStream out (tmp_file); + db::OASISWriterOptions oasis_options; + oasis_options.strict_mode = strict; + oasis_options.tables_at_end = tables_at_end; db::SaveLayoutOptions options; options.set_format ("OASIS"); + options.set_options (oasis_options); options.set_write_context_info (false); db::Writer writer (options); writer.write (layout_org, out); @@ -1945,3 +1954,25 @@ TEST(130) EXPECT_EQ (layout_read.meta_info ("b").value.to_string (), "nil"); } +// Meta info + +TEST(130a) +{ + run_test130 (_this, false, false); +} + +TEST(130b) +{ + run_test130 (_this, true, false); +} + +TEST(130c) +{ + run_test130 (_this, false, true); +} + +TEST(130d) +{ + run_test130 (_this, true, true); +} +