From e654ef3012a1f2f178724e43e3d6dc32749007a3 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 22 Feb 2026 19:03:46 +0100 Subject: [PATCH] Experimental: enhance OASIS reader/writer to preserve KLayout's extended property data types (uses S_GDS_PROPERTIES for numerical/string combinations and standard OASIS properties where possible, uses specially annotated strings to store other types) --- .../oasis/db_plugin/dbOASISReader.cc | 65 +++++++--- .../streamers/oasis/db_plugin/dbOASISReader.h | 8 +- .../oasis/db_plugin/dbOASISWriter.cc | 115 +++++++++++------- .../streamers/oasis/db_plugin/dbOASISWriter.h | 5 +- .../oasis/unit_tests/dbOASISWriterTests.cc | 8 +- 5 files changed, 132 insertions(+), 69 deletions(-) diff --git a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc index 1ad137915..3ca4e6ef7 100644 --- a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc +++ b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc @@ -776,13 +776,13 @@ OASISReader::do_read (db::Layout &layout) get (id); } - if (! m_propnames.insert (std::make_pair (id, name)).second) { + if (! m_propnames.insert (std::make_pair (id, make_prop_value (name))).second) { error (tl::sprintf (tl::to_string (tr ("A PROPNAME with id %ld is present already")), id)); } auto fw = m_propname_forward_references.find (id); if (fw != m_propname_forward_references.end ()) { - fw->second = db::property_names_id (name); + fw->second = db::property_names_id (make_prop_value (name)); } reset_modal_variables (); @@ -818,13 +818,13 @@ OASISReader::do_read (db::Layout &layout) get (id); } - if (! m_propstrings.insert (std::make_pair (id, name)).second) { + if (! m_propstrings.insert (std::make_pair (id, make_prop_value (name))).second) { error (tl::sprintf (tl::to_string (tr ("A PROPSTRING with id %ld is present already")), id)); } - std::map::iterator fw = m_propvalue_forward_references.find (id); + auto fw = m_propvalue_forward_references.find (id); if (fw != m_propvalue_forward_references.end ()) { - fw->second = name; + fw->second = db::property_values_id (make_prop_value (name)); } reset_modal_variables (); @@ -1028,6 +1028,13 @@ OASISReader::do_read (db::Layout &layout) } } + // all forward references to property values must be resolved + for (std::map ::const_iterator fw = m_propvalue_forward_references.begin (); fw != m_propvalue_forward_references.end (); ++fw) { + if (fw->second == 0) { + error (tl::sprintf (tl::to_string (tr ("No property string defined for property string id %ld")), fw->first)); + } + } + // Resolve forward references for stored shape and instance prop_ids. // This makes these shape and instance property IDs valid @@ -1216,6 +1223,32 @@ OASISReader::has_forward_refs (const db::PropertiesSet &properties) return false; } +const std::string klayout_prop_string_prefix = "KLAYOUT_VALUE:"; + +tl::Variant +OASISReader::make_prop_value (const std::string &s) +{ + if (strncmp (s.c_str (), klayout_prop_string_prefix.c_str (), klayout_prop_string_prefix.size ()) == 0) { + + tl::Extractor ex (s.c_str () + klayout_prop_string_prefix.size ()); + try { + + tl::Variant v; + ex.read (v); + return v; + + } catch (tl::Exception &) { + + warn (tl::sprintf (tl::to_string (tr ("Unable to decode special value string (%s) - keeping as a string")), s)); + return tl::Variant (s); + + } + + } else { + return tl::Variant (s); + } +} + properties_id_type OASISReader::make_forward_properties_id (const db::PropertiesSet &properties) { // NOTE: the forward properties ID scheme makes use of the fact that IDs @@ -1331,9 +1364,9 @@ OASISReader::replace_forward_references_in_variant (tl::Variant &v) if (v.is_id ()) { uint64_t id = (uint64_t) v.to_id (); - std::map ::const_iterator fw = m_propvalue_forward_references.find (id); + auto fw = m_propvalue_forward_references.find (id); if (fw != m_propvalue_forward_references.end ()) { - v = tl::Variant (fw->second); + v = db::property_value (fw->second); } else { error (tl::sprintf (tl::to_string (tr ("No property value defined for property value id %ld")), id)); } @@ -1355,9 +1388,9 @@ OASISReader::replace_forward_references_in_variant (tl::Variant &v) for (std::vector::iterator ll = new_list.begin (); ll != new_list.end (); ++ll) { if (ll->is_id ()) { uint64_t id = (uint64_t) ll->to_id (); - std::map ::const_iterator fw = m_propvalue_forward_references.find (id); + auto fw = m_propvalue_forward_references.find (id); if (fw != m_propvalue_forward_references.end ()) { - *ll = tl::Variant (fw->second); + *ll = db::property_value (fw->second); } else { error (tl::sprintf (tl::to_string (tr ("No property value defined for property value id %ld")), id)); } @@ -1484,12 +1517,12 @@ OASISReader::read_properties () uint64_t id; get (id); - std::map ::const_iterator cid = m_propnames.find (id); + auto cid = m_propnames.find (id); if (cid == m_propnames.end ()) { mm_last_property_name = db::property_names_id (tl::Variant (id, true /*dummy for id type*/)); m_propname_forward_references.insert (std::make_pair (id, db::property_names_id_type (0))); } else { - mm_last_property_name = db::property_names_id (tl::Variant (cid->second)); + mm_last_property_name = db::property_names_id (cid->second); } } else { @@ -1498,7 +1531,7 @@ OASISReader::read_properties () warn (tl::to_string (tr ("PROPERTY names must be references to PROPNAME ids in strict mode"))); } - mm_last_property_name = db::property_names_id (tl::Variant (get_str ())); + mm_last_property_name = db::property_names_id (make_prop_value (get_str ())); } } @@ -1547,7 +1580,7 @@ OASISReader::read_properties () } if (m_read_properties) { - mm_last_value_list.get_non_const ().push_back (tl::Variant (get_str ())); + mm_last_value_list.get_non_const ().push_back (make_prop_value (get_str ())); } else { get_str (); } @@ -1557,12 +1590,12 @@ OASISReader::read_properties () uint64_t id; get (id); if (m_read_properties) { - std::map ::const_iterator sid = m_propstrings.find (id); + auto sid = m_propstrings.find (id); if (sid == m_propstrings.end ()) { - m_propvalue_forward_references.insert (std::make_pair (id, std::string ())); + m_propvalue_forward_references.insert (std::make_pair (id, db::property_values_id_type (0))); mm_last_value_list.get_non_const ().push_back (tl::Variant (id, true /*dummy for id type*/)); } else { - mm_last_value_list.get_non_const ().push_back (tl::Variant (sid->second)); + mm_last_value_list.get_non_const ().push_back (sid->second); } } diff --git a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.h b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.h index 4420e6c45..32b8430e2 100644 --- a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.h +++ b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.h @@ -166,8 +166,8 @@ private: std::map m_cellname_properties; std::map m_textstrings; std::map m_text_forward_references; - std::map m_propstrings; - std::map m_propnames; + std::map m_propstrings; + std::map m_propnames; std::map > m_context_strings_per_cell; @@ -179,7 +179,7 @@ private: bool m_read_all_properties; std::map m_propname_forward_references; - std::map m_propvalue_forward_references; + std::map m_propvalue_forward_references; std::map > m_forward_properties_for_shapes; std::map > m_forward_properties_for_instances; std::map m_future_cell_properties; @@ -216,6 +216,8 @@ private: void replace_forward_references_in_variant (tl::Variant &v); void extract_context_strings (db::PropertiesSet &properties, std::vector &context_strings); bool has_forward_refs (const db::PropertiesSet &properties); + + tl::Variant make_prop_value (const std::string &s); db::properties_id_type make_forward_properties_id (const db::PropertiesSet &properties); const db::PropertiesSet &forward_properties (db::properties_id_type id) const; bool is_forward_properties_id (db::properties_id_type id) const; diff --git a/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.cc b/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.cc index e7ce59048..bbdca29ce 100644 --- a/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.cc +++ b/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.cc @@ -967,20 +967,35 @@ OASISWriter::write_ucoord (db::Coord c) } } +const std::string klayout_prop_string_prefix = "KLAYOUT_VALUE:"; + +std::string +OASISWriter::make_prop_string (const tl::Variant &v) +{ + if (v.is_a_string ()) { + return v.to_stdstring (); + } else { + return klayout_prop_string_prefix + v.to_parsable_string (); + } +} + void OASISWriter::emit_propname_def (db::properties_id_type prop_id) { - auto props = db::properties (prop_id).to_map (); + auto props = db::properties (prop_id); for (auto p = props.begin (); p != props.end (); ++p) { - const tl::Variant &name = p->first; - const char *name_str = s_gds_property_name; - if (! make_gds_property (name)) { - name_str = name.to_string (); + const tl::Variant &name = db::property_name (p->first); + const tl::Variant &value = db::property_value (p->second); + + std::string name_str (s_gds_property_name); + if (! value.is_a_string () || ! make_gds_property (name)) { + name_str = make_prop_string (name); } + if (m_propnames.insert (std::make_pair (name_str, m_propname_id)).second) { write_record_id (7); - write_nstring (name_str); + write_nstring (name_str.c_str ()); ++m_propname_id; } @@ -992,38 +1007,50 @@ OASISWriter::emit_propstring_def (db::properties_id_type prop_id) { std::vector pv_list; - auto props = db::properties (prop_id).to_map (); + auto props = db::properties (prop_id); for (auto p = props.begin (); p != props.end (); ++p) { pv_list.clear (); const std::vector *pvl = &pv_list; - const tl::Variant &name = p->first; - if (! make_gds_property (name)) { + const tl::Variant &name = db::property_name (p->first); + const tl::Variant &value = db::property_value (p->second); - if (p->second.is_list ()) { - pvl = &p->second.get_list (); - } else if (!p->second.is_nil ()) { + if (! value.is_a_string () || ! make_gds_property (name)) { + + if (value.is_list ()) { + pvl = &value.get_list (); + } else if (!value.is_nil ()) { pv_list.reserve (1); - pv_list.push_back (p->second); + pv_list.push_back (value); + } + + for (std::vector::const_iterator pv = pvl->begin (); pv != pvl->end (); ++pv) { + + if (!pv->is_double () && !pv->is_longlong () && !pv->is_ulonglong () && !pv->is_long () && !pv->is_ulong ()) { + + std::string v = make_prop_string (*pv); + + if (m_propstrings.insert (std::make_pair (v, m_propstring_id)).second) { + write_record_id (9); + write_bstring (v.c_str ()); + ++m_propstring_id; + } + + } + } } else { - pv_list.reserve (2); - pv_list.push_back (name.to_ulong ()); - pv_list.push_back (p->second.to_string ()); + std::string v = make_prop_string (value); - } - - for (std::vector::const_iterator pv = pvl->begin (); pv != pvl->end (); ++pv) { - if (!pv->is_double () && !pv->is_longlong () && !pv->is_ulonglong () && !pv->is_long () && !pv->is_ulong ()) { - if (m_propstrings.insert (std::make_pair (pv->to_string (), m_propstring_id)).second) { - write_record_id (9); - write_bstring (pv->to_string ()); - ++m_propstring_id; - } + if (m_propstrings.insert (std::make_pair (v, m_propstring_id)).second) { + write_record_id (9); + write_bstring (v.c_str ()); + ++m_propstring_id; } + } } @@ -2117,37 +2144,37 @@ OASISWriter::write_props (db::properties_id_type prop_id) { std::vector pv_list; - auto props = db::properties (prop_id).to_map (); - + auto props = db::properties (prop_id); for (auto p = props.begin (); p != props.end (); ++p) { + const tl::Variant &name = db::property_name (p->first); + const tl::Variant &value = db::property_value (p->second); + m_progress.set (mp_stream->pos ()); - const tl::Variant &name = p->first; - - const char *name_str = s_gds_property_name; + std::string name_str (s_gds_property_name); bool sflag = true; pv_list.clear (); const std::vector *pvl = &pv_list; - if (! make_gds_property (name)) { + if (! value.is_a_string () || ! make_gds_property (name)) { - name_str = name.to_string (); + name_str = make_prop_string (name); sflag = false; - if (p->second.is_list ()) { - pvl = &p->second.get_list (); - } else if (!p->second.is_nil ()) { + if (value.is_list ()) { + pvl = &value.get_list (); + } else if (!value.is_nil ()) { pv_list.reserve (1); - pv_list.push_back (p->second); + pv_list.push_back (value); } } else { pv_list.reserve (2); pv_list.push_back (name.to_ulong ()); - pv_list.push_back (p->second.to_string ()); + pv_list.push_back (value); } @@ -2157,7 +2184,7 @@ OASISWriter::write_props (db::properties_id_type prop_id) } void -OASISWriter::write_property_def (const char *name_str, const tl::Variant &pv, bool sflag) +OASISWriter::write_property_def (const std::string &name_str, const tl::Variant &pv, bool sflag) { std::vector pvl; pvl.reserve (1); @@ -2166,7 +2193,7 @@ OASISWriter::write_property_def (const char *name_str, const tl::Variant &pv, bo } void -OASISWriter::write_property_def (const char *name_str, const std::vector &pvl, bool sflag) +OASISWriter::write_property_def (const std::string &name_str, const std::vector &pvl, bool sflag) { bool same_name = (mm_last_property_name == name_str); bool same_value = (mm_last_value_list == pvl); @@ -2203,7 +2230,7 @@ OASISWriter::write_property_def (const char *name_str, const std::vector::const_iterator pvi = m_propstrings.find (pvs); // In strict mode always write property string ID's: before we have issued the table we can @@ -2264,11 +2291,11 @@ OASISWriter::write_property_def (const char *name_str, const std::vectorsecond); } else { - write_byte (10 + string_type (pvs)); - write_bstring (pvs); + write_byte (10 + string_type (pvs.c_str ())); + write_bstring (pvs.c_str ()); } } diff --git a/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.h b/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.h index be28a4527..2263c35a8 100644 --- a/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.h +++ b/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.h @@ -300,6 +300,7 @@ private: void reset_modal_variables (); + static std::string make_prop_string (const tl::Variant &v); void emit_propname_def (db::properties_id_type prop_id); void emit_propstring_def (db::properties_id_type prop_id); void write_insts (const std::set &cell_set); @@ -307,8 +308,8 @@ private: void write_shapes (const db::LayerProperties &lprops, const db::Shapes &shapes); void write_props (db::properties_id_type prop_id); - void write_property_def (const char *name_str, const std::vector &pvl, bool sflag); - void write_property_def (const char *name_str, const tl::Variant &pv, bool sflag); + void write_property_def (const std::string &name_str, const std::vector &pvl, bool sflag); + void write_property_def (const std::string &name_str, const tl::Variant &pv, bool sflag); void write_pointlist (const std::vector &pointlist, bool for_polygons); void write_inst_with_rep (const db::CellInstArray &inst, db::properties_id_type prop_id, const db::Vector &disp, const db::Repetition &rep); diff --git a/src/plugins/streamers/oasis/unit_tests/dbOASISWriterTests.cc b/src/plugins/streamers/oasis/unit_tests/dbOASISWriterTests.cc index e748fe08c..000bb2852 100644 --- a/src/plugins/streamers/oasis/unit_tests/dbOASISWriterTests.cc +++ b/src/plugins/streamers/oasis/unit_tests/dbOASISWriterTests.cc @@ -1533,14 +1533,14 @@ TEST(116) "set props {\n" " {42 {42}}\n" " {{S_BOUNDING_BOX} {(0,0,100,1000,1100)}}\n" - " {{S_CELL_OFFSET} {231}}\n" + " {{S_CELL_OFFSET} {247}}\n" "}\n" "begin_cellp $props {$1}\n" "path 1 0 0 0 0 {0 100} {1000 1200}\n" "end_cell\n" "set props {\n" " {{S_BOUNDING_BOX} {(2,0,0,0,0)}}\n" - " {{S_CELL_OFFSET} {229}}\n" + " {{S_CELL_OFFSET} {245}}\n" "}\n" "begin_cellp $props {$2}\n" "end_cell\n" @@ -1598,13 +1598,13 @@ TEST(116) "begin_libp $props 0.001\n" "set props {\n" " {42 {42}}\n" - " {{S_CELL_OFFSET} {182}}\n" + " {{S_CELL_OFFSET} {198}}\n" "}\n" "begin_cellp $props {$1}\n" "path 1 0 0 0 0 {0 100} {1000 1200}\n" "end_cell\n" "set props {\n" - " {{S_CELL_OFFSET} {180}}\n" + " {{S_CELL_OFFSET} {196}}\n" "}\n" "begin_cellp $props {$2}\n" "end_cell\n"