mirror of https://github.com/KLayout/klayout.git
WIP: cell name conflict resolution modes, bugfixed first implementation
This commit is contained in:
parent
85869c329d
commit
a92ebd0e17
|
|
@ -59,7 +59,7 @@ CommonReader::make_cell (db::Layout &layout, const std::string &cn)
|
|||
|
||||
} else {
|
||||
|
||||
db::cell_index_type ci = layout.add_cell ();
|
||||
db::cell_index_type ci = layout.add_anonymous_cell ();
|
||||
|
||||
m_name_map [cn] = std::make_pair (null_id, ci);
|
||||
return ci;
|
||||
|
|
@ -103,7 +103,7 @@ CommonReader::make_cell (db::Layout &layout, size_t id)
|
|||
|
||||
} else {
|
||||
|
||||
db::cell_index_type ci = layout.add_cell ();
|
||||
db::cell_index_type ci = layout.add_anonymous_cell ();
|
||||
|
||||
m_id_map [id] = std::make_pair (std::string (), ci);
|
||||
return ci;
|
||||
|
|
@ -136,7 +136,7 @@ CommonReader::rename_cell (db::Layout &layout, size_t id, const std::string &cn)
|
|||
|
||||
if (iid != m_id_map.end () && iname != m_name_map.end ()) {
|
||||
|
||||
if (iid->second.first != cn) {
|
||||
if (! iid->second.first.empty () && iid->second.first != cn) {
|
||||
common_reader_error (tl::sprintf (tl::to_string (tr ("Cell named %s with ID %ld was already given name %s")), cn, id, iid->second.first));
|
||||
}
|
||||
|
||||
|
|
@ -149,20 +149,26 @@ CommonReader::rename_cell (db::Layout &layout, size_t id, const std::string &cn)
|
|||
|
||||
}
|
||||
|
||||
iid->second.first = cn;
|
||||
iname->second.first = id;
|
||||
|
||||
} else if (iid != m_id_map.end ()) {
|
||||
|
||||
m_name_map [cn] = std::make_pair (id, iid->second.second);
|
||||
iid->second.first = cn;
|
||||
|
||||
} else if (iname != m_name_map.end ()) {
|
||||
|
||||
m_id_map [id] = std::make_pair (cn, iname->second.second);
|
||||
iname->second.first = id;
|
||||
|
||||
} else {
|
||||
|
||||
db::cell_index_type ci = layout.add_cell ();
|
||||
db::cell_index_type ci = layout.add_anonymous_cell ();
|
||||
layout.cell (ci).set_ghost_cell (true);
|
||||
|
||||
m_id_map [id] = std::make_pair (std::string (), ci);
|
||||
m_name_map [cn] = std::make_pair (null_id, ci);
|
||||
m_id_map [id] = std::make_pair (cn, ci);
|
||||
m_name_map [cn] = std::make_pair (id, ci);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -179,7 +185,7 @@ CommonReader::cell_for_instance (db::Layout &layout, size_t id)
|
|||
|
||||
} else {
|
||||
|
||||
db::cell_index_type ci = layout.add_cell ();
|
||||
db::cell_index_type ci = layout.add_anonymous_cell ();
|
||||
layout.cell (ci).set_ghost_cell (true);
|
||||
|
||||
m_id_map [id] = std::make_pair (std::string (), ci);
|
||||
|
|
@ -200,7 +206,7 @@ CommonReader::cell_for_instance (db::Layout &layout, const std::string &cn)
|
|||
|
||||
} else {
|
||||
|
||||
db::cell_index_type ci = layout.add_cell ();
|
||||
db::cell_index_type ci = layout.add_anonymous_cell ();
|
||||
layout.cell (ci).set_ghost_cell (true);
|
||||
|
||||
m_name_map [cn] = std::make_pair (null_id, ci);
|
||||
|
|
@ -259,44 +265,84 @@ CommonReader::finish (db::Layout &layout)
|
|||
common_reader_error (tl::to_string (tr ("Some cell IDs don't have a name (see previous warnings)")));
|
||||
}
|
||||
|
||||
for (std::map<std::string, std::pair<size_t, db::cell_index_type> >::const_iterator i = m_name_map.begin (); i != m_name_map.end (); ++i) {
|
||||
// check if we need to resolve conflicts
|
||||
|
||||
if (layout.has_cell (i->first.c_str ())) {
|
||||
bool has_conflict = false;
|
||||
for (std::map<std::string, std::pair<size_t, db::cell_index_type> >::const_iterator i = m_name_map.begin (); i != m_name_map.end () && ! has_conflict; ++i) {
|
||||
has_conflict = layout.cell_by_name (i->first.c_str ()).first;
|
||||
}
|
||||
|
||||
db::cell_index_type ci_org = layout.cell_by_name (i->first.c_str ()).second;
|
||||
db::cell_index_type ci_new = i->second.second;
|
||||
if (! has_conflict) {
|
||||
|
||||
if (m_cc_resolution == RenameCell || layout.cell (ci_org).is_proxy ()) {
|
||||
// no conflict - plain rename
|
||||
|
||||
// NOTE: we never reopen proxies (they are always local to their layout). Instead we
|
||||
// always rename for proxies
|
||||
layout.rename_cell (i->second.second, i->first.c_str ());
|
||||
for (std::map<std::string, std::pair<size_t, db::cell_index_type> >::const_iterator i = m_name_map.begin (); i != m_name_map.end () && ! has_conflict; ++i) {
|
||||
layout.rename_cell (i->second.second, i->first.c_str ());
|
||||
}
|
||||
|
||||
} else {
|
||||
} else {
|
||||
|
||||
// we have a cell conflict
|
||||
layout.force_update ();
|
||||
// elaborate conflict resolution
|
||||
|
||||
if (m_cc_resolution == OverwriteCell && ! layout.cell (ci_new).is_ghost_cell ()) {
|
||||
layout.force_update ();
|
||||
|
||||
layout.prune_subcells (ci_org);
|
||||
layout.cell (ci_org).clear_shapes ();
|
||||
std::map<db::cell_index_type, std::string> new_cells;
|
||||
for (std::map<std::string, std::pair<size_t, db::cell_index_type> >::const_iterator i = m_name_map.begin (); i != m_name_map.end (); ++i) {
|
||||
new_cells.insert (std::make_pair (i->second.second, i->first));
|
||||
}
|
||||
|
||||
} else if (m_cc_resolution == SkipNewCell && ! layout.cell (ci_org).is_ghost_cell ()) {
|
||||
// NOTE: by iterating bottom up we don't need to update the layout (we need the parents for merge_cell)
|
||||
for (db::Layout::bottom_up_iterator bu = layout.begin_bottom_up (); bu != layout.end_bottom_up (); ++bu) {
|
||||
|
||||
layout.prune_subcells (ci_new);
|
||||
layout.cell (ci_new).clear_shapes ();
|
||||
db::cell_index_type ci_new = *bu;
|
||||
|
||||
if (new_cells.find (ci_new) == new_cells.end ()) {
|
||||
// not a new cell
|
||||
continue;
|
||||
} else if (! layout.is_valid_cell_index (ci_new)) {
|
||||
// this can happen if the new cell has been deleted by "prune_subcells"
|
||||
continue;
|
||||
}
|
||||
|
||||
std::map<db::cell_index_type, std::string>::const_iterator i = new_cells.find (ci_new);
|
||||
|
||||
std::pair<bool, db::cell_index_type> c2n = layout.cell_by_name (i->second.c_str ());
|
||||
db::cell_index_type ci_org = c2n.second;
|
||||
|
||||
if (c2n.first) {
|
||||
|
||||
if (m_cc_resolution == RenameCell || layout.cell (ci_org).is_proxy ()) {
|
||||
|
||||
// NOTE: we never reopen proxies (they are always local to their layout). Instead we
|
||||
// always rename for proxies
|
||||
layout.rename_cell (ci_new, layout.uniquify_cell_name (i->second.c_str ()).c_str ());
|
||||
|
||||
} else {
|
||||
|
||||
// we have a cell conflict
|
||||
|
||||
if (m_cc_resolution == OverwriteCell && ! layout.cell (ci_new).is_ghost_cell ()) {
|
||||
|
||||
layout.prune_subcells (ci_org);
|
||||
layout.cell (ci_org).clear_shapes ();
|
||||
|
||||
} else if (m_cc_resolution == SkipNewCell && ! layout.cell (ci_org).is_ghost_cell ()) {
|
||||
|
||||
layout.prune_subcells (ci_new);
|
||||
layout.cell (ci_new).clear_shapes ();
|
||||
|
||||
}
|
||||
|
||||
merge_cell (layout, ci_org, ci_new);
|
||||
|
||||
}
|
||||
|
||||
merge_cell (layout, ci_org, ci_new);
|
||||
} else {
|
||||
|
||||
layout.rename_cell (ci_new, layout.uniquify_cell_name (i->second.c_str ()).c_str ());
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
layout.rename_cell (i->second.second, i->first.c_str ());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1068,14 +1068,41 @@ Layout::add_cell (const char *name)
|
|||
return new_index;
|
||||
}
|
||||
|
||||
cell_index_type
|
||||
Layout::add_anonymous_cell ()
|
||||
{
|
||||
std::string b;
|
||||
|
||||
// create a new cell
|
||||
cell_index_type new_index = allocate_new_cell ();
|
||||
|
||||
cell_type *new_cell = new cell_type (new_index, *this);
|
||||
m_cells.push_back_ptr (new_cell);
|
||||
m_cell_ptrs [new_index] = new_cell;
|
||||
|
||||
// enter it's index and cell_name
|
||||
register_cell_name (0, new_index);
|
||||
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
manager ()->queue (this, new NewRemoveCellOp (new_index, m_cell_names [new_index], false /*new*/, 0));
|
||||
}
|
||||
|
||||
return new_index;
|
||||
}
|
||||
|
||||
void
|
||||
Layout::register_cell_name (const char *name, cell_index_type ci)
|
||||
{
|
||||
// enter it's index and cell_name
|
||||
char *cp;
|
||||
|
||||
cp = new char [strlen (name) + 1];
|
||||
strcpy (cp, name);
|
||||
if (name == 0) {
|
||||
cp = new char [1];
|
||||
*cp = 0;
|
||||
} else {
|
||||
cp = new char [strlen (name) + 1];
|
||||
strcpy (cp, name);
|
||||
}
|
||||
|
||||
while (m_cell_names.size () < ci) {
|
||||
char *e = new char [1];
|
||||
|
|
@ -1090,7 +1117,9 @@ Layout::register_cell_name (const char *name, cell_index_type ci)
|
|||
m_cell_names.push_back (cp);
|
||||
}
|
||||
|
||||
m_cell_map.insert (std::make_pair (cp, ci));
|
||||
if (name) {
|
||||
m_cell_map.insert (std::make_pair (cp, ci));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -727,7 +727,17 @@ public:
|
|||
*/
|
||||
cell_index_type add_cell (const char *name = 0);
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Add a cell without a name
|
||||
*
|
||||
* The cell is created, but cannot be found by name. The name returned is an empty string.
|
||||
* The cell is created with the purpose of being renamed later.
|
||||
*
|
||||
* @return The index of the new cell
|
||||
*/
|
||||
cell_index_type add_anonymous_cell ();
|
||||
|
||||
/**
|
||||
* @brief Rename a cell
|
||||
*
|
||||
* Rename the cell with the given id.
|
||||
|
|
|
|||
|
|
@ -85,6 +85,16 @@ static void set_properties_enabled (db::LoadLayoutOptions *options, bool l)
|
|||
options->get_options<db::CommonReaderOptions> ().enable_properties = l;
|
||||
}
|
||||
|
||||
static db::CommonReader::CellConflictResolution get_cell_conflict_resolution (const db::LoadLayoutOptions *options)
|
||||
{
|
||||
return options->get_options<db::CommonReaderOptions> ().cell_conflict_resolution;
|
||||
}
|
||||
|
||||
static void set_cell_conflict_resolution (db::LoadLayoutOptions *options, db::CommonReader::CellConflictResolution cc)
|
||||
{
|
||||
options->get_options<db::CommonReaderOptions> ().cell_conflict_resolution = cc;
|
||||
}
|
||||
|
||||
// extend lay::LoadLayoutOptions with the Common options
|
||||
static
|
||||
gsi::ClassExt<db::LoadLayoutOptions> common_reader_options (
|
||||
|
|
@ -157,6 +167,22 @@ gsi::ClassExt<db::LoadLayoutOptions> common_reader_options (
|
|||
"@param enabled True, if properties should be read."
|
||||
"\n"
|
||||
"Starting with version 0.25 this option only applies to GDS2 and OASIS format. Other formats provide their own configuration."
|
||||
) +
|
||||
gsi::method_ext ("cell_conflict_resolution", &get_cell_conflict_resolution,
|
||||
"@brief Gets the cell conflict resolution mode\n"
|
||||
"\n"
|
||||
"Multiple layout files can be collected into a single Layout object by reading file after file into the Layout object. "
|
||||
"Cells with same names are considered a conflict. This mode indicates how such conflicts are resolved. See \\CellConflictResolution "
|
||||
"for the values allowed. The default mode is \\CellConflictResolution#AddToCell.\n"
|
||||
"\n"
|
||||
"This option has been introduced in version 0.27."
|
||||
) +
|
||||
gsi::method_ext ("cell_conflict_resolution=", &set_cell_conflict_resolution, gsi::arg ("mode"),
|
||||
"@brief Sets the cell conflict resolution mode\n"
|
||||
"\n"
|
||||
"See \\cell_conflict_resolution for details about this option.\n"
|
||||
"\n"
|
||||
"This option has been introduced in version 0.27."
|
||||
),
|
||||
""
|
||||
);
|
||||
|
|
|
|||
|
|
@ -366,6 +366,8 @@ TEST(Bug_121_1)
|
|||
reader.read (layout);
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
|
||||
std::string fn_au (tl::testsrc () + "/testdata/gds/bug_121_au1.gds");
|
||||
db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1145,7 +1145,9 @@ OASISReader::do_read (db::Layout &layout)
|
|||
|
||||
unsigned long id = 0;
|
||||
get (id);
|
||||
if (has_cell (id)) {
|
||||
|
||||
std::pair<bool, db::cell_index_type> cc = cell_by_id (id);
|
||||
if (cc.first && ! layout.cell (cc.second).is_ghost_cell ()) {
|
||||
error (tl::sprintf (tl::to_string (tr ("A cell with id %ld is defined already")), id));
|
||||
}
|
||||
|
||||
|
|
@ -1158,7 +1160,9 @@ OASISReader::do_read (db::Layout &layout)
|
|||
}
|
||||
|
||||
std::string name = get_str ();
|
||||
if (has_cell (name)) {
|
||||
|
||||
std::pair<bool, db::cell_index_type> cc = cell_by_name (name);
|
||||
if (cc.first && ! layout.cell (cc.second).is_ghost_cell ()) {
|
||||
error (tl::sprintf (tl::to_string (tr ("A cell with name %s is defined already")), name.c_str ()));
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue