mirror of https://github.com/KLayout/klayout.git
Implementing meta data persistency also with strict OASIS and forward references
This commit is contained in:
parent
bc30887488
commit
d1f962a228
|
|
@ -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 = "";
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue