From 277ab2c33538f798e7772a937db00076f2454eb3 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 30 Jul 2024 00:13:47 +0200 Subject: [PATCH] Refactoring of GDS2 writer - split large functions into smaller ones --- .../gds2/db_plugin/dbGDS2WriterBase.cc | 278 ++++++++++-------- .../gds2/db_plugin/dbGDS2WriterBase.h | 11 + 2 files changed, 164 insertions(+), 125 deletions(-) diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.cc b/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.cc index e679f7689..710262fe3 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.cc +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.cc @@ -44,12 +44,7 @@ namespace db { // ------------------------------------------------------------------ -// GDS2WriterBase implementation - -GDS2WriterBase::GDS2WriterBase () -{ - // .. nothing yet .. -} +// Limit checking conversion functions static int32_t safe_convert_to_int32 (int32_t value) { @@ -155,6 +150,16 @@ static uint16_t safe_convert_to_uint16 (uint64_t value) return uint16_t (value); } +// ------------------------------------------------------------------ +// GDS2WriterBase implementation + +GDS2WriterBase::GDS2WriterBase () + : m_dbu (0.0), m_resolve_skew_arrays (false), m_multi_xy (false), m_no_zero_length_paths (false), + m_max_vertex_count (0), m_write_cell_properties (false), m_keep_instances (false) +{ + // .. nothing yet .. +} + void GDS2WriterBase::write_context_string (size_t n, const std::string &s) { @@ -294,13 +299,135 @@ GDS2WriterBase::write_context_cell (db::Layout &layout, const short *time_data, write_record (sENDSTR); } +void +GDS2WriterBase::write_shape (const db::Layout &layout, int layer, int datatype, const db::Shape &shape, double sf) +{ + if (shape.is_text ()) { + + write_text (layer, datatype, sf, m_dbu, shape, layout, shape.prop_id ()); + + } else if (shape.is_polygon ()) { + + write_polygon (layer, datatype, sf, shape, m_multi_xy, m_max_vertex_count, layout, shape.prop_id ()); + + } else if (shape.is_edge ()) { + + write_edge (layer, datatype, sf, shape, layout, shape.prop_id ()); + + } else if (shape.is_edge_pair ()) { + + write_edge (layer, datatype, sf, shape.edge_pair ().first (), layout, shape.prop_id ()); + write_edge (layer, datatype, sf, shape.edge_pair ().second (), layout, shape.prop_id ()); + + } else if (shape.is_path ()) { + + if (m_no_zero_length_paths && (shape.path_length () - shape.path_extensions ().first - shape.path_extensions ().second) == 0) { + // eliminate the zero-width path + db::Polygon poly; + shape.polygon (poly); + write_polygon (layer, datatype, sf, poly, m_multi_xy, m_max_vertex_count, layout, shape.prop_id (), false); + } else { + write_path (layer, datatype, sf, shape, m_multi_xy, layout, shape.prop_id ()); + } + + } else if (shape.is_box ()) { + + write_box (layer, datatype, sf, shape, layout, shape.prop_id ()); + + } +} + +void +GDS2WriterBase::write_cell (db::Layout &layout, const db::Cell &cref, const std::vector > &layers, const std::set &cell_set, double sf, short *time_data) +{ + // cell header + + write_record_size (4 + 12 * 2); + write_record (sBGNSTR); + write_time (time_data); + write_time (time_data); + + try { + write_string_record (sSTRNAME, m_cell_name_map.cell_name (cref.cell_index ())); + } catch (tl::Exception &ex) { + throw tl::Exception (ex.msg () + tl::to_string (tr (", writing cell name"))); + } + + // cell body + + if (m_write_cell_properties && cref.prop_id () != 0) { + try { + write_properties (layout, cref.prop_id ()); + } catch (tl::Exception &ex) { + throw tl::Exception (ex.msg () + tl::to_string (tr (", writing layout properties"))); + } + } + + // instances + + for (db::Cell::const_iterator inst = cref.begin (); ! inst.at_end (); ++inst) { + + // write only instances to selected cells + if (m_keep_instances || cell_set.find (inst->cell_index ()) != cell_set.end ()) { + + progress_checkpoint (); + try { + write_inst (sf, *inst, true /*normalize*/, m_resolve_skew_arrays, layout, inst->prop_id ()); + } catch (tl::Exception &ex) { + throw tl::Exception (ex.msg () + tl::to_string (tr (", writing instances"))); + } + + } + + } + + // shapes + + for (std::vector >::const_iterator l = layers.begin (); l != layers.end (); ++l) { + + if (layout.is_valid_layer (l->first) && l->second.layer >= 0 && l->second.datatype >= 0) { + + int layer = l->second.layer; + if (layer > std::numeric_limits::max ()) { + throw tl::Exception (tl::sprintf (tl::to_string (tr ("Cannot write layer numbers larger than %d to GDS2 streams")), int (std::numeric_limits::max ()))); + } + int datatype = l->second.datatype; + if (datatype > std::numeric_limits::max ()) { + throw tl::Exception (tl::sprintf (tl::to_string (tr ("Cannot write datatype numbers larger than %d to GDS2 streams")), int (std::numeric_limits::max ()))); + } + + db::ShapeIterator shape (cref.shapes (l->first).begin (db::ShapeIterator::Boxes | db::ShapeIterator::Polygons | db::ShapeIterator::Edges | db::ShapeIterator::EdgePairs | db::ShapeIterator::Paths | db::ShapeIterator::Texts)); + while (! shape.at_end ()) { + + progress_checkpoint (); + + try { + write_shape (layout, layer, datatype, *shape, sf); + } catch (tl::Exception &ex) { + throw tl::Exception (ex.msg () + tl::sprintf (tl::to_string (tr (", writing layer %d/%d")), layer, datatype)); + } + + ++shape; + + } + + } + + } + + // end of cell + + write_record_size (4); + write_record (sENDSTR); +} + void GDS2WriterBase::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLayoutOptions &options) { set_stream (stream); - double dbu = (options.dbu () == 0.0) ? layout.dbu () : options.dbu (); - double sf = options.scale_factor () * (layout.dbu () / dbu); + m_dbu = (options.dbu () == 0.0) ? layout.dbu () : options.dbu (); + double sf = options.scale_factor () * (layout.dbu () / m_dbu); if (fabs (sf - 1.0) < 1e-9) { // to avoid rounding problems, set to 1.0 exactly if possible. sf = 1.0; @@ -308,8 +435,8 @@ GDS2WriterBase::write (db::Layout &layout, tl::OutputStream &stream, const db::S db::GDS2WriterOptions gds2_options = options.get_options (); - layout.add_meta_info ("dbuu", MetaInfo (tl::to_string (tr ("Database unit in user units")), tl::to_string (dbu / std::max (1e-9, gds2_options.user_units)))); - layout.add_meta_info ("dbum", MetaInfo (tl::to_string (tr ("Database unit in meter")), tl::to_string (dbu * 1e-6))); + layout.add_meta_info ("dbuu", MetaInfo (tl::to_string (tr ("Database unit in user units")), tl::to_string (m_dbu / std::max (1e-9, gds2_options.user_units)))); + layout.add_meta_info ("dbum", MetaInfo (tl::to_string (tr ("Database unit in meter")), tl::to_string (m_dbu * 1e-6))); layout.add_meta_info ("libname", MetaInfo (tl::to_string (tr ("Library name")), gds2_options.libname)); std::vector > layers; @@ -348,11 +475,14 @@ GDS2WriterBase::write (db::Layout &layout, tl::OutputStream &stream, const db::S layout.add_meta_info ("mod_time", MetaInfo (tl::to_string (tr ("Modification Time")), str_time)); layout.add_meta_info ("access_time", MetaInfo (tl::to_string (tr ("Access Time")), str_time)); - bool multi_xy = gds2_options.multi_xy_records; + m_keep_instances = options.keep_instances (); + m_multi_xy = gds2_options.multi_xy_records; + m_max_vertex_count = std::max (gds2_options.max_vertex_count, (unsigned int)4); + m_no_zero_length_paths = gds2_options.no_zero_length_paths; + m_resolve_skew_arrays = gds2_options.resolve_skew_arrays; + m_write_cell_properties = gds2_options.write_cell_properties; + size_t max_cellname_length = std::max (gds2_options.max_cellname_length, (unsigned int)8); - size_t max_vertex_count = std::max (gds2_options.max_vertex_count, (unsigned int)4); - bool no_zero_length_paths = gds2_options.no_zero_length_paths; - bool resolve_skew_arrays = gds2_options.resolve_skew_arrays; m_cell_name_map = db::WriterCellNameMap (max_cellname_length); m_cell_name_map.replacement ('$'); @@ -393,8 +523,8 @@ GDS2WriterBase::write (db::Layout &layout, tl::OutputStream &stream, const db::S write_record_size (4 + 8 * 2); write_record (sUNITS); - write_double (dbu / std::max (1e-9, gds2_options.user_units)); - write_double (dbu * 1e-6); + write_double (m_dbu / std::max (1e-9, gds2_options.user_units)); + write_double (m_dbu * 1e-6); // layout properties @@ -433,118 +563,16 @@ GDS2WriterBase::write (db::Layout &layout, tl::OutputStream &stream, const db::S const db::Cell &cref (layout.cell (*cell)); - try { - - // don't write ghost cells unless they are not empty (any more) - // also don't write proxy cells which are not employed - if ((! cref.is_ghost_cell () || ! cref.empty ()) && (! cref.is_proxy () || ! cref.is_top ())) { - - // cell header - - write_record_size (4 + 12 * 2); - write_record (sBGNSTR); - write_time (time_data); - write_time (time_data); - - try { - write_string_record (sSTRNAME, m_cell_name_map.cell_name (*cell)); - } catch (tl::Exception &ex) { - throw tl::Exception (ex.msg () + tl::to_string (tr (", writing cell name"))); - } - - // cell body - - if (gds2_options.write_cell_properties && cref.prop_id () != 0) { - try { - write_properties (layout, cref.prop_id ()); - } catch (tl::Exception &ex) { - throw tl::Exception (ex.msg () + tl::to_string (tr (", writing layout properties"))); - } - } - - // instances - - for (db::Cell::const_iterator inst = cref.begin (); ! inst.at_end (); ++inst) { - - // write only instances to selected cells - if (options.keep_instances () || cell_set.find (inst->cell_index ()) != cell_set.end ()) { - - progress_checkpoint (); - try { - write_inst (sf, *inst, true /*normalize*/, resolve_skew_arrays, layout, inst->prop_id ()); - } catch (tl::Exception &ex) { - throw tl::Exception (ex.msg () + tl::to_string (tr (", writing instances"))); - } - - } - - } - - // shapes - - for (std::vector >::const_iterator l = layers.begin (); l != layers.end (); ++l) { - - if (layout.is_valid_layer (l->first) && l->second.layer >= 0 && l->second.datatype >= 0) { - - int layer = l->second.layer; - if (layer > std::numeric_limits::max ()) { - throw tl::Exception (tl::sprintf (tl::to_string (tr ("Cannot write layer numbers larger than %d to GDS2 streams")), int (std::numeric_limits::max ()))); - } - int datatype = l->second.datatype; - if (datatype > std::numeric_limits::max ()) { - throw tl::Exception (tl::sprintf (tl::to_string (tr ("Cannot write datatype numbers larger than %d to GDS2 streams")), int (std::numeric_limits::max ()))); - } - - try { - - db::ShapeIterator shape (cref.shapes (l->first).begin (db::ShapeIterator::Boxes | db::ShapeIterator::Polygons | db::ShapeIterator::Edges | db::ShapeIterator::EdgePairs | db::ShapeIterator::Paths | db::ShapeIterator::Texts)); - while (! shape.at_end ()) { - - progress_checkpoint (); - - if (shape->is_text ()) { - write_text (layer, datatype, sf, dbu, *shape, layout, shape->prop_id ()); - } else if (shape->is_polygon ()) { - write_polygon (layer, datatype, sf, *shape, multi_xy, max_vertex_count, layout, shape->prop_id ()); - } else if (shape->is_edge ()) { - write_edge (layer, datatype, sf, *shape, layout, shape->prop_id ()); - } else if (shape->is_edge_pair ()) { - write_edge (layer, datatype, sf, shape->edge_pair ().first (), layout, shape->prop_id ()); - write_edge (layer, datatype, sf, shape->edge_pair ().second (), layout, shape->prop_id ()); - } else if (shape->is_path ()) { - if (no_zero_length_paths && (shape->path_length () - shape->path_extensions ().first - shape->path_extensions ().second) == 0) { - // eliminate the zero-width path - db::Polygon poly; - shape->polygon (poly); - write_polygon (layer, datatype, sf, poly, multi_xy, max_vertex_count, layout, shape->prop_id (), false); - } else { - write_path (layer, datatype, sf, *shape, multi_xy, layout, shape->prop_id ()); - } - } else if (shape->is_box ()) { - write_box (layer, datatype, sf, *shape, layout, shape->prop_id ()); - } - - ++shape; - - } - - } catch (tl::Exception &ex) { - throw tl::Exception (ex.msg () + tl::sprintf (tl::to_string (tr (", writing layer %d/%d")), layer, datatype)); - } - - } - - } - - // end of cell - - write_record_size (4); - write_record (sENDSTR); + // don't write ghost cells unless they are not empty (any more) + // also don't write proxy cells which are not employed + if ((! cref.is_ghost_cell () || ! cref.empty ()) && (! cref.is_proxy () || ! cref.is_top ())) { + try { + write_cell (layout, cref, layers, cell_set, sf, time_data); + } catch (tl::Exception &ex) { + throw tl::Exception (ex.msg () + tl::sprintf (tl::to_string (tr (", writing cell '%s'")), layout.cell_name (*cell))); } - } catch (tl::Exception &ex) { - throw tl::Exception (ex.msg () + tl::sprintf (tl::to_string (tr (", writing cell '%s'")), layout.cell_name (*cell))); } } diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.h b/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.h index 0d058e7fe..de1e9fc4b 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.h +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.h @@ -39,6 +39,7 @@ namespace db class Layout; class SaveLayoutOptions; +class GDS2WriterOptions; /** * @brief A GDS2 writer abstraction @@ -166,10 +167,20 @@ protected: private: db::WriterCellNameMap m_cell_name_map; + double m_dbu; + bool m_resolve_skew_arrays; + bool m_multi_xy; + bool m_no_zero_length_paths; + size_t m_max_vertex_count; + bool m_write_cell_properties; + bool m_keep_instances; void write_properties (const db::Layout &layout, db::properties_id_type prop_id); void write_context_cell (db::Layout &layout, const short *time_data, const std::vector &cells); void write_context_string (size_t n, const std::string &s); + void write_cell (db::Layout &layout, const db::Cell &cref, const std::vector > &layers, + const std::set &cell_set, double sf, short *time_data); + void write_shape (const db::Layout &layout, int layer, int datatype, const db::Shape &shape, double sf); }; } // namespace db