diff --git a/src/db/db/dbCommonReader.cc b/src/db/db/dbCommonReader.cc index 64eb1d85f5..e40b886945 100644 --- a/src/db/db/dbCommonReader.cc +++ b/src/db/db/dbCommonReader.cc @@ -160,7 +160,7 @@ CommonReaderBase::rename_cell (db::Layout &layout, size_t id, const std::string // Both cells already exist and are not identical: merge ID-declared cell into the name-declared one layout.force_update (); - merge_cell (layout, iname->second.second, iid->second.second); + merge_cell (layout, iname->second.second, iid->second.second, true); iid->second.second = iname->second.second; } @@ -235,7 +235,7 @@ CommonReaderBase::cell_for_instance (db::Layout &layout, const std::string &cn) } void -CommonReaderBase::merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index) const +CommonReaderBase::merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta) const { const db::Cell &src_cell = layout.cell (src_cell_index); db::Cell &target_cell = layout.cell (target_cell_index); @@ -249,11 +249,11 @@ CommonReaderBase::merge_cell (db::Layout &layout, db::cell_index_type target_cel } } - merge_cell_without_instances (layout, target_cell_index, src_cell_index); + merge_cell_without_instances (layout, target_cell_index, src_cell_index, with_meta); } void -CommonReaderBase::merge_cell_without_instances (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index) const +CommonReaderBase::merge_cell_without_instances (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta) const { const db::Cell &src_cell = layout.cell (src_cell_index); db::Cell &target_cell = layout.cell (target_cell_index); @@ -268,6 +268,16 @@ CommonReaderBase::merge_cell_without_instances (db::Layout &layout, db::cell_ind // replace all instances of the new cell with the original one layout.replace_instances_of (src_cell.cell_index (), target_cell.cell_index ()); + // merge meta info + if (with_meta) { + auto ib = layout.begin_meta (src_cell.cell_index ()); + auto ie = layout.end_meta (src_cell.cell_index ()); + for (auto i = ib; i != ie; ++i) { + layout.add_meta_info (target_cell.cell_index (), i->first, i->second); + } + } + layout.clear_meta (src_cell.cell_index ()); + // finally delete the new cell layout.delete_cell (src_cell.cell_index ()); } @@ -371,7 +381,7 @@ CommonReaderBase::finish (db::Layout &layout) layout.cell (ci_org).clear_shapes (); - merge_cell (layout, ci_org, ci_new); + merge_cell (layout, ci_org, ci_new, true); } else if (m_cc_resolution == SkipNewCell && ! layout.cell (ci_org).is_ghost_cell ()) { @@ -379,11 +389,11 @@ CommonReaderBase::finish (db::Layout &layout) layout.cell (ci_new).clear_shapes (); // NOTE: ignore instances -> this saves us a layout update - merge_cell_without_instances (layout, ci_org, ci_new); + merge_cell_without_instances (layout, ci_org, ci_new, false); } else { - merge_cell (layout, ci_org, ci_new); + merge_cell (layout, ci_org, ci_new, m_cc_resolution != SkipNewCell); } diff --git a/src/db/db/dbCommonReader.h b/src/db/db/dbCommonReader.h index 45afd6cc56..90e98d339a 100644 --- a/src/db/db/dbCommonReader.h +++ b/src/db/db/dbCommonReader.h @@ -242,12 +242,12 @@ class DB_PUBLIC CommonReaderBase /** * @brief Merge (and delete) the src_cell into target_cell */ - void merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index) const; + void merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta) const; /** * @brief Merge (and delete) the src_cell into target_cell without instances */ - void merge_cell_without_instances (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index) const; + void merge_cell_without_instances (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta) const; /** * @brief Gets the layer name map diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index 8ab1e87172..4e29d27efd 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -257,6 +257,83 @@ struct InsertRemoveLayerOp bool m_insert; }; +struct SetLayoutMetaInfoOp + : public LayoutOp +{ + SetLayoutMetaInfoOp (db::Layout::meta_info_name_id_type name_id, const db::MetaInfo *f, const db::MetaInfo *t) + : m_name_id (name_id), m_has_from (f != 0), m_has_to (t != 0) + { + if (f) { + m_from = *f; + } + if (t) { + m_to = *t; + } + } + + virtual void redo (db::Layout *layout) const + { + if (! m_has_to) { + layout->remove_meta_info (m_name_id); + } else { + layout->add_meta_info (m_name_id, m_to); + } + } + + virtual void undo (db::Layout *layout) const + { + if (! m_has_from) { + layout->remove_meta_info (m_name_id); + } else { + layout->add_meta_info (m_name_id, m_from); + } + } + +private: + db::Layout::meta_info_name_id_type m_name_id; + bool m_has_from, m_has_to; + db::MetaInfo m_from, m_to; +}; + +struct SetCellMetaInfoOp + : public LayoutOp +{ + SetCellMetaInfoOp (db::cell_index_type ci, db::Layout::meta_info_name_id_type name_id, const db::MetaInfo *f, const db::MetaInfo *t) + : m_ci (ci), m_name_id (name_id), m_has_from (f != 0), m_has_to (t != 0) + { + if (f) { + m_from = *f; + } + if (t) { + m_to = *t; + } + } + + virtual void redo (db::Layout *layout) const + { + if (! m_has_to) { + layout->remove_meta_info (m_ci, m_name_id); + } else { + layout->add_meta_info (m_ci, m_name_id, m_to); + } + } + + virtual void undo (db::Layout *layout) const + { + if (! m_has_from) { + layout->remove_meta_info (m_ci, m_name_id); + } else { + layout->add_meta_info (m_ci, m_name_id, m_from); + } + } + +private: + db::cell_index_type m_ci; + db::Layout::meta_info_name_id_type m_name_id; + bool m_has_from, m_has_to; + db::MetaInfo m_from, m_to; +}; + // ----------------------------------------------------------------- // Implementation of the ProxyContextInfo class @@ -848,6 +925,9 @@ Layout::delete_cells (const std::set &cells_to_delete) // cell child objects that must remain. for (std::set::const_iterator c = cells_to_delete.begin (); c != cells_to_delete.end (); ++c) { + // supports undo + clear_meta (*c); + if (manager () && manager ()->transacting ()) { // note the "take" method - this takes out the cell @@ -917,9 +997,12 @@ Layout::delete_cell (cell_index_type id) // a backup container for the cell. This is necessary since the ID's within manager are given to // cell child objects that must remain. + // supports undo + clear_meta (id); + if (manager () && manager ()->transacting ()) { - // not the "take" method - this takes out the cell + // note the "take" method - this takes out the cell std::string cn (cell_name (id)); manager ()->queue (this, new NewRemoveCellOp (id, cn, true /*remove*/, take_cell (id))); @@ -1869,18 +1952,36 @@ Layout::meta_info_name_id (const std::string &name) const void Layout::clear_meta () { + if (manager () && manager ()->transacting ()) { + for (auto i = m_meta_info.begin (); i != m_meta_info.end (); ++i) { + manager ()->queue (this, new SetLayoutMetaInfoOp (i->first, &i->second, 0)); + } + } + m_meta_info.clear (); } void Layout::add_meta_info (meta_info_name_id_type name_id, const MetaInfo &i) { + if (manager () && manager ()->transacting ()) { + auto e = m_meta_info.find (name_id); + manager ()->queue (this, new SetLayoutMetaInfoOp (name_id, e != m_meta_info.end () ? &e->second : 0, &i)); + } + m_meta_info[name_id] = i; } void Layout::remove_meta_info (meta_info_name_id_type name_id) { + if (manager () && manager ()->transacting ()) { + auto e = m_meta_info.find (name_id); + if (e != m_meta_info.end ()) { + manager ()->queue (this, new SetLayoutMetaInfoOp (name_id, &e->second, 0)); + } + } + m_meta_info.erase (name_id); } @@ -1901,12 +2002,41 @@ Layout::has_meta_info (meta_info_name_id_type name_id) const void Layout::clear_meta (db::cell_index_type ci) { + if (manager () && manager ()->transacting ()) { + auto ib = begin_meta (ci); + auto ie = end_meta (ci); + for (auto i = ib; i != ie; ++i) { + manager ()->queue (this, new SetCellMetaInfoOp (ci, i->first, &i->second, 0)); + } + } + m_meta_info_by_cell.erase (ci); } +void +Layout::clear_all_meta () +{ + clear_meta (); + while (! m_meta_info_by_cell.empty ()) { + clear_meta (m_meta_info_by_cell.begin ()->first); + } +} + void Layout::add_meta_info (db::cell_index_type ci, meta_info_name_id_type name_id, const MetaInfo &i) { + if (manager () && manager ()->transacting ()) { + const MetaInfo *from = 0; + auto c = m_meta_info_by_cell.find (ci); + if (c != m_meta_info_by_cell.end ()) { + auto e = c->second.find (name_id); + if (e != c->second.end ()) { + from = &e->second; + } + } + manager ()->queue (this, new SetCellMetaInfoOp (ci, name_id, from, &i)); + } + m_meta_info_by_cell[ci][name_id] = i; } @@ -1914,6 +2044,18 @@ void Layout::remove_meta_info (db::cell_index_type ci, meta_info_name_id_type name_id) { auto c = m_meta_info_by_cell.find (ci); + + if (manager () && manager ()->transacting ()) { + const MetaInfo *from = 0; + if (c != m_meta_info_by_cell.end ()) { + auto e = c->second.find (name_id); + if (e != c->second.end ()) { + from = &e->second; + } + } + manager ()->queue (this, new SetCellMetaInfoOp (ci, name_id, from, 0)); + } + if (c != m_meta_info_by_cell.end ()) { c->second.erase (name_id); } @@ -1945,6 +2087,40 @@ Layout::has_meta_info (db::cell_index_type ci, meta_info_name_id_type name_id) c } } +void +Layout::merge_meta_info (const db::Layout &other) +{ + for (auto mi = other.begin_meta (); mi != other.end_meta (); ++mi) { + add_meta_info (other.meta_info_name (mi->first), mi->second); + } +} + +void +Layout::merge_meta_info (db::cell_index_type into_cell, const db::Layout &other, db::cell_index_type other_cell) +{ + auto mi_begin = other.begin_meta (other_cell); + auto mi_end = other.end_meta (other_cell); + for (auto mi = mi_begin; mi != mi_end; ++mi) { + add_meta_info (into_cell, other.meta_info_name (mi->first), mi->second); + } +} + +void +Layout::merge_meta_info (const db::Layout &other, const db::CellMapping &cm) +{ + for (auto i = cm.begin (); i != cm.end (); ++i) { + merge_meta_info (i->second, other, i->first); + } +} + +void +Layout::copy_meta_info (const db::Layout &other, const db::CellMapping &cm) +{ + for (auto i = cm.begin (); i != cm.end (); ++i) { + copy_meta_info (i->second, other, i->first); + } +} + void Layout::swap_layers (unsigned int a, unsigned int b) { diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h index 7d2598da6d..59a4ad19f4 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -1993,6 +1993,11 @@ class DB_PUBLIC Layout */ void clear_meta (db::cell_index_type ci); + /** + * @brief Clears all meta information (cells and layout) + */ + void clear_all_meta (); + /** * @brief Adds meta information for a given cell * The given meta information object is to the meta information list for the given cell. @@ -2021,6 +2026,50 @@ class DB_PUBLIC Layout } } + /** + * @brief Merges meta information from the other layout into self + * This applies to the layout-only meta information. Same keys get overwritten, new ones are added. + */ + void merge_meta_info (const db::Layout &other); + + /** + * @brief Copies meta information from the other layout into self + * This applies to the layout-only meta information. All keys are replaced. + */ + void copy_meta_info (const db::Layout &other) + { + clear_meta (); + merge_meta_info (other); + } + + /** + * @brief Merges meta information from the other cell into the target cell from sel. + * This applies to the cell-specific meta information. Same keys get overwritten, new ones are added. + */ + void merge_meta_info (db::cell_index_type into_cell, const db::Layout &other, db::cell_index_type other_cell); + + /** + * @brief Copies meta information from the other cell into the target cell from sel. + * This applies to the cell-specific meta information. All keys are replaced. + */ + void copy_meta_info (db::cell_index_type into_cell, const db::Layout &other, db::cell_index_type other_cell) + { + clear_meta (into_cell); + merge_meta_info (into_cell, other, other_cell); + } + + /** + * @brief Merges meta information from the other cell into the target cell from sel using the given cell mapping. + * The cell mapping specifies which meta information to merge from which cell into which cell. + */ + void merge_meta_info (const db::Layout &other, const db::CellMapping &cm); + + /** + * @brief Copies meta information from the other cell into the target cell from sel using the given cell mapping. + * The cell mapping specifies which meta information to copy from which cell into which cell. + */ + void copy_meta_info (const db::Layout &other, const db::CellMapping &cm); + /** * @brief Gets a value indicating whether a meta info with the given name is present for the given cell */ diff --git a/src/db/db/dbLayoutDiff.cc b/src/db/db/dbLayoutDiff.cc index bc35d4c62c..b52e71b022 100644 --- a/src/db/db/dbLayoutDiff.cc +++ b/src/db/db/dbLayoutDiff.cc @@ -702,6 +702,29 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout r.dbu_differs (a.dbu (), b.dbu ()); } + if ((flags & layout_diff::f_with_meta) != 0) { + std::map > mi; + for (auto i = a.begin_meta (); i != a.end_meta (); ++i) { + if (i->second.persisted) { + mi [a.meta_info_name (i->first)].first = i->second.value; + } + } + for (auto i = b.begin_meta (); i != b.end_meta (); ++i) { + if (i->second.persisted) { + mi [b.meta_info_name (i->first)].second = i->second.value; + } + } + for (auto i = mi.begin (); i != mi.end (); ++i) { + if (i->second.first != i->second.second) { + differs = true; + if (flags & layout_diff::f_silent) { + return false; + } + r.layout_meta_info_differs (i->first, i->second.first, i->second.second); + } + } + } + bool verbose = (flags & layout_diff::f_verbose); bool no_duplicates = (flags & layout_diff::f_ignore_duplicates); @@ -928,6 +951,33 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout r.begin_cell (common_cells [cci], common_cells_a [cci], common_cells_b [cci]); + if ((flags & layout_diff::f_with_meta) != 0) { + std::map > mi; + auto ib = a.begin_meta (common_cells_a [cci]); + auto ie = a.end_meta (common_cells_a [cci]); + for (auto i = ib; i != ie; ++i) { + if (i->second.persisted) { + mi [a.meta_info_name (i->first)].first = i->second.value; + } + } + ib = b.begin_meta (common_cells_b [cci]); + ie = b.end_meta (common_cells_b [cci]); + for (auto i = ib; i != ie; ++i) { + if (i->second.persisted) { + mi [b.meta_info_name (i->first)].second = i->second.value; + } + } + for (auto i = mi.begin (); i != mi.end (); ++i) { + if (i->second.first != i->second.second) { + differs = true; + if (flags & layout_diff::f_silent) { + return false; + } + r.cell_meta_info_differs (i->first, i->second.first, i->second.second); + } + } + } + if (!verbose && cell_a->bbox () != cell_b->bbox ()) { differs = true; if (flags & layout_diff::f_silent) { @@ -1215,6 +1265,7 @@ class PrintingDifferenceReceiver } void dbu_differs (double dbu_a, double dbu_b); + void layout_meta_info_differs (const std::string &name, const tl::Variant &a, const tl::Variant &b); void layer_in_a_only (const db::LayerProperties &la); void layer_in_b_only (const db::LayerProperties &lb); void layer_name_differs (const db::LayerProperties &la, const db::LayerProperties &lb); @@ -1222,6 +1273,7 @@ class PrintingDifferenceReceiver void cell_in_b_only (const std::string &cellname, db::cell_index_type ci); void cell_name_differs (const std::string &cellname_a, db::cell_index_type cia, const std::string &cellname_b, db::cell_index_type cib); void begin_cell (const std::string &cellname, db::cell_index_type cia, db::cell_index_type cib); + void cell_meta_info_differs (const std::string &name, const tl::Variant &a, const tl::Variant &b); void bbox_differs (const db::Box &ba, const db::Box &bb); void begin_inst_differences (); void instances_in_a (const std::vector &insts_a, const std::vector &cell_names, const db::PropertiesRepository &props); @@ -1384,6 +1436,16 @@ PrintingDifferenceReceiver::dbu_differs (double dbu_a, double dbu_b) } } +void +PrintingDifferenceReceiver::layout_meta_info_differs (const std::string &name, const tl::Variant &a, const tl::Variant &b) +{ + try { + enough (tl::error) << "Global meta info differs - [" << name << "]: " << a << " vs. " << b; + } catch (tl::CancelException &) { + // ignore cancel exceptions + } +} + void PrintingDifferenceReceiver::layer_in_a_only (const db::LayerProperties &la) { @@ -1461,6 +1523,16 @@ PrintingDifferenceReceiver::begin_cell (const std::string &cellname, db::cell_in m_cellname = cellname; } +void +PrintingDifferenceReceiver::cell_meta_info_differs (const std::string &name, const tl::Variant &a, const tl::Variant &b) +{ + try { + enough (tl::error) << "Meta info differs in cell " << m_cellname << " - [" << name << "]: " << a << " vs. " << b; + } catch (tl::CancelException &) { + // ignore cancel exceptions + } +} + void PrintingDifferenceReceiver::begin_inst_differences () { diff --git a/src/db/db/dbLayoutDiff.h b/src/db/db/dbLayoutDiff.h index ce39f5988f..223ddd4f48 100644 --- a/src/db/db/dbLayoutDiff.h +++ b/src/db/db/dbLayoutDiff.h @@ -56,6 +56,9 @@ const unsigned int f_no_text_orientation = 0x02; // Ignore properties const unsigned int f_no_properties = 0x04; +// With meta info +const unsigned int f_with_meta = 0x08; + // Do not compare layer names const unsigned int f_no_layer_names = 0x10; @@ -94,6 +97,7 @@ class DB_PUBLIC DifferenceReceiver virtual ~DifferenceReceiver () { } virtual void dbu_differs (double /*dbu_a*/, double /*dbu_b*/) { } + virtual void layout_meta_info_differs (const std::string & /*name*/, const tl::Variant & /*value_a*/, const tl::Variant & /*value_b*/) { } virtual void layer_in_a_only (const db::LayerProperties & /*la*/) { } virtual void layer_in_b_only (const db::LayerProperties & /*lb*/) { } virtual void layer_name_differs (const db::LayerProperties & /*la*/, const db::LayerProperties & /*lb*/) { } @@ -102,6 +106,7 @@ class DB_PUBLIC DifferenceReceiver virtual void cell_in_b_only (const std::string & /*cellname*/, db::cell_index_type /*ci*/) { } virtual void bbox_differs (const db::Box & /*ba*/, const db::Box & /*bb*/) { } virtual void begin_cell (const std::string & /*cellname*/, db::cell_index_type /*cia*/, db::cell_index_type /*cib*/) { } + virtual void cell_meta_info_differs (const std::string & /*name*/, const tl::Variant & /*value_a*/, const tl::Variant & /*value_b*/) { } virtual void begin_inst_differences () { } virtual void instances_in_a (const std::vector & /*insts_a*/, const std::vector & /*cell_names*/, const db::PropertiesRepository & /*props*/) { } virtual void instances_in_b (const std::vector & /*insts_b*/, const std::vector & /*cell_names*/, const db::PropertiesRepository & /*props*/) { } diff --git a/src/db/db/dbLayoutUtils.cc b/src/db/db/dbLayoutUtils.cc index 1c4a7e0d10..2fe5174fbb 100644 --- a/src/db/db/dbLayoutUtils.cc +++ b/src/db/db/dbLayoutUtils.cc @@ -252,6 +252,9 @@ merge_layouts (db::Layout &target, const db::Cell &source_cell = source.cell (*c); db::Cell &target_cell = target.cell (target_cell_index); + // merge meta info + target.merge_meta_info (target_cell_index, source, *c); + // NOTE: this implementation employs the safe but cumbersome "local transformation" feature. // This means, all cells are transformed according to the given transformation and their // references are transformed to account for that effect. This will lead to somewhat strange diff --git a/src/db/db/dbTestSupport.cc b/src/db/db/dbTestSupport.cc index c93757909f..871e663968 100644 --- a/src/db/db/dbTestSupport.cc +++ b/src/db/db/dbTestSupport.cc @@ -139,6 +139,7 @@ void compare_layouts (tl::TestBase *_this, const db::Layout &layout, const std:: (n > 0 ? db::layout_diff::f_silent : db::layout_diff::f_verbose) | ((norm & AsPolygons) != 0 ? db::layout_diff::f_boxes_as_polygons + db::layout_diff::f_paths_as_polygons : 0) | ((norm & WithArrays) != 0 ? 0 : db::layout_diff::f_flatten_array_insts) + | ((norm & WithMeta) == 0 ? 0 : db::layout_diff::f_with_meta) /*| db::layout_diff::f_no_text_details | db::layout_diff::f_no_text_orientation*/ , tolerance, 100 /*max diff lines*/); if (equal && n > 0) { diff --git a/src/db/db/dbTestSupport.h b/src/db/db/dbTestSupport.h index 4963b2ec4a..5369a6e90f 100644 --- a/src/db/db/dbTestSupport.h +++ b/src/db/db/dbTestSupport.h @@ -58,7 +58,8 @@ enum NormalizationMode NormFileMask = 7, // bits the extract for file mode NoContext = 8, // write tmp file without context AsPolygons = 16, // paths and boxes are treated as polygons - WithArrays = 32 // do not flatten arrays + WithArrays = 32, // do not flatten arrays + WithMeta = 64 // with meta info }; /** diff --git a/src/db/db/gsiDeclDbCell.cc b/src/db/db/gsiDeclDbCell.cc index 4a65a4a91a..fc32fa381d 100644 --- a/src/db/db/gsiDeclDbCell.cc +++ b/src/db/db/gsiDeclDbCell.cc @@ -1004,6 +1004,22 @@ static void cell_add_meta_info (db::Cell *cell, const MetaInfo &mi) } } +static void cell_merge_meta_info (db::Cell *cell, const db::Cell *source) +{ + if (! source || ! cell->layout () || ! source->layout ()) { + return; + } + cell->layout ()->merge_meta_info (cell->cell_index (), *source->layout (), source->cell_index ()); +} + +static void cell_copy_meta_info (db::Cell *cell, const db::Cell *source) +{ + if (! source || ! cell->layout () || ! source->layout ()) { + return; + } + cell->layout ()->copy_meta_info (cell->cell_index (), *source->layout (), source->cell_index ()); +} + static const tl::Variant &cell_meta_info_value (db::Cell *cell, const std::string &name) { if (! cell->layout ()) { @@ -1755,6 +1771,7 @@ read_options (db::Cell *cell, const std::string &path, const db::LoadLayoutOptio db::CellMapping cm; std::vector new_cells = cm.create_single_mapping_full (*cell->layout (), cell->cell_index (), tmp, *tmp.begin_top_down ()); cell->move_tree_shapes (tmp.cell (*tmp.begin_top_down ()), cm); + cell->layout ()->merge_meta_info (tmp, cm); return new_cells; } @@ -1834,6 +1851,21 @@ Class decl_Cell ("db", "Cell", "\n" "This method has been introduced in version 0.28.8." ) + + gsi::method_ext ("merge_meta_info", &cell_merge_meta_info, gsi::arg ("other"), + "@brief Merges the meta information from the other cell into this cell\n" + "See \\LayoutMetaInfo for details about cells and meta information.\n" + "Existing keys in this cell will be overwritten by the respective values from the other cell.\n" + "New keys will be added.\n" + "\n" + "This method has been introduced in version 0.28.16." + ) + + gsi::method_ext ("copy_meta_info", &cell_copy_meta_info, gsi::arg ("other"), + "@brief Copies the meta information from the other cell into this cell\n" + "See \\LayoutMetaInfo for details about cells and meta information.\n" + "The meta information from this cell will be replaced by the meta information from the other cell.\n" + "\n" + "This method has been introduced in version 0.28.16." + ) + gsi::method_ext ("clear_meta_info", &cell_clear_meta_info, "@brief Clears the meta information of the cell\n" "See \\LayoutMetaInfo for details about cells and meta information.\n" diff --git a/src/db/db/gsiDeclDbLayout.cc b/src/db/db/gsiDeclDbLayout.cc index d85fe36873..db8c78233d 100644 --- a/src/db/db/gsiDeclDbLayout.cc +++ b/src/db/db/gsiDeclDbLayout.cc @@ -1105,12 +1105,54 @@ Class decl_Layout ("db", "Layout", "\n" "This method has been introduced in version 0.25." ) + + gsi::method ("merge_meta_info", static_cast (&db::Layout::merge_meta_info), gsi::arg ("other"), + "@brief Merges the meta information from the other layout into this layout\n" + "See \\LayoutMetaInfo for details about cells and meta information.\n" + "Existing keys in this layout will be overwritten by the respective values from the other layout.\n" + "New keys will be added.\n" + "\n" + "This method has been introduced in version 0.28.16." + ) + + gsi::method ("merge_meta_info", static_cast (&db::Layout::merge_meta_info), gsi::arg ("other"), gsi::arg ("cm"), + "@brief Merges the meta information from the other layout into this layout for the cells given by the cell mapping\n" + "See \\LayoutMetaInfo for details about cells and meta information.\n" + "This method will use the source/target cell pairs from the cell mapping object and merge the meta information " + "from each source cell from the 'other' layout into the mapped cell inside self.\n" + "This method can be used with '\\copy_tree_shapes' and similar to copy meta information in addition to the shapes.\n" + "Existing cell-specific keys in this layout will be overwritten by the respective values from the other layout.\n" + "New keys will be added.\n" + "\n" + "This method has been introduced in version 0.28.16." + ) + + gsi::method ("copy_meta_info", static_cast (&db::Layout::copy_meta_info), gsi::arg ("other"), + "@brief Copies the meta information from the other layout into this layout\n" + "See \\LayoutMetaInfo for details about cells and meta information.\n" + "The meta information from this layout will be replaced by the meta information from the other layout.\n" + "\n" + "This method has been introduced in version 0.28.16." + ) + + gsi::method ("copy_meta_info", static_cast (&db::Layout::copy_meta_info), gsi::arg ("other"), gsi::arg ("cm"), + "@brief Copies the meta information from the other layout into this layout for the cells given by the cell mapping\n" + "See \\LayoutMetaInfo for details about cells and meta information.\n" + "This method will use the source/target cell pairs from the cell mapping object and merge the meta information " + "from each source cell from the 'other' layout into the mapped cell inside self.\n" + "This method can be used with '\\copy_tree_shapes' and similar to copy meta information in addition to the shapes.\n" + "All cell-specific keys in this layout will be replaced by the respective values from the other layout.\n" + "\n" + "This method has been introduced in version 0.28.16." + ) + gsi::method ("clear_meta_info", static_cast (&db::Layout::clear_meta), "@brief Clears the meta information of the layout\n" "See \\LayoutMetaInfo for details about layouts and meta information." "\n" "This method has been introduced in version 0.28.8." ) + + gsi::method ("clear_all_meta_info", static_cast (&db::Layout::clear_all_meta), + "@brief Clears all meta information of the layout (cell specific and global)\n" + "See \\LayoutMetaInfo for details about layouts and meta information." + "\n" + "This method has been introduced in version 0.28.16." + ) + gsi::method ("remove_meta_info", static_cast (&db::Layout::remove_meta_info), gsi::arg ("name"), "@brief Removes meta information from the layout\n" "See \\LayoutMetaInfo for details about layouts and meta information." diff --git a/src/db/db/gsiDeclDbLayoutDiff.cc b/src/db/db/gsiDeclDbLayoutDiff.cc index 84ac3217e1..3e80987508 100644 --- a/src/db/db/gsiDeclDbLayoutDiff.cc +++ b/src/db/db/gsiDeclDbLayoutDiff.cc @@ -90,6 +90,11 @@ class LayoutDiff dbu_differs_event (dbu_a, dbu_b); } + virtual void layout_meta_info_differs (const std::string &name, const tl::Variant &value_a, const tl::Variant &value_b) + { + layout_meta_info_differs_event (name, value_a, value_b); + } + virtual void layer_in_a_only (const db::LayerProperties &la) { layer_in_a_only_event (la); @@ -132,6 +137,11 @@ class LayoutDiff begin_cell_event (mp_cell_a, mp_cell_b); } + virtual void cell_meta_info_differs (const std::string &name, const tl::Variant &value_a, const tl::Variant &value_b) + { + cell_meta_info_differs_event (name, value_a, value_b); + } + virtual void begin_inst_differences () { begin_inst_differences_event (); @@ -343,6 +353,7 @@ class LayoutDiff } tl::event dbu_differs_event; + tl::event layout_meta_info_differs_event; tl::event layer_in_a_only_event; tl::event layer_in_b_only_event; tl::event layer_name_differs_event; @@ -351,6 +362,7 @@ class LayoutDiff tl::event cell_in_b_only_event; tl::event bbox_differs_event; tl::event begin_cell_event; + tl::event cell_meta_info_differs_event; tl::Event begin_inst_differences_event; tl::event instance_in_a_only_event; tl::event instance_in_b_only_event; @@ -409,6 +421,10 @@ static unsigned int f_no_properties () { return db::layout_diff::f_no_properties; } +static unsigned int f_with_meta () { + return db::layout_diff::f_with_meta; +} + static unsigned int f_no_layer_names () { return db::layout_diff::f_no_layer_names; } @@ -450,7 +466,7 @@ gsi::Class decl_LayoutDiff ("db", "LayoutDiff", "full compare.\n" "\n" "This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be " - "compared with other constants to form a flag set." + "combined with other constants to form a flag set." ) + gsi::constant ("IgnoreDuplicates", &f_ignore_duplicates, "@brief Ignore duplicate instances or shapes\n" @@ -462,17 +478,25 @@ gsi::Class decl_LayoutDiff ("db", "LayoutDiff", gsi::constant ("NoTextOrientation", &f_no_text_orientation, "@brief Ignore text orientation\n" "This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be " - "compared with other constants to form a flag set." + "combined with other constants to form a flag set." ) + gsi::constant ("NoProperties", &f_no_properties, "@brief Ignore properties\n" "This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be " - "compared with other constants to form a flag set." + "combined with other constants to form a flag set." + ) + + gsi::constant ("WithMetaInfo", &f_with_meta, + "@brief Ignore meta info\n" + "This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be " + "combined with other constants to form a flag set. If present, this option tells the compare algorithm " + "to include persisted meta info in the compare.\n" + "\n" + "This flag has been introduced in version 0.28.16." ) + gsi::constant ("NoLayerNames", &f_no_layer_names, "@brief Do not compare layer names\n" "This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be " - "compared with other constants to form a flag set." + "combined with other constants to form a flag set." ) + gsi::constant ("Verbose", &f_verbose, "@brief Enables verbose mode (gives details about the differences)\n" @@ -480,22 +504,22 @@ gsi::Class decl_LayoutDiff ("db", "LayoutDiff", "See the event descriptions for details about the differences in verbose and non-verbose mode.\n" "\n" "This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be " - "compared with other constants to form a flag set." + "combined with other constants to form a flag set." ) + gsi::constant ("BoxesAsPolygons", &f_boxes_as_polygons, "@brief Compare boxes to polygons\n" "This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be " - "compared with other constants to form a flag set." + "combined with other constants to form a flag set." ) + gsi::constant ("FlattenArrayInsts", &f_flatten_array_insts, "@brief Compare array instances instance by instance\n" "This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be " - "compared with other constants to form a flag set." + "combined with other constants to form a flag set." ) + gsi::constant ("PathsAsPolygons", &f_paths_as_polygons, "@brief Compare paths to polygons\n" "This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be " - "compared with other constants to form a flag set." + "combined with other constants to form a flag set." ) + gsi::constant ("SmartCellMapping", &f_smart_cell_mapping, "@brief Derive smart cell mapping instead of name mapping (available only if top cells are specified)\n" @@ -503,7 +527,7 @@ gsi::Class decl_LayoutDiff ("db", "LayoutDiff", "cells are compared (with \\LayoutDiff#compare with cells instead of layout objects).\n" "\n" "This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be " - "compared with other constants to form a flag set.\n" + "combined with other constants to form a flag set.\n" ) + gsi::constant ("DontSummarizeMissingLayers", &f_dont_summarize_missing_layers, "@brief Don't summarize missing layers\n" @@ -511,12 +535,12 @@ gsi::Class decl_LayoutDiff ("db", "LayoutDiff", "layer will be reported as difference.\n" "\n" "This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be " - "compared with other constants to form a flag set." + "combined with other constants to form a flag set." ) + gsi::constant ("NoTextDetails", &f_no_text_details, "@brief Ignore text details (font, size, presentation)\n" "This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be " - "compared with other constants to form a flag set." + "combined with other constants to form a flag set." ) + gsi::method ("compare", &LayoutDiff::compare_layouts, gsi::arg("a"), @@ -593,6 +617,14 @@ gsi::Class decl_LayoutDiff ("db", "LayoutDiff", gsi::event ("on_dbu_differs", &LayoutDiff::dbu_differs_event, gsi::arg ("dbu_a"), gsi::arg ("dbu_b"), "@brief This signal indicates a difference in the database units of the layouts\n" ) + + gsi::event ("on_layout_meta_info_differs", &LayoutDiff::layout_meta_info_differs_event, gsi::arg ("name"), gsi::arg ("a"), gsi::arg ("b"), + "@brief This signal indicates that global meta info differs\n" + "Meta information is only compared when \\WithMetaInfo is added to the compare flags.\n" + "'a' and 'b' are the values for the first and second layout. 'nil' is passed to these values to indicate " + "missing meta information on one side.\n" + "\n" + "This event has been added in version 0.28.16." + ) + gsi::event ("on_layer_in_a_only", &LayoutDiff::layer_in_a_only_event, gsi::arg ("a"), "@brief This signal indicates a layer that is present only in the first layout\n" ) + @@ -619,9 +651,17 @@ gsi::Class decl_LayoutDiff ("db", "LayoutDiff", "In verbose mode detailed events will be issued indicating the differences.\n" ) + gsi::event ("on_begin_cell", &LayoutDiff::begin_cell_event, gsi::arg ("ca"), gsi::arg ("cb"), - "@brief This signal initiates the sequence of events for a cell pair\n" + "@brief This signal indicates the sequence of events for a cell pair\n" "All cell specific events happen between \\begin_cell_event and \\end_cell_event signals." ) + + gsi::event ("on_cell_meta_info_differs", &LayoutDiff::cell_meta_info_differs_event, gsi::arg ("name"), gsi::arg ("a"), gsi::arg ("b"), + "@brief This signal indicates that meta info between the current cells differs\n" + "Meta information is only compared when \\WithMetaInfo is added to the compare flags.\n" + "'a' and 'b' are the values for the first and second layout. 'nil' is passed to these values to indicate " + "missing meta information on one side.\n" + "\n" + "This event has been added in version 0.28.16." + ) + gsi::event ("on_begin_inst_differences", &LayoutDiff::begin_inst_differences_event, "@brief This signal indicates differences in the cell instances\n" "In verbose mode (see \\Verbose) more events will follow that indicate the instances that are present only " diff --git a/src/db/unit_tests/dbLayoutDiffTests.cc b/src/db/unit_tests/dbLayoutDiffTests.cc index 87ef5f1bae..6fb0d413b2 100644 --- a/src/db/unit_tests/dbLayoutDiffTests.cc +++ b/src/db/unit_tests/dbLayoutDiffTests.cc @@ -38,6 +38,7 @@ class TestDifferenceReceiver std::string text () const { return m_os.str (); } void clear () { m_os.str (std::string ()); } void dbu_differs (double dbu_a, double dbu_b); + void layout_meta_info_differs (const std::string &, const tl::Variant &, const tl::Variant &); void layer_in_a_only (const db::LayerProperties &la); void layer_in_b_only (const db::LayerProperties &lb); void layer_name_differs (const db::LayerProperties &la, const db::LayerProperties &lb); @@ -45,6 +46,7 @@ class TestDifferenceReceiver void cell_in_b_only (const std::string &cellname, db::cell_index_type ci); void cell_name_differs (const std::string &cellname_a, db::cell_index_type cia, const std::string &cellname_b, db::cell_index_type cib); void begin_cell (const std::string &cellname, db::cell_index_type cia, db::cell_index_type cib); + void cell_meta_info_differs (const std::string &, const tl::Variant &, const tl::Variant &); void bbox_differs (const db::Box &ba, const db::Box &bb); void begin_inst_differences (); void instances_in_a (const std::vector &insts_a, const std::vector &cell_names, const db::PropertiesRepository &props); @@ -155,6 +157,12 @@ TestDifferenceReceiver::dbu_differs (double dbu_a, double dbu_b) m_os << "layout_diff: database units differ " << dbu_a << " vs. " << dbu_b << std::endl; } +void +TestDifferenceReceiver::layout_meta_info_differs (const std::string &name, const tl::Variant &va, const tl::Variant &vb) +{ + m_os << "layout_diff: global meta info differs " << name << ": " << va.to_string () << " vs. " << vb.to_string () << std::endl; +} + void TestDifferenceReceiver::layer_in_a_only (const db::LayerProperties &la) { @@ -204,6 +212,12 @@ TestDifferenceReceiver::begin_cell (const std::string &cellname, db::cell_index_ m_cellname = cellname; } +void +TestDifferenceReceiver::cell_meta_info_differs (const std::string &name, const tl::Variant &va, const tl::Variant &vb) +{ + m_os << "layout_diff: cell meta info differs for cell " << m_cellname << " - " << name << ": " << va.to_string () << " vs. " << vb.to_string () << std::endl; +} + void TestDifferenceReceiver::begin_inst_differences () { @@ -1704,4 +1718,46 @@ TEST(8) ); } +// meta info +TEST(9) +{ + db::Layout a; + db::cell_index_type caa = a.add_cell ("A"); + db::cell_index_type cab = a.add_cell ("B"); + + db::Layout b; + db::cell_index_type cba = b.add_cell ("A"); + db::cell_index_type cbb = b.add_cell ("B"); + + a.add_meta_info ("x", db::MetaInfo ("", 17.0, true)); + a.add_meta_info ("y", db::MetaInfo ("", -1.0, false)); // not persisted + a.add_meta_info ("z", db::MetaInfo ("", -1.0, true)); + a.add_meta_info (caa, "a1", db::MetaInfo ("", "a", true)); + a.add_meta_info (caa, "a2", db::MetaInfo ("", 42, false)); // not persisted + a.add_meta_info (caa, "a3", db::MetaInfo ("", 41, true)); + a.add_meta_info (cab, "b1", db::MetaInfo ("", "b", true)); + a.add_meta_info (cab, "b2", db::MetaInfo ("", 3, false)); // not persisted + a.add_meta_info (cab, "b3", db::MetaInfo ("", "q", true)); + + b.add_meta_info ("x", db::MetaInfo ("", 21.0, true)); + b.add_meta_info ("y", db::MetaInfo ("", -1.0, true)); + b.add_meta_info (cba, "a1", db::MetaInfo ("", "aa", true)); + b.add_meta_info (cba, "a2", db::MetaInfo ("", 42, true)); + b.add_meta_info (cbb, "b1", db::MetaInfo ("", "bb", true)); + b.add_meta_info (cbb, "b2", db::MetaInfo ("", 3, true)); + TestDifferenceReceiver r; + bool eq = db::compare_layouts (a, b, db::layout_diff::f_verbose | db::layout_diff::f_with_meta, 0, r); + EXPECT_EQ (eq, false); + EXPECT_EQ (r.text (), + "layout_diff: global meta info differs x: 17 vs. 21\n" + "layout_diff: global meta info differs y: nil vs. -1\n" + "layout_diff: global meta info differs z: -1 vs. nil\n" + "layout_diff: cell meta info differs for cell A - a1: a vs. aa\n" + "layout_diff: cell meta info differs for cell A - a2: nil vs. 42\n" + "layout_diff: cell meta info differs for cell A - a3: 41 vs. nil\n" + "layout_diff: cell meta info differs for cell B - b1: b vs. bb\n" + "layout_diff: cell meta info differs for cell B - b2: nil vs. 3\n" + "layout_diff: cell meta info differs for cell B - b3: q vs. nil\n" + ); +} diff --git a/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc b/src/plugins/streamers/gds2/unit_tests/dbGDS2ReaderTests.cc similarity index 98% rename from src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc rename to src/plugins/streamers/gds2/unit_tests/dbGDS2ReaderTests.cc index 4e3774736b..c503bab0aa 100644 --- a/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc +++ b/src/plugins/streamers/gds2/unit_tests/dbGDS2ReaderTests.cc @@ -538,7 +538,7 @@ TEST(4_CollectModeRename) } std::string fn_au (tl::testdata () + "/gds/collect_rename_au.gds"); - db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1); + db::compare_layouts (_this, layout, fn_au, db::NormalizationMode (db::WriteGDS2 | db::WithMeta), 1); } TEST(4_CollectModeRenameWithGhost) @@ -634,7 +634,7 @@ TEST(4_CollectModeOverwrite) } std::string fn_au (tl::testdata () + "/gds/collect_overwrite_au.gds"); - db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1); + db::compare_layouts (_this, layout, fn_au, db::NormalizationMode (db::WriteGDS2 | db::WithMeta), 1); } TEST(4_CollectModeSkip) @@ -658,7 +658,7 @@ TEST(4_CollectModeSkip) } std::string fn_au (tl::testdata () + "/gds/collect_skip_au.gds"); - db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1); + db::compare_layouts (_this, layout, fn_au, db::NormalizationMode (db::WriteGDS2 | db::WithMeta), 1); } TEST(4_CollectModeAdd) @@ -682,7 +682,7 @@ TEST(4_CollectModeAdd) } std::string fn_au (tl::testdata () + "/gds/collect_add_au.gds"); - db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1); + db::compare_layouts (_this, layout, fn_au, db::NormalizationMode (db::WriteGDS2 | db::WithMeta), 1); } // border case with multiple padding 0 for SNAME and STRING records diff --git a/src/plugins/streamers/gds2/unit_tests/dbGDS2Writer.cc b/src/plugins/streamers/gds2/unit_tests/dbGDS2WriterTests.cc similarity index 100% rename from src/plugins/streamers/gds2/unit_tests/dbGDS2Writer.cc rename to src/plugins/streamers/gds2/unit_tests/dbGDS2WriterTests.cc diff --git a/src/plugins/streamers/gds2/unit_tests/unit_tests.pro b/src/plugins/streamers/gds2/unit_tests/unit_tests.pro index cc5d39a619..396a6273ed 100644 --- a/src/plugins/streamers/gds2/unit_tests/unit_tests.pro +++ b/src/plugins/streamers/gds2/unit_tests/unit_tests.pro @@ -6,8 +6,8 @@ TARGET = gds2_tests include($$PWD/../../../../lib_ut.pri) SOURCES = \ - dbGDS2Reader.cc \ - dbGDS2Writer.cc \ + dbGDS2ReaderTests.cc \ + dbGDS2WriterTests.cc INCLUDEPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common DEPENDPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common diff --git a/testdata/gds/collect_add_au.gds b/testdata/gds/collect_add_au.gds index ca0206610f..ec52fb2068 100644 Binary files a/testdata/gds/collect_add_au.gds and b/testdata/gds/collect_add_au.gds differ diff --git a/testdata/gds/collect_added.gds b/testdata/gds/collect_added.gds index e4882b6d83..2e366a6a0f 100644 Binary files a/testdata/gds/collect_added.gds and b/testdata/gds/collect_added.gds differ diff --git a/testdata/gds/collect_basic.gds b/testdata/gds/collect_basic.gds index 9fad7517e9..b9c8c7e63d 100644 Binary files a/testdata/gds/collect_basic.gds and b/testdata/gds/collect_basic.gds differ diff --git a/testdata/gds/collect_overwrite_au.gds b/testdata/gds/collect_overwrite_au.gds index e4790a23d6..b77fbcde91 100644 Binary files a/testdata/gds/collect_overwrite_au.gds and b/testdata/gds/collect_overwrite_au.gds differ diff --git a/testdata/gds/collect_rename_au.gds b/testdata/gds/collect_rename_au.gds index af98c817f9..f66ca2fde9 100644 Binary files a/testdata/gds/collect_rename_au.gds and b/testdata/gds/collect_rename_au.gds differ diff --git a/testdata/gds/collect_skip_au.gds b/testdata/gds/collect_skip_au.gds index 5a0b96fa91..7b77e88e0f 100644 Binary files a/testdata/gds/collect_skip_au.gds and b/testdata/gds/collect_skip_au.gds differ diff --git a/testdata/ruby/dbLayoutTests2.rb b/testdata/ruby/dbLayoutTests2.rb index b5dbb9a50a..bf53496459 100644 --- a/testdata/ruby/dbLayoutTests2.rb +++ b/testdata/ruby/dbLayoutTests2.rb @@ -23,6 +23,10 @@ load("test_prologue.rb") +def mi2s(obj) + obj.each_meta_info.collect { |mi| mi.name + ":" + mi.value.to_s }.sort.join(";") +end + class DBLayoutTests2_TestClass < TestBase # LayerInfo @@ -1253,6 +1257,175 @@ def test_15 end + # Cell#read and meta info (issue #1609) + def test_16 + + tmp = File::join($ut_testtmp, "test16.gds") + + ly1 = RBA::Layout::new + a = ly1.create_cell("A") + b = ly1.create_cell("B") + a.insert(RBA::DCellInstArray::new(b, RBA::Trans::new)) + + a.add_meta_info(RBA::LayoutMetaInfo::new("am1", 42.0, "", true)) + a.add_meta_info(RBA::LayoutMetaInfo::new("am2", "u", "", true)) + assert_equal(mi2s(a), "am1:42.0;am2:u") + + b.add_meta_info(RBA::LayoutMetaInfo::new("bm1", 17, "", true)) + assert_equal(mi2s(b), "bm1:17") + + ly1.add_meta_info(RBA::LayoutMetaInfo::new("lm1", -2.0, "", true)) + ly1.add_meta_info(RBA::LayoutMetaInfo::new("lm2", "v", "", true)) + assert_equal(mi2s(ly1), "lm1:-2.0;lm2:v") + + ly1.write(tmp) + + ly2 = RBA::Layout::new + top = ly2.create_cell("TOP") + a = ly2.create_cell("A") + c = ly2.create_cell("C") + top.insert(RBA::DCellInstArray::new(a, RBA::Trans::new)) + a.insert(RBA::DCellInstArray::new(c, RBA::Trans::new)) + + top.add_meta_info(RBA::LayoutMetaInfo::new("topm1", "abc")) + assert_equal(mi2s(top), "topm1:abc") + a.add_meta_info(RBA::LayoutMetaInfo::new("am1", "a number")) + a.add_meta_info(RBA::LayoutMetaInfo::new("am3", 0)) + assert_equal(mi2s(a), "am1:a number;am3:0") + c.add_meta_info(RBA::LayoutMetaInfo::new("cm1", 3)) + assert_equal(mi2s(c), "cm1:3") + + ly2.add_meta_info(RBA::LayoutMetaInfo::new("lm1", 5)) + assert_equal(mi2s(ly2), "lm1:5") + + a.read(tmp) + # not modified + assert_equal(mi2s(ly2), "lm1:5") + # merged + assert_equal(mi2s(a), "am1:42.0;am2:u;am3:0") + # not modified + assert_equal(mi2s(c), "cm1:3") + + b2 = ly2.cell("B") + # imported + assert_equal(mi2s(b2), "bm1:17") + + puts "done." + + end + + # Layout, meta info diverse + def test_17 + + manager = RBA::Manager::new + + ly = RBA::Layout::new(manager) + a = ly.create_cell("A") + + manager.transaction("trans") + ly.add_meta_info(RBA::LayoutMetaInfo::new("lm1", 17)) + a.add_meta_info(RBA::LayoutMetaInfo::new("am1", "u")) + manager.commit + + assert_equal(mi2s(ly), "lm1:17") + assert_equal(mi2s(a), "am1:u") + + manager.undo + assert_equal(mi2s(ly), "") + assert_equal(mi2s(a), "") + + manager.redo + assert_equal(mi2s(ly), "lm1:17") + assert_equal(mi2s(a), "am1:u") + + manager.transaction("trans") + ly.add_meta_info(RBA::LayoutMetaInfo::new("lm1", 117)) + a.add_meta_info(RBA::LayoutMetaInfo::new("am1", "v")) + manager.commit + + assert_equal(mi2s(ly), "lm1:117") + assert_equal(mi2s(a), "am1:v") + + manager.undo + assert_equal(mi2s(ly), "lm1:17") + assert_equal(mi2s(a), "am1:u") + + manager.redo + assert_equal(mi2s(ly), "lm1:117") + assert_equal(mi2s(a), "am1:v") + + manager.undo + assert_equal(mi2s(ly), "lm1:17") + assert_equal(mi2s(a), "am1:u") + + manager.transaction("trans") + ly.remove_meta_info("lm1") + a.remove_meta_info("am1") + a.remove_meta_info("doesnotexist") + manager.commit + + assert_equal(mi2s(ly), "") + assert_equal(mi2s(a), "") + + manager.undo + assert_equal(mi2s(ly), "lm1:17") + assert_equal(mi2s(a), "am1:u") + + manager.transaction("trans") + ly.clear_all_meta_info + manager.commit + + assert_equal(mi2s(ly), "") + assert_equal(mi2s(a), "") + + manager.undo + assert_equal(mi2s(ly), "lm1:17") + assert_equal(mi2s(a), "am1:u") + + manager.redo + assert_equal(mi2s(ly), "") + assert_equal(mi2s(a), "") + + ly2 = RBA::Layout::new + ly.add_meta_info(RBA::LayoutMetaInfo::new("lm1", 17)) + ly2.add_meta_info(RBA::LayoutMetaInfo::new("lm2", 42)) + assert_equal(mi2s(ly), "lm1:17") + ly.merge_meta_info(ly2) + assert_equal(mi2s(ly), "lm1:17;lm2:42") + ly.copy_meta_info(ly2) + assert_equal(mi2s(ly), "lm2:42") + + a = ly.create_cell("A") + a.add_meta_info(RBA::LayoutMetaInfo::new("am1", "u")) + b = ly2.create_cell("B") + b.add_meta_info(RBA::LayoutMetaInfo::new("bm1", "v")) + + assert_equal(mi2s(a), "am1:u") + a.merge_meta_info(b) + assert_equal(mi2s(a), "am1:u;bm1:v") + a.copy_meta_info(b) + assert_equal(mi2s(a), "bm1:v") + + ly = RBA::Layout::new + ly2 = RBA::Layout::new + + a = ly.create_cell("A") + a.add_meta_info(RBA::LayoutMetaInfo::new("am1", "u")) + ly2.create_cell("X") + b = ly2.create_cell("B") + b.add_meta_info(RBA::LayoutMetaInfo::new("bm1", "v")) + + cm = RBA::CellMapping::new + cm.map(b.cell_index, a.cell_index) + + assert_equal(mi2s(a), "am1:u") + ly.merge_meta_info(ly2, cm) + assert_equal(mi2s(a), "am1:u;bm1:v") + ly.copy_meta_info(ly2, cm) + assert_equal(mi2s(a), "bm1:v") + + end + end load("test_epilogue.rb")