Refactoring of GDS2 writer - split large functions into smaller ones

This commit is contained in:
Matthias Koefferlein 2024-07-30 00:13:47 +02:00
parent 589a6ce88a
commit 277ab2c335
2 changed files with 164 additions and 125 deletions

View File

@ -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 <std::pair <unsigned int, db::LayerProperties> > &layers, const std::set<db::cell_index_type> &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 <std::pair <unsigned int, db::LayerProperties> >::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<uint16_t>::max ()) {
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Cannot write layer numbers larger than %d to GDS2 streams")), int (std::numeric_limits<uint16_t>::max ())));
}
int datatype = l->second.datatype;
if (datatype > std::numeric_limits<uint16_t>::max ()) {
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Cannot write datatype numbers larger than %d to GDS2 streams")), int (std::numeric_limits<uint16_t>::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<db::GDS2WriterOptions> ();
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 <std::pair <unsigned int, db::LayerProperties> > 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 <std::pair <unsigned int, db::LayerProperties> >::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<uint16_t>::max ()) {
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Cannot write layer numbers larger than %d to GDS2 streams")), int (std::numeric_limits<uint16_t>::max ())));
}
int datatype = l->second.datatype;
if (datatype > std::numeric_limits<uint16_t>::max ()) {
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Cannot write datatype numbers larger than %d to GDS2 streams")), int (std::numeric_limits<uint16_t>::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)));
}
}

View File

@ -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<cell_index_type> &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 <std::pair <unsigned int, db::LayerProperties> > &layers,
const std::set <db::cell_index_type> &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