Implementing meta data persistency also with strict OASIS and forward references

This commit is contained in:
Matthias Koefferlein 2023-04-20 23:47:47 +02:00
parent bc30887488
commit d1f962a228
4 changed files with 116 additions and 33 deletions

View File

@ -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<tl::Variant> &context_properties)
{
std::vector<std::string> 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 <db::properties_id_type> pids;
for (db::PropertiesRepository::iterator p = rep.begin (); p != rep.end (); ++p) {
std::map<db::properties_id_type, std::vector<db::cell_index_type> > 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<db::cell_index_type> ()));
}
}
// 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 <db::properties_id_type>::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<tl::Variant> &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<std::string> 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 <std::string> context_strings;
std::vector <tl::Variant> 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<tl::Variant>::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 = "";

View File

@ -172,6 +172,8 @@ private:
std::map <unsigned long, std::string> m_propstrings;
std::map <unsigned long, std::string> m_propnames;
std::map <db::cell_index_type, std::vector<tl::Variant> > m_context_strings_per_cell;
tl::vector<db::CellInstArray> m_instances;
tl::vector<db::CellInstArrayWithProperties> m_instances_with_props;

View File

@ -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 <std::string, unsigned long>::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 <std::string>::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 <std::string, unsigned long>::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;

View File

@ -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);
}