mirror of https://github.com/KLayout/klayout.git
Fixed issue #2088 in reader and writer
Reader fix: the reader will not error out duplicate cell names, but rename the cells. Writer fix: the writer will uniquify cell names *after* illegal character substitution.
This commit is contained in:
parent
d1dc885235
commit
d0b935d9e5
|
|
@ -146,8 +146,6 @@ CommonReaderBase::name_for_id (size_t id) const
|
||||||
void
|
void
|
||||||
CommonReaderBase::rename_cell (db::Layout &layout, size_t id, const std::string &cn)
|
CommonReaderBase::rename_cell (db::Layout &layout, size_t id, const std::string &cn)
|
||||||
{
|
{
|
||||||
m_name_for_id.insert (std::make_pair (id, cn));
|
|
||||||
|
|
||||||
std::map<size_t, std::pair<std::string, db::cell_index_type> >::iterator iid = m_id_map.find (id);
|
std::map<size_t, std::pair<std::string, db::cell_index_type> >::iterator iid = m_id_map.find (id);
|
||||||
std::map<std::string, std::pair<size_t, db::cell_index_type> >::iterator iname = m_name_map.find (cn);
|
std::map<std::string, std::pair<size_t, db::cell_index_type> >::iterator iname = m_name_map.find (cn);
|
||||||
|
|
||||||
|
|
@ -156,9 +154,22 @@ CommonReaderBase::rename_cell (db::Layout &layout, size_t id, const std::string
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iname != m_name_map.end () && iname->second.first != null_id && iname->second.first != id) {
|
if (iname != m_name_map.end () && iname->second.first != null_id && iname->second.first != id) {
|
||||||
common_reader_error (tl::sprintf (tl::to_string (tr ("Same cell name %s, but different IDs: %ld and %ld")), cn, id, iname->second.first));
|
|
||||||
|
// picking a different name on name clash (issue #2088)
|
||||||
|
std::string cn_new = cn + "_id$" + tl::to_string (id);
|
||||||
|
for (size_t i = 0; m_name_map.find (cn_new) != m_name_map.end (); ++i) {
|
||||||
|
cn_new = cn + "_id$" + tl::to_string (id) + "$" + tl::to_string (i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
common_reader_warn (tl::sprintf (tl::to_string (tr ("Same cell name %s, but different IDs: %ld and %ld, renaming first to %s")), cn, id, iname->second.first, cn_new));
|
||||||
|
rename_cell (layout, id, cn_new);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
m_name_for_id.insert (std::make_pair (id, cn));
|
||||||
|
|
||||||
if (iid != m_id_map.end () && iname != m_name_map.end ()) {
|
if (iid != m_id_map.end () && iname != m_name_map.end ()) {
|
||||||
|
|
||||||
if (iname->second.second != iid->second.second) {
|
if (iname->second.second != iid->second.second) {
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#include "tlDeflate.h"
|
#include "tlDeflate.h"
|
||||||
#include "tlMath.h"
|
#include "tlMath.h"
|
||||||
|
#include "tlUniqueName.h"
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
|
@ -1334,7 +1335,7 @@ OASISWriter::write_cellname_table (size_t &cellnames_table_pos, const std::vecto
|
||||||
begin_table (cellnames_table_pos);
|
begin_table (cellnames_table_pos);
|
||||||
|
|
||||||
write_record_id (sequential ? 3 : 4);
|
write_record_id (sequential ? 3 : 4);
|
||||||
write_nstring (layout.cell_name (*cell));
|
write_nstring (cell_nstring (*cell));
|
||||||
if (! sequential) {
|
if (! sequential) {
|
||||||
write ((unsigned long) *cell);
|
write ((unsigned long) *cell);
|
||||||
}
|
}
|
||||||
|
|
@ -1476,6 +1477,31 @@ static bool skip_cell_body (const db::Cell &cref)
|
||||||
return cref.is_ghost_cell () && cref.empty ();
|
return cref.is_ghost_cell () && cref.empty ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
OASISWriter::create_cell_nstrings (const db::Layout &layout, const std::set <db::cell_index_type> &cell_set)
|
||||||
|
{
|
||||||
|
m_cell_nstrings.clear ();
|
||||||
|
|
||||||
|
std::set<std::string> names;
|
||||||
|
|
||||||
|
for (auto c = cell_set.begin (); c != cell_set.end (); ++c) {
|
||||||
|
|
||||||
|
std::string cn = make_nstring (layout.cell_name (*c));
|
||||||
|
cn = tl::unique_name (cn, names);
|
||||||
|
|
||||||
|
m_cell_nstrings.insert (std::make_pair (*c, cn));
|
||||||
|
names.insert (cn);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
OASISWriter::cell_nstring (db::cell_index_type cell_index)
|
||||||
|
{
|
||||||
|
auto n = m_cell_nstrings.find (cell_index);
|
||||||
|
tl_assert (n != m_cell_nstrings.end ());
|
||||||
|
return n->second.c_str ();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLayoutOptions &options)
|
OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLayoutOptions &options)
|
||||||
|
|
@ -1510,6 +1536,8 @@ OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::Save
|
||||||
std::set <db::cell_index_type> cell_set;
|
std::set <db::cell_index_type> cell_set;
|
||||||
options.get_cells (layout, cell_set, layers);
|
options.get_cells (layout, cell_set, layers);
|
||||||
|
|
||||||
|
create_cell_nstrings (layout, cell_set);
|
||||||
|
|
||||||
// create a cell index vector sorted bottom-up
|
// create a cell index vector sorted bottom-up
|
||||||
std::vector <db::cell_index_type> cells, cells_by_index;
|
std::vector <db::cell_index_type> cells, cells_by_index;
|
||||||
|
|
||||||
|
|
@ -1602,7 +1630,7 @@ OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::Save
|
||||||
is_top = (cell_set.find (*p) == cell_set.end ());
|
is_top = (cell_set.find (*p) == cell_set.end ());
|
||||||
}
|
}
|
||||||
if (is_top) {
|
if (is_top) {
|
||||||
write_property_def (s_top_cell_name, tl::Variant (make_nstring (layout.cell_name (*cell))), true);
|
write_property_def (s_top_cell_name, tl::Variant (cell_nstring (*cell)), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -216,6 +216,7 @@ private:
|
||||||
std::map <std::string, unsigned long> m_textstrings;
|
std::map <std::string, unsigned long> m_textstrings;
|
||||||
std::map <std::string, unsigned long> m_propnames;
|
std::map <std::string, unsigned long> m_propnames;
|
||||||
std::map <std::string, unsigned long> m_propstrings;
|
std::map <std::string, unsigned long> m_propstrings;
|
||||||
|
std::map <db::cell_index_type, std::string> m_cell_nstrings;
|
||||||
|
|
||||||
typedef std::vector<tl::Variant> property_value_list;
|
typedef std::vector<tl::Variant> property_value_list;
|
||||||
|
|
||||||
|
|
@ -248,6 +249,9 @@ private:
|
||||||
OASISWriterOptions m_options;
|
OASISWriterOptions m_options;
|
||||||
tl::AbsoluteProgress m_progress;
|
tl::AbsoluteProgress m_progress;
|
||||||
|
|
||||||
|
void create_cell_nstrings (const db::Layout &layout, const std::set <db::cell_index_type> &cell_set);
|
||||||
|
const char *cell_nstring(db::cell_index_type cell_index);
|
||||||
|
|
||||||
void write_record_id (char b);
|
void write_record_id (char b);
|
||||||
void write_byte (char b);
|
void write_byte (char b);
|
||||||
void write_bytes (const char *b, size_t n);
|
void write_bytes (const char *b, size_t n);
|
||||||
|
|
|
||||||
|
|
@ -662,20 +662,16 @@ TEST(Bug_1799)
|
||||||
EXPECT_EQ (ps2.value (pn).to_string (), "hello, world!");
|
EXPECT_EQ (ps2.value (pn).to_string (), "hello, world!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Modified in #2088 to give a warning
|
||||||
TEST(DuplicateCellname)
|
TEST(DuplicateCellname)
|
||||||
{
|
{
|
||||||
db::Manager m (false);
|
db::Manager m (false);
|
||||||
db::Layout layout (&m);
|
db::Layout layout (&m);
|
||||||
|
|
||||||
try {
|
|
||||||
tl::InputStream file (tl::testdata () + "/oasis/duplicate_cellname.oas");
|
tl::InputStream file (tl::testdata () + "/oasis/duplicate_cellname.oas");
|
||||||
db::OASISReader reader (file);
|
db::OASISReader reader (file);
|
||||||
reader.read (layout);
|
reader.read (layout);
|
||||||
EXPECT_EQ (false, true);
|
|
||||||
} catch (tl::CancelException &ex) {
|
std::string fn_au (tl::testdata () + "/oasis/duplicate_cellname_au.oas");
|
||||||
// Seen when private test data is not installed
|
db::compare_layouts (_this, layout, fn_au, db::NoNormalization, 1);
|
||||||
throw;
|
|
||||||
} catch (tl::Exception &ex) {
|
|
||||||
EXPECT_EQ (ex.msg ().find ("Same cell name TOP, but different IDs: 3 and 0 (position=1070, cell=)"), size_t (0));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2072,3 +2072,31 @@ TEST(130d)
|
||||||
run_test130 (_this, true, true);
|
run_test130 (_this, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Issue #2088 (name duplication)
|
||||||
|
TEST(140)
|
||||||
|
{
|
||||||
|
db::Layout layout_org;
|
||||||
|
|
||||||
|
layout_org.add_cell ("X X");
|
||||||
|
layout_org.add_cell ("X*X");
|
||||||
|
|
||||||
|
std::string tmp_file = tl::TestBase::tmp_file (tl::sprintf ("tmp_dbOASISWriter140.oas"));
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::OutputStream out (tmp_file);
|
||||||
|
db::SaveLayoutOptions options;
|
||||||
|
options.set_format ("OASIS");
|
||||||
|
db::Writer writer (options);
|
||||||
|
writer.write (layout_org, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::InputStream in (tmp_file);
|
||||||
|
db::Reader reader (in);
|
||||||
|
db::Layout gg;
|
||||||
|
reader.set_warnings_as_errors (true);
|
||||||
|
reader.read (gg);
|
||||||
|
|
||||||
|
db::compare_layouts (_this, gg, tl::testdata () + "/oasis/dbOASISWriter40_au.gds", db::NoNormalization);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue