mirror of https://github.com/KLayout/klayout.git
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:
parent
c6ede46fd0
commit
f16a5085c5
|
|
@ -137,14 +137,23 @@ MAGReader::warn (const std::string &msg)
|
|||
db::cell_index_type
|
||||
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 ()) {
|
||||
return c->second;
|
||||
}
|
||||
|
||||
// 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 ());
|
||||
m_cells_read.insert (std::make_pair (path, ci));
|
||||
db::cell_index_type 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;
|
||||
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;
|
||||
layout.cell (ci).set_ghost_cell (true);
|
||||
} 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;
|
||||
|
|
|
|||
|
|
@ -62,12 +62,8 @@ MAGWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLa
|
|||
tl::URI src (stream.path ());
|
||||
std::string basename = tl::basename (src.path ());
|
||||
std::pair<bool, db::cell_index_type> ci = layout.cell_by_name (basename.c_str ());
|
||||
if (! ci.first) {
|
||||
throw tl::Exception (tl::to_string (tr ("Magic file names must be valid cell names. 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);
|
||||
if (! ci.first || cell_set.find (ci.second) == cell_set.end ()) {
|
||||
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;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
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";
|
||||
|
|
@ -151,7 +147,7 @@ MAGWriter::do_write_cell (db::cell_index_type ci, const std::vector <std::pair <
|
|||
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) {
|
||||
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;
|
||||
}
|
||||
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");
|
||||
}
|
||||
|
||||
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
|
||||
|
|
@ -294,7 +290,7 @@ MAGWriter::write_single_instance (db::cell_index_type ci, db::ICplxTrans trans,
|
|||
|
||||
int id = (m_cell_id [ci] += 1);
|
||||
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) {
|
||||
|
||||
|
|
@ -384,5 +380,29 @@ MAGWriter::needs_rounding (const db::Vector &v) const
|
|||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ private:
|
|||
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_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
|
||||
|
|
|
|||
|
|
@ -29,49 +29,6 @@
|
|||
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
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ static std::locale c_locale ("C");
|
|||
|
||||
#include "utf_casefolding.h"
|
||||
|
||||
static inline wchar_t wdowncase (wchar_t c)
|
||||
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]) {
|
||||
|
|
@ -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;
|
||||
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) {
|
||||
return c32;
|
||||
|
|
@ -75,8 +75,7 @@ static inline uint32_t utf32_downcase (uint32_t c32)
|
|||
}
|
||||
}
|
||||
|
||||
/* Not used yet:
|
||||
static inline uint32_t utf32_upcase (uint32_t c32)
|
||||
uint32_t utf32_upcase (uint32_t c32)
|
||||
{
|
||||
if (sizeof (wchar_t) == 2 && c32 >= 0x10000) {
|
||||
return c32;
|
||||
|
|
@ -84,12 +83,11 @@ static inline uint32_t utf32_upcase (uint32_t c32)
|
|||
return uint32_t (wupcase (wchar_t (c32)));
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// 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++;
|
||||
if (c32 >= 0xf0 && ((cpe && cp + 2 < cpe) || (! cpe && cp [0] && cp [1] && cp [2]))) {
|
||||
|
|
|
|||
|
|
@ -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::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
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue