WIP: some implementation refinement

- MAG writer output name does not need to match a cell name
  (this file is not written in this case, but the path and extension
  are taken from it). A warning is issued in this case.
- Strings for layer and cell names are normalized (special chars, UTF8)
- Cell duplicates won't be produced but existing cells are reused.
  This enables "incremental reads".
This commit is contained in:
Matthias Koefferlein 2019-11-30 19:04:54 +01:00
parent c6ede46fd0
commit f16a5085c5
6 changed files with 76 additions and 66 deletions

View File

@ -137,14 +137,23 @@ MAGReader::warn (const std::string &msg)
db::cell_index_type db::cell_index_type
MAGReader::cell_from_path (const std::string &path, db::Layout &layout) MAGReader::cell_from_path (const std::string &path, db::Layout &layout)
{ {
std::map<std::string, db::cell_index_type>::const_iterator c = m_cells_read.find (path); std::string cellname = tl::filename (path);
std::map<std::string, db::cell_index_type>::const_iterator c = m_cells_read.find (cellname);
if (c != m_cells_read.end ()) { if (c != m_cells_read.end ()) {
return c->second; return c->second;
} }
// NOTE: this can lead to cell variants if a cell is present with different library paths ... (L500_CHAR_p) // NOTE: this can lead to cell variants if a cell is present with different library paths ... (L500_CHAR_p)
db::cell_index_type ci = layout.add_cell (cell_name_from_path (path).c_str ()); db::cell_index_type ci;
m_cells_read.insert (std::make_pair (path, ci)); if (layout.has_cell (cellname.c_str ())) {
// NOTE: this reuses an existing cell and will add(!) the layout to the latter. This
// enables "incremental read" like for GDS files.
ci = layout.cell_by_name (cellname.c_str ()).second;
} else {
ci = layout.add_cell (cell_name_from_path (path).c_str ());
}
m_cells_read.insert (std::make_pair (cellname, ci));
std::string cell_file; std::string cell_file;
if (! resolve_path (path, cell_file)) { if (! resolve_path (path, cell_file)) {
@ -152,7 +161,7 @@ MAGReader::cell_from_path (const std::string &path, db::Layout &layout)
tl::warn << tl::to_string (tr ("Unable to find a layout file for cell - skipping this cell: ")) << path; tl::warn << tl::to_string (tr ("Unable to find a layout file for cell - skipping this cell: ")) << path;
layout.cell (ci).set_ghost_cell (true); layout.cell (ci).set_ghost_cell (true);
} else { } else {
m_cells_to_read.insert (std::make_pair (path, std::make_pair (cell_file, ci))); m_cells_to_read.insert (std::make_pair (cellname, std::make_pair (cell_file, ci)));
} }
return ci; return ci;

View File

@ -62,12 +62,8 @@ MAGWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLa
tl::URI src (stream.path ()); tl::URI src (stream.path ());
std::string basename = tl::basename (src.path ()); std::string basename = tl::basename (src.path ());
std::pair<bool, db::cell_index_type> ci = layout.cell_by_name (basename.c_str ()); std::pair<bool, db::cell_index_type> ci = layout.cell_by_name (basename.c_str ());
if (! ci.first) { if (! ci.first || cell_set.find (ci.second) == cell_set.end ()) {
throw tl::Exception (tl::to_string (tr ("Magic file names must be valid cell names. This is not a valid name: ")) + basename); tl::warn << tl::to_string (tr ("Magic file names should be valid cell names - otherwise no such file is written. This is not a valid name: ")) << basename;
}
if (cell_set.find (ci.second) == cell_set.end ()) {
throw tl::Exception (tl::to_string (tr ("Cell name derived from file name isn't a selected cell: ")) + basename);
} }
m_options = options.get_options<MAGWriterOptions> (); m_options = options.get_options<MAGWriterOptions> ();
@ -135,7 +131,7 @@ MAGWriter::do_write_cell (db::cell_index_type ci, const std::vector <std::pair <
tech = layout.meta_info_value ("technology"); tech = layout.meta_info_value ("technology");
} }
if (! tech.empty ()) { if (! tech.empty ()) {
os << "tech " << tl::to_word_or_quoted_string (tl::to_lower_case (tech)) << "\n"; os << "tech " << make_string (tl::to_lower_case (tech)) << "\n";
} }
os << "timestamp " << m_timestamp << "\n"; os << "timestamp " << m_timestamp << "\n";
@ -151,7 +147,7 @@ MAGWriter::do_write_cell (db::cell_index_type ci, const std::vector <std::pair <
any = false; any = false;
for (db::Shapes::shape_iterator s = cell.shapes (ll->first).begin (db::ShapeIterator::Boxes | db::ShapeIterator::Polygons | db::ShapeIterator::Paths); ! s.at_end (); ++s) { for (db::Shapes::shape_iterator s = cell.shapes (ll->first).begin (db::ShapeIterator::Boxes | db::ShapeIterator::Polygons | db::ShapeIterator::Paths); ! s.at_end (); ++s) {
if (! any) { if (! any) {
os << "<< " << tl::to_word_or_quoted_string (tl::to_lower_case (ll->second.name)) << " >>\n"; os << "<< " << make_string (tl::to_lower_case (ll->second.name)) << " >>\n";
any = true; any = true;
} }
db::Polygon poly; db::Polygon poly;
@ -262,7 +258,7 @@ MAGWriter::write_label (const std::string &layer, const db::Text &text, const db
s = tl::replaced (s, "\n", "\\n"); s = tl::replaced (s, "\n", "\\n");
} }
os << "rlabel " << tl::to_word_or_quoted_string (layer) << " " << v.x () << " " << v.y () << " " << v.x () << " " << v.y () << " 0 " << s << "\n"; os << "rlabel " << make_string (layer) << " " << v.x () << " " << v.y () << " " << v.x () << " " << v.y () << " 0 " << s << "\n";
} }
void void
@ -294,7 +290,7 @@ MAGWriter::write_single_instance (db::cell_index_type ci, db::ICplxTrans trans,
int id = (m_cell_id [ci] += 1); int id = (m_cell_id [ci] += 1);
std::string cn = layout.cell_name (ci); std::string cn = layout.cell_name (ci);
os << "use " << tl::to_word_or_quoted_string (cn) << " " << tl::to_word_or_quoted_string (cn + "_" + tl::to_string (id)) << "\n"; os << "use " << make_string (cn) << " " << make_string (cn + "_" + tl::to_string (id)) << "\n";
if (na > 1 || nb > 1) { if (na > 1 || nb > 1) {
@ -384,5 +380,29 @@ MAGWriter::needs_rounding (const db::Vector &v) const
return ! db::DVector (res).equal (db::DVector (v) * m_sf); return ! db::DVector (res).equal (db::DVector (v) * m_sf);
} }
static inline bool is_valid_char (uint32_t c32)
{
return (c32 >= 'A' && c32 <= 'Z') ||
(c32 >= 'a' && c32 <= 'z') ||
(c32 >= '0' && c32 <= '9') ||
c32 == '_' || c32 == '.';
}
std::string
MAGWriter::make_string (const std::string &s)
{
std::string res;
for (const char *cp = s.c_str (); *cp; ) {
uint32_t c32 = tl::utf32_from_utf8 (cp);
if (! is_valid_char (c32)) {
res += tl::sprintf ("x%x", c32);
} else {
res += (char) c32;
}
}
return res;
}
} }

View File

@ -104,6 +104,7 @@ private:
void write_label (const std::string &layer, const db::Text &text, const Layout &layout, tl::OutputStream &os); void write_label (const std::string &layer, const db::Text &text, const Layout &layout, tl::OutputStream &os);
void write_instance (const db::CellInstArray &inst, const db::Layout &layout, tl::OutputStream &os); void write_instance (const db::CellInstArray &inst, const db::Layout &layout, tl::OutputStream &os);
void write_single_instance (db::cell_index_type ci, ICplxTrans tr, db::Vector a, db::Vector b, unsigned long na, unsigned long nb, const db::Layout &layout, tl::OutputStream &os); void write_single_instance (db::cell_index_type ci, ICplxTrans tr, db::Vector a, db::Vector b, unsigned long na, unsigned long nb, const db::Layout &layout, tl::OutputStream &os);
std::string make_string (const std::string &s);
}; };
} // namespace db } // namespace db

View File

@ -29,49 +29,6 @@
namespace tl namespace tl
{ {
// ---------------------------------------------------------------------------------
// TODO: take from tlString.h
static inline uint32_t utf32_from_utf8 (const char *&cp, const char *cpe = 0)
{
uint32_t c32 = (unsigned char) *cp++;
if (c32 >= 0xf0 && ((cpe && cp + 2 < cpe) || (! cpe && cp [0] && cp [1] && cp [2]))) {
c32 = ((c32 & 0x7) << 18) | ((uint32_t (cp [0]) & 0x3f) << 12) | ((uint32_t (cp [1]) & 0x3f) << 6) | (uint32_t (cp [2]) & 0x3f);
cp += 3;
} else if (c32 >= 0xe0 && ((cpe && cp + 1 < cpe) || (! cpe && cp [0] && cp [1]))) {
c32 = ((c32 & 0xf) << 12) | ((uint32_t (cp [0]) & 0x3f) << 6) | (uint32_t (cp [1]) & 0x3f);
cp += 2;
} else if (c32 >= 0xc0 && ((cpe && cp < cpe) || (! cpe && cp [0]))) {
c32 = ((c32 & 0x1f) << 6) | (uint32_t (*cp) & 0x3f);
++cp;
}
return c32;
}
#include "utf_casefolding.h"
static inline wchar_t wdowncase (wchar_t c)
{
int ch = c >> 8;
if (ch >= 0 && ch < int (sizeof (uc_tab) / sizeof (uc_tab[0])) && uc_tab[ch]) {
return uc_tab[ch][c & 0xff];
} else {
return c;
}
}
static inline uint32_t utf32_downcase (uint32_t c32)
{
if (sizeof (wchar_t) == 2 && c32 >= 0x10000) {
return c32;
} else {
return uint32_t (wdowncase (wchar_t (c32)));
}
}
// ---------------------------------------------------------------------------------
class GlobPatternOpBase class GlobPatternOpBase
{ {
public: public:

View File

@ -46,7 +46,7 @@ static std::locale c_locale ("C");
#include "utf_casefolding.h" #include "utf_casefolding.h"
static inline wchar_t wdowncase (wchar_t c) wchar_t wdowncase (wchar_t c)
{ {
int ch = c >> 8; int ch = c >> 8;
if (ch >= 0 && ch < int (sizeof (uc_tab) / sizeof (uc_tab[0])) && uc_tab[ch]) { if (ch >= 0 && ch < int (sizeof (uc_tab) / sizeof (uc_tab[0])) && uc_tab[ch]) {
@ -56,7 +56,7 @@ static inline wchar_t wdowncase (wchar_t c)
} }
} }
static inline wchar_t wupcase (wchar_t c) wchar_t wupcase (wchar_t c)
{ {
int ch = c >> 8; int ch = c >> 8;
if (ch >= 0 && ch < int (sizeof (lc_tab) / sizeof (lc_tab[0])) && lc_tab[ch]) { if (ch >= 0 && ch < int (sizeof (lc_tab) / sizeof (lc_tab[0])) && lc_tab[ch]) {
@ -66,7 +66,7 @@ static inline wchar_t wupcase (wchar_t c)
} }
} }
static inline uint32_t utf32_downcase (uint32_t c32) uint32_t utf32_downcase (uint32_t c32)
{ {
if (sizeof (wchar_t) == 2 && c32 >= 0x10000) { if (sizeof (wchar_t) == 2 && c32 >= 0x10000) {
return c32; return c32;
@ -75,8 +75,7 @@ static inline uint32_t utf32_downcase (uint32_t c32)
} }
} }
/* Not used yet: uint32_t utf32_upcase (uint32_t c32)
static inline uint32_t utf32_upcase (uint32_t c32)
{ {
if (sizeof (wchar_t) == 2 && c32 >= 0x10000) { if (sizeof (wchar_t) == 2 && c32 >= 0x10000) {
return c32; return c32;
@ -84,12 +83,11 @@ static inline uint32_t utf32_upcase (uint32_t c32)
return uint32_t (wupcase (wchar_t (c32))); return uint32_t (wupcase (wchar_t (c32)));
} }
} }
*/
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// Conversion of UTF8 to wchar_t // Conversion of UTF8 to wchar_t
uint32_t utf32_from_utf8 (const char *&cp, const char *cpe = 0) uint32_t utf32_from_utf8 (const char *&cp, const char *cpe)
{ {
uint32_t c32 = (unsigned char) *cp++; uint32_t c32 = (unsigned char) *cp++;
if (c32 >= 0xf0 && ((cpe && cp + 2 < cpe) || (! cpe && cp [0] && cp [1] && cp [2]))) { if (c32 >= 0xf0 && ((cpe && cp + 2 < cpe) || (! cpe && cp [0] && cp [1] && cp [2]))) {

View File

@ -878,8 +878,33 @@ TL_PUBLIC std::string trim (const std::string &s);
TL_PUBLIC std::vector<std::string> split (const std::string &s, const std::string &sep); TL_PUBLIC std::vector<std::string> split (const std::string &s, const std::string &sep);
TL_PUBLIC std::string join (const std::vector<std::string> &strings, const std::string &sep); TL_PUBLIC std::string join (const std::vector<std::string> &strings, const std::string &sep);
/**
* @brief Returns the lower-case character for a wchar_t
*/
TL_PUBLIC wchar_t wdowncase (wchar_t c);
/**
* @brief Returns the upper-case character for a wchar_t
*/
TL_PUBLIC wchar_t wupcase (wchar_t c);
/**
* @brief Returns the lower-case UTF32 character
*/
TL_PUBLIC uint32_t utf32_downcase (uint32_t c32);
/**
* @brief Returns the upper-case UTF32 character
*/
TL_PUBLIC uint32_t utf32_upcase (uint32_t c32);
/**
* @brief Parses the next UTF32 character from an UTF-8 string
* @param cp The input character's position, will be set to the next character.
* @paran cpe The end of the string of 0 for "no end"
*/
TL_PUBLIC uint32_t utf32_from_utf8 (const char *&cp, const char *cpe = 0);
} // namespace tl } // namespace tl
#endif #endif