mirror of https://github.com/KLayout/klayout.git
Merge branch 'enhanced-meta-info' into wip2
This commit is contained in:
commit
67276c4922
|
|
@ -124,6 +124,7 @@ SOURCES = \
|
|||
gsiDeclDbLibrary.cc \
|
||||
gsiDeclDbManager.cc \
|
||||
gsiDeclDbMatrix.cc \
|
||||
gsiDeclDbMetaInfo.cc \
|
||||
gsiDeclDbPath.cc \
|
||||
gsiDeclDbPoint.cc \
|
||||
gsiDeclDbPolygon.cc \
|
||||
|
|
|
|||
|
|
@ -356,7 +356,7 @@ CellMapping::do_create_missing_mapping (db::Layout &layout_a, const db::Layout &
|
|||
&& (! exclude_cells || exclude_cells->find (*b) == exclude_cells->end ())
|
||||
&& (! include_cells || include_cells->find (*b) != include_cells->end ())) {
|
||||
|
||||
db::cell_index_type new_cell = layout_a.add_cell (layout_b.cell_name (*b));
|
||||
db::cell_index_type new_cell = layout_a.add_cell (layout_b, *b);
|
||||
new_cells.push_back (new_cell);
|
||||
new_cells_b.push_back (*b);
|
||||
|
||||
|
|
|
|||
|
|
@ -275,6 +275,7 @@ VariantsCollectorBase::separate_variants (db::Layout &layout, db::Cell &top_cell
|
|||
var_name += "$VAR" + tl::to_string (index);
|
||||
|
||||
ci_var = layout.add_cell (var_name.c_str ());
|
||||
layout.add_meta_info (ci_var, layout.begin_meta (*c), layout.end_meta (*c));
|
||||
copy_shapes (layout, ci_var, *c);
|
||||
|
||||
// a new entry for the variant
|
||||
|
|
|
|||
|
|
@ -556,7 +556,7 @@ make_clip_variants (const db::Layout &layout,
|
|||
for (std::map <std::pair <db::cell_index_type, db::Box>, db::cell_index_type>::iterator v = variants.begin (); v != variants.end (); ++v) {
|
||||
if (v->first.second != layout.cell (v->first.first).bbox () || &layout != &target_layout) {
|
||||
// need for a new cell
|
||||
v->second = target_layout.add_cell (layout.cell_name (v->first.first));
|
||||
v->second = target_layout.add_cell (layout, v->first.first);
|
||||
} else {
|
||||
v->second = v->first.first;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -201,7 +201,8 @@ ClipboardData::do_insert (db::Layout &layout, const db::ICplxTrans *trans, db::C
|
|||
cell_map.insert (std::make_pair (c->cell_index (), pc->cell_index ()));
|
||||
} else {
|
||||
// fallback: create a new cell
|
||||
cell_map.insert (std::make_pair (c->cell_index (), layout.add_cell (m_layout.cell_name (c->cell_index ()))));
|
||||
db::cell_index_type ci = layout.add_cell (m_layout, c->cell_index ());
|
||||
cell_map.insert (std::make_pair (c->cell_index (), ci));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
@ -217,7 +218,8 @@ ClipboardData::do_insert (db::Layout &layout, const db::ICplxTrans *trans, db::C
|
|||
cell_map.insert (std::make_pair (c->cell_index (), tc));
|
||||
}
|
||||
} else {
|
||||
cell_map.insert (std::make_pair (c->cell_index (), layout.add_cell (m_layout.cell_name (c->cell_index ()))));
|
||||
db::cell_index_type ci = layout.add_cell (m_layout, c->cell_index ());
|
||||
cell_map.insert (std::make_pair (c->cell_index (), ci));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -313,7 +315,7 @@ ClipboardData::cell_for_cell (const db::Layout &layout, db::cell_index_type cell
|
|||
return cm->second;
|
||||
}
|
||||
|
||||
db::cell_index_type target_cell_index = m_layout.add_cell (layout.cell_name (cell_index));
|
||||
db::cell_index_type target_cell_index = m_layout.add_cell (layout, cell_index);
|
||||
m_cell_index_map.insert (std::make_pair (cell_index, target_cell_index));
|
||||
|
||||
if (incomplete) {
|
||||
|
|
|
|||
|
|
@ -49,8 +49,8 @@ ColdProxy::cold_proxies_per_lib_name (const std::string &libname)
|
|||
}
|
||||
}
|
||||
|
||||
ColdProxy::ColdProxy (db::cell_index_type ci, db::Layout &layout, const ProxyContextInfo &info)
|
||||
: Cell (ci, layout), mp_context_info (new ProxyContextInfo (info))
|
||||
ColdProxy::ColdProxy (db::cell_index_type ci, db::Layout &layout, const LayoutOrCellContextInfo &info)
|
||||
: Cell (ci, layout), mp_context_info (new LayoutOrCellContextInfo (info))
|
||||
{
|
||||
if (! info.lib_name.empty ()) {
|
||||
tl::MutexLocker locker (&s_map_mutex);
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
namespace db
|
||||
{
|
||||
|
||||
struct ProxyContextInfo;
|
||||
struct LayoutOrCellContextInfo;
|
||||
|
||||
/**
|
||||
* @brief A cell specialization: a cold proxy representing a library or PCell which has gone out of scope
|
||||
|
|
@ -53,7 +53,7 @@ public:
|
|||
*
|
||||
* Creates a cold proxy represented by the ProxyContextInfo data.
|
||||
*/
|
||||
ColdProxy (db::cell_index_type ci, db::Layout &layout, const ProxyContextInfo &info);
|
||||
ColdProxy (db::cell_index_type ci, db::Layout &layout, const LayoutOrCellContextInfo &info);
|
||||
|
||||
/**
|
||||
* @brief The destructor
|
||||
|
|
@ -68,7 +68,7 @@ public:
|
|||
/**
|
||||
* @brief Get the library id
|
||||
*/
|
||||
const ProxyContextInfo &context_info () const
|
||||
const LayoutOrCellContextInfo &context_info () const
|
||||
{
|
||||
return *mp_context_info;
|
||||
}
|
||||
|
|
@ -102,7 +102,7 @@ public:
|
|||
virtual std::string get_qualified_name () const;
|
||||
|
||||
private:
|
||||
ProxyContextInfo *mp_context_info;
|
||||
LayoutOrCellContextInfo *mp_context_info;
|
||||
|
||||
ColdProxy (const ColdProxy &d);
|
||||
ColdProxy &operator= (const ColdProxy &d);
|
||||
|
|
|
|||
|
|
@ -384,6 +384,8 @@ struct DetectTagEdgeSink
|
|||
DetectTagEdgeSink (int tag)
|
||||
: fail_tag (tag), result (true) { }
|
||||
|
||||
virtual void put (const db::Edge &) { }
|
||||
|
||||
virtual void put (const db::Edge &, int tag)
|
||||
{
|
||||
if (tag == fail_tag) {
|
||||
|
|
|
|||
|
|
@ -258,12 +258,12 @@ private:
|
|||
// -----------------------------------------------------------------
|
||||
// Implementation of the ProxyContextInfo class
|
||||
|
||||
ProxyContextInfo
|
||||
ProxyContextInfo::deserialize (std::vector<std::string>::const_iterator from, std::vector<std::string>::const_iterator to)
|
||||
LayoutOrCellContextInfo
|
||||
LayoutOrCellContextInfo::deserialize (std::vector<std::string>::const_iterator from, std::vector<std::string>::const_iterator to)
|
||||
{
|
||||
ProxyContextInfo info;
|
||||
LayoutOrCellContextInfo info;
|
||||
|
||||
for (std::vector<std::string>::const_iterator i = from; i != to; ++i) {
|
||||
for (auto i = from; i != to; ++i) {
|
||||
|
||||
tl::Extractor ex (i->c_str ());
|
||||
|
||||
|
|
@ -290,6 +290,20 @@ ProxyContextInfo::deserialize (std::vector<std::string>::const_iterator from, st
|
|||
|
||||
info.cell_name = ex.skip ();
|
||||
|
||||
} else if (ex.test ("META(")) {
|
||||
|
||||
std::pair<std::string, std::pair<tl::Variant, std::string> > vv;
|
||||
|
||||
ex.read_word_or_quoted (vv.first);
|
||||
if (ex.test (",")) {
|
||||
ex.read_word_or_quoted (vv.second.second);
|
||||
}
|
||||
ex.test (")");
|
||||
ex.test ("=");
|
||||
ex.read (vv.second.first);
|
||||
|
||||
info.meta_info.insert(vv);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -298,12 +312,12 @@ ProxyContextInfo::deserialize (std::vector<std::string>::const_iterator from, st
|
|||
}
|
||||
|
||||
void
|
||||
ProxyContextInfo::serialize (std::vector<std::string> &strings)
|
||||
LayoutOrCellContextInfo::serialize (std::vector<std::string> &strings)
|
||||
{
|
||||
if (! lib_name.empty ()) {
|
||||
strings.push_back ("LIB=" + lib_name);
|
||||
}
|
||||
for (std::map<std::string, tl::Variant> ::const_iterator p = pcell_parameters.begin (); p != pcell_parameters.end (); ++p) {
|
||||
for (auto p = pcell_parameters.begin (); p != pcell_parameters.end (); ++p) {
|
||||
strings.push_back ("P(" + tl::to_word_or_quoted_string (p->first) + ")=" + p->second.to_parsable_string ());
|
||||
}
|
||||
if (! pcell_name.empty ()) {
|
||||
|
|
@ -312,6 +326,32 @@ ProxyContextInfo::serialize (std::vector<std::string> &strings)
|
|||
if (! cell_name.empty ()) {
|
||||
strings.push_back ("CELL=" + cell_name);
|
||||
}
|
||||
|
||||
std::string mv;
|
||||
for (auto m = meta_info.begin (); m != meta_info.end (); ++m) {
|
||||
mv.clear ();
|
||||
mv += "META(";
|
||||
mv += tl::to_word_or_quoted_string (m->first);
|
||||
if (! m->second.second.empty ()) {
|
||||
mv += ",";
|
||||
mv += tl::to_word_or_quoted_string (m->second.second);
|
||||
}
|
||||
mv += ")=";
|
||||
mv += m->second.first.to_parsable_string ();
|
||||
strings.push_back (mv);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
LayoutOrCellContextInfo::has_proxy_info () const
|
||||
{
|
||||
return !pcell_name.empty () || !lib_name.empty ();
|
||||
}
|
||||
|
||||
bool
|
||||
LayoutOrCellContextInfo::has_meta_info () const
|
||||
{
|
||||
return !meta_info.empty ();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
|
@ -481,7 +521,13 @@ Layout::operator= (const Layout &d)
|
|||
}
|
||||
|
||||
m_dbu = d.m_dbu;
|
||||
|
||||
m_meta_info = d.m_meta_info;
|
||||
m_meta_info_by_cell = d.m_meta_info_by_cell;
|
||||
m_meta_info_names = d.m_meta_info_names;
|
||||
m_meta_info_name_map = d.m_meta_info_name_map;
|
||||
|
||||
m_tech_name = d.m_tech_name;
|
||||
|
||||
}
|
||||
return *this;
|
||||
|
|
@ -593,7 +639,7 @@ Layout::set_technology_name (const std::string &tech)
|
|||
if (! pn.first) {
|
||||
|
||||
// substitute by a cold proxy
|
||||
db::ProxyContextInfo info;
|
||||
db::LayoutOrCellContextInfo info;
|
||||
get_context_info (ci, info);
|
||||
create_cold_proxy_as (info, ci);
|
||||
|
||||
|
|
@ -606,7 +652,7 @@ Layout::set_technology_name (const std::string &tech)
|
|||
if (! old_pcell_decl || ! new_pcell_decl) {
|
||||
|
||||
// substitute by a cold proxy
|
||||
db::ProxyContextInfo info;
|
||||
db::LayoutOrCellContextInfo info;
|
||||
get_context_info (ci, info);
|
||||
create_cold_proxy_as (info, ci);
|
||||
|
||||
|
|
@ -633,7 +679,7 @@ Layout::set_technology_name (const std::string &tech)
|
|||
if (! cn.first) {
|
||||
|
||||
// unlink this proxy: substitute by a cold proxy
|
||||
db::ProxyContextInfo info;
|
||||
db::LayoutOrCellContextInfo info;
|
||||
get_context_info (ci, info);
|
||||
create_cold_proxy_as (info, ci);
|
||||
|
||||
|
|
@ -650,7 +696,7 @@ Layout::set_technology_name (const std::string &tech)
|
|||
db::cell_index_type ci = (*lp)->Cell::cell_index ();
|
||||
|
||||
// substitute by a cold proxy
|
||||
db::ProxyContextInfo info;
|
||||
db::LayoutOrCellContextInfo info;
|
||||
get_context_info (ci, info);
|
||||
create_cold_proxy_as (info, ci);
|
||||
|
||||
|
|
@ -1204,6 +1250,11 @@ Layout::take_cell (cell_index_type ci)
|
|||
|
||||
m_cell_ptrs [ci] = 0;
|
||||
|
||||
auto mi = m_meta_info_by_cell.find (ci);
|
||||
if (mi != m_meta_info_by_cell.end ()) {
|
||||
m_meta_info_by_cell.erase (mi);
|
||||
}
|
||||
|
||||
// Using free cell indices does have one significant drawback:
|
||||
// The cellview references cannot be uniquely classified as being invalid - because the
|
||||
// ID might be reused. This causes problems, when a cell is being deleted and subsequently a
|
||||
|
|
@ -1252,7 +1303,24 @@ Layout::uniquify_cell_name (const char *name) const
|
|||
}
|
||||
}
|
||||
|
||||
cell_index_type
|
||||
cell_index_type
|
||||
Layout::add_cell (const db::Layout &other, db::cell_index_type ci)
|
||||
{
|
||||
cell_index_type ci_new = add_cell (other.cell_name (ci));
|
||||
cell (ci_new).set_ghost_cell (other.cell (ci).is_ghost_cell ());
|
||||
|
||||
if (&other == this) {
|
||||
add_meta_info (ci_new, other.begin_meta (ci), other.end_meta (ci));
|
||||
} else {
|
||||
for (auto m = other.begin_meta (ci); m != other.end_meta (ci); ++m) {
|
||||
add_meta_info (ci_new, meta_info_name_id (other.meta_info_name (m->first)), m->second);
|
||||
}
|
||||
}
|
||||
|
||||
return ci_new;
|
||||
}
|
||||
|
||||
cell_index_type
|
||||
Layout::add_cell (const char *name)
|
||||
{
|
||||
std::string b;
|
||||
|
|
@ -1748,6 +1816,58 @@ Layout::do_update ()
|
|||
delete pr;
|
||||
}
|
||||
|
||||
static Layout::meta_info_map s_empty_meta;
|
||||
|
||||
Layout::meta_info_iterator
|
||||
Layout::begin_meta (db::cell_index_type ci) const
|
||||
{
|
||||
auto m = m_meta_info_by_cell.find (ci);
|
||||
if (m != m_meta_info_by_cell.end ()) {
|
||||
return m->second.begin ();
|
||||
} else {
|
||||
return s_empty_meta.begin ();
|
||||
}
|
||||
}
|
||||
|
||||
Layout::meta_info_iterator
|
||||
Layout::end_meta (db::cell_index_type ci) const
|
||||
{
|
||||
auto m = m_meta_info_by_cell.find (ci);
|
||||
if (m != m_meta_info_by_cell.end ()) {
|
||||
return m->second.end ();
|
||||
} else {
|
||||
return s_empty_meta.end ();
|
||||
}
|
||||
}
|
||||
|
||||
const std::string &
|
||||
Layout::meta_info_name (Layout::meta_info_name_id_type name_id) const
|
||||
{
|
||||
static std::string empty;
|
||||
return name_id < m_meta_info_names.size () ? m_meta_info_names[name_id] : empty;
|
||||
}
|
||||
|
||||
Layout::meta_info_name_id_type
|
||||
Layout::meta_info_name_id (const std::string &name)
|
||||
{
|
||||
auto n = m_meta_info_name_map.find (name);
|
||||
if (n != m_meta_info_name_map.end ()) {
|
||||
return n->second;
|
||||
} else {
|
||||
size_t id = m_meta_info_names.size ();
|
||||
m_meta_info_names.push_back (name);
|
||||
m_meta_info_name_map.insert (std::make_pair (name, id));
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
Layout::meta_info_name_id_type
|
||||
Layout::meta_info_name_id (const std::string &name) const
|
||||
{
|
||||
auto n = m_meta_info_name_map.find (name);
|
||||
return n != m_meta_info_name_map.end () ? n->second : std::numeric_limits<meta_info_name_id_type>::max ();
|
||||
}
|
||||
|
||||
void
|
||||
Layout::clear_meta ()
|
||||
{
|
||||
|
|
@ -1755,42 +1875,79 @@ Layout::clear_meta ()
|
|||
}
|
||||
|
||||
void
|
||||
Layout::add_meta_info (const MetaInfo &i)
|
||||
Layout::add_meta_info (meta_info_name_id_type name_id, const MetaInfo &i)
|
||||
{
|
||||
for (meta_info::iterator m = m_meta_info.begin (); m != m_meta_info.end (); ++m) {
|
||||
if (m->name == i.name) {
|
||||
*m = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_meta_info.push_back (i);
|
||||
m_meta_info[name_id] = i;
|
||||
}
|
||||
|
||||
void
|
||||
Layout::remove_meta_info (const std::string &name)
|
||||
Layout::remove_meta_info (meta_info_name_id_type name_id)
|
||||
{
|
||||
for (meta_info::iterator m = m_meta_info.begin (); m != m_meta_info.end (); ++m) {
|
||||
if (m->name == name) {
|
||||
m_meta_info.erase (m);
|
||||
return;
|
||||
}
|
||||
m_meta_info.erase (name_id);
|
||||
}
|
||||
|
||||
const MetaInfo &
|
||||
Layout::meta_info (meta_info_name_id_type name_id) const
|
||||
{
|
||||
auto n = m_meta_info.find (name_id);
|
||||
static MetaInfo null_value;
|
||||
return n != m_meta_info.end () ? n->second : null_value;
|
||||
}
|
||||
|
||||
bool
|
||||
Layout::has_meta_info (meta_info_name_id_type name_id) const
|
||||
{
|
||||
return m_meta_info.find (name_id) != m_meta_info.end ();
|
||||
}
|
||||
|
||||
void
|
||||
Layout::clear_meta (db::cell_index_type ci)
|
||||
{
|
||||
m_meta_info_by_cell.erase (ci);
|
||||
}
|
||||
|
||||
void
|
||||
Layout::add_meta_info (db::cell_index_type ci, meta_info_name_id_type name_id, const MetaInfo &i)
|
||||
{
|
||||
m_meta_info_by_cell[ci][name_id] = i;
|
||||
}
|
||||
|
||||
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 (c != m_meta_info_by_cell.end ()) {
|
||||
c->second.erase (name_id);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string &
|
||||
Layout::meta_info_value (const std::string &name) const
|
||||
const MetaInfo &
|
||||
Layout::meta_info (db::cell_index_type ci, meta_info_name_id_type name_id) const
|
||||
{
|
||||
for (meta_info::const_iterator m = m_meta_info.begin (); m != m_meta_info.end (); ++m) {
|
||||
if (m->name == name) {
|
||||
return m->value;
|
||||
auto c = m_meta_info_by_cell.find (ci);
|
||||
if (c != m_meta_info_by_cell.end ()) {
|
||||
auto i = c->second.find (name_id);
|
||||
if (i != c->second.end ()) {
|
||||
return i->second;
|
||||
}
|
||||
}
|
||||
|
||||
static const std::string s_empty;
|
||||
return s_empty;
|
||||
static MetaInfo null_value;
|
||||
return null_value;
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
Layout::has_meta_info (db::cell_index_type ci, meta_info_name_id_type name_id) const
|
||||
{
|
||||
auto c = m_meta_info_by_cell.find (ci);
|
||||
if (c != m_meta_info_by_cell.end ()) {
|
||||
return c->second.find (name_id) != c->second.end ();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Layout::swap_layers (unsigned int a, unsigned int b)
|
||||
{
|
||||
tl_assert (m_layers.layer_state (a) != LayoutLayers::Free);
|
||||
|
|
@ -2369,10 +2526,85 @@ Layout::get_pcell_variant_cell (cell_index_type cell_index, const std::vector<tl
|
|||
|
||||
}
|
||||
|
||||
bool
|
||||
Layout::has_context_info () const
|
||||
{
|
||||
for (auto i = m_meta_info.begin (); i != m_meta_info.end (); ++i) {
|
||||
if (i->second.persisted) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
Layout::has_context_info (cell_index_type cell_index) const
|
||||
{
|
||||
auto c = m_meta_info_by_cell.find (cell_index);
|
||||
if (c != m_meta_info_by_cell.end ()) {
|
||||
for (auto i = c->second.begin (); i != c->second.end (); ++i) {
|
||||
if (i->second.persisted) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const db::Cell &cref = cell (cell_index);
|
||||
if (cref.is_proxy () && ! cref.is_top ()) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Layout::get_context_info (std::vector <std::string> &strings) const
|
||||
{
|
||||
LayoutOrCellContextInfo info;
|
||||
if (! get_context_info (info)) {
|
||||
return false;
|
||||
} else {
|
||||
info.serialize (strings);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Layout::get_context_info (LayoutOrCellContextInfo &info) const
|
||||
{
|
||||
for (auto i = m_meta_info.begin (); i != m_meta_info.end (); ++i) {
|
||||
if (i->second.persisted) {
|
||||
std::pair<tl::Variant, std::string> &mi = info.meta_info [m_meta_info_names [i->first] ];
|
||||
mi.first = i->second.value;
|
||||
mi.second = i->second.description;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Layout::fill_meta_info_from_context (std::vector <std::string>::const_iterator from, std::vector <std::string>::const_iterator to)
|
||||
{
|
||||
fill_meta_info_from_context (LayoutOrCellContextInfo::deserialize (from, to));
|
||||
}
|
||||
|
||||
void
|
||||
Layout::fill_meta_info_from_context (const LayoutOrCellContextInfo &context_info)
|
||||
{
|
||||
if (! context_info.meta_info.empty ()) {
|
||||
for (auto i = context_info.meta_info.begin (); i != context_info.meta_info.end (); ++i) {
|
||||
meta_info_name_id_type name_id = meta_info_name_id (i->first);
|
||||
m_meta_info [name_id] = MetaInfo (i->second.second, i->second.first, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Layout::get_context_info (cell_index_type cell_index, std::vector <std::string> &strings) const
|
||||
{
|
||||
ProxyContextInfo info;
|
||||
LayoutOrCellContextInfo info;
|
||||
if (! get_context_info (cell_index, info)) {
|
||||
return false;
|
||||
} else {
|
||||
|
|
@ -2382,8 +2614,22 @@ Layout::get_context_info (cell_index_type cell_index, std::vector <std::string>
|
|||
}
|
||||
|
||||
bool
|
||||
Layout::get_context_info (cell_index_type cell_index, ProxyContextInfo &info) const
|
||||
Layout::get_context_info (cell_index_type cell_index, LayoutOrCellContextInfo &info) const
|
||||
{
|
||||
bool any_meta = false;
|
||||
|
||||
auto cmi = m_meta_info_by_cell.find (cell_index);
|
||||
if (cmi != m_meta_info_by_cell.end ()) {
|
||||
for (auto i = cmi->second.begin (); i != cmi->second.end (); ++i) {
|
||||
if (i->second.persisted) {
|
||||
std::pair<tl::Variant, std::string> &mi = info.meta_info [m_meta_info_names [i->first] ];
|
||||
mi.first = i->second.value;
|
||||
mi.second = i->second.description;
|
||||
any_meta = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const db::Cell *cptr = &cell (cell_index);
|
||||
|
||||
const db::ColdProxy *cold_proxy = dynamic_cast <const db::ColdProxy *> (cptr);
|
||||
|
|
@ -2399,7 +2645,7 @@ Layout::get_context_info (cell_index_type cell_index, ProxyContextInfo &info) co
|
|||
|
||||
const db::Library *lib = db::LibraryManager::instance ().lib (lib_proxy->lib_id ());
|
||||
if (! lib) {
|
||||
return false; // abort
|
||||
return any_meta; // abort
|
||||
} else {
|
||||
|
||||
// one level of library indirection
|
||||
|
|
@ -2432,6 +2678,27 @@ Layout::get_context_info (cell_index_type cell_index, ProxyContextInfo &info) co
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Layout::fill_meta_info_from_context (cell_index_type cell_index, std::vector <std::string>::const_iterator from, std::vector <std::string>::const_iterator to)
|
||||
{
|
||||
fill_meta_info_from_context (cell_index, LayoutOrCellContextInfo::deserialize (from, to));
|
||||
}
|
||||
|
||||
void
|
||||
Layout::fill_meta_info_from_context (cell_index_type cell_index, const LayoutOrCellContextInfo &context_info)
|
||||
{
|
||||
if (! context_info.meta_info.empty ()) {
|
||||
|
||||
meta_info_map &mi = m_meta_info_by_cell [cell_index];
|
||||
|
||||
for (auto i = context_info.meta_info.begin (); i != context_info.meta_info.end (); ++i) {
|
||||
meta_info_name_id_type name_id = meta_info_name_id (i->first);
|
||||
mi [name_id] = MetaInfo (i->second.second, i->second.first, true);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Layout::restore_proxies (ImportLayerMapping *layer_mapping)
|
||||
{
|
||||
|
|
@ -2463,11 +2730,11 @@ Layout::recover_proxy_as (cell_index_type cell_index, std::vector <std::string>:
|
|||
return false;
|
||||
}
|
||||
|
||||
return recover_proxy_as (cell_index, ProxyContextInfo::deserialize (from, to), layer_mapping);
|
||||
return recover_proxy_as (cell_index, LayoutOrCellContextInfo::deserialize (from, to), layer_mapping);
|
||||
}
|
||||
|
||||
bool
|
||||
Layout::recover_proxy_as (cell_index_type cell_index, const ProxyContextInfo &info, ImportLayerMapping *layer_mapping)
|
||||
Layout::recover_proxy_as (cell_index_type cell_index, const LayoutOrCellContextInfo &info, ImportLayerMapping *layer_mapping)
|
||||
{
|
||||
if (! info.lib_name.empty ()) {
|
||||
|
||||
|
|
@ -2517,11 +2784,11 @@ Layout::recover_proxy (std::vector <std::string>::const_iterator from, std::vect
|
|||
return 0;
|
||||
}
|
||||
|
||||
return recover_proxy (ProxyContextInfo::deserialize (from, to));
|
||||
return recover_proxy (LayoutOrCellContextInfo::deserialize (from, to));
|
||||
}
|
||||
|
||||
db::Cell *
|
||||
Layout::recover_proxy (const ProxyContextInfo &info)
|
||||
Layout::recover_proxy (const LayoutOrCellContextInfo &info)
|
||||
{
|
||||
if (! info.lib_name.empty ()) {
|
||||
|
||||
|
|
@ -2549,7 +2816,7 @@ Layout::recover_proxy (const ProxyContextInfo &info)
|
|||
}
|
||||
|
||||
db::Cell *
|
||||
Layout::recover_proxy_no_lib (const ProxyContextInfo &info)
|
||||
Layout::recover_proxy_no_lib (const LayoutOrCellContextInfo &info)
|
||||
{
|
||||
if (! info.pcell_name.empty ()) {
|
||||
|
||||
|
|
@ -2646,7 +2913,7 @@ Layout::get_lib_proxy (Library *lib, cell_index_type cell_index)
|
|||
}
|
||||
|
||||
cell_index_type
|
||||
Layout::create_cold_proxy (const db::ProxyContextInfo &info)
|
||||
Layout::create_cold_proxy (const db::LayoutOrCellContextInfo &info)
|
||||
{
|
||||
// create a new unique name
|
||||
std::string b;
|
||||
|
|
@ -2677,7 +2944,7 @@ Layout::create_cold_proxy (const db::ProxyContextInfo &info)
|
|||
}
|
||||
|
||||
void
|
||||
Layout::create_cold_proxy_as (const db::ProxyContextInfo &info, cell_index_type target_cell_index)
|
||||
Layout::create_cold_proxy_as (const db::LayoutOrCellContextInfo &info, cell_index_type target_cell_index)
|
||||
{
|
||||
tl_assert (m_cell_ptrs [target_cell_index] != 0);
|
||||
|
||||
|
|
|
|||
|
|
@ -417,15 +417,19 @@ public:
|
|||
/**
|
||||
* @brief A binary object representing context information for regenerating library proxies and PCells
|
||||
*/
|
||||
struct DB_PUBLIC ProxyContextInfo
|
||||
struct DB_PUBLIC LayoutOrCellContextInfo
|
||||
{
|
||||
std::string lib_name;
|
||||
std::string cell_name;
|
||||
std::string pcell_name;
|
||||
std::map<std::string, tl::Variant> pcell_parameters;
|
||||
std::map<std::string, std::pair<tl::Variant, std::string> > meta_info;
|
||||
|
||||
static ProxyContextInfo deserialize (std::vector<std::string>::const_iterator from, std::vector<std::string>::const_iterator to);
|
||||
static LayoutOrCellContextInfo deserialize (std::vector<std::string>::const_iterator from, std::vector<std::string>::const_iterator to);
|
||||
void serialize (std::vector<std::string> &strings);
|
||||
|
||||
bool has_proxy_info () const;
|
||||
bool has_meta_info () const;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -465,8 +469,9 @@ public:
|
|||
typedef pcell_name_map::const_iterator pcell_iterator;
|
||||
typedef std::map<std::pair<lib_id_type, cell_index_type>, cell_index_type> lib_proxy_map;
|
||||
typedef LayerIterator layer_iterator;
|
||||
typedef std::vector<MetaInfo> meta_info;
|
||||
typedef meta_info::const_iterator meta_info_iterator;
|
||||
typedef size_t meta_info_name_id_type;
|
||||
typedef std::map<meta_info_name_id_type, MetaInfo> meta_info_map;
|
||||
typedef meta_info_map::const_iterator meta_info_iterator;
|
||||
|
||||
/**
|
||||
* @brief A helper functor to compare "const char *" by the content
|
||||
|
|
@ -756,6 +761,14 @@ public:
|
|||
*/
|
||||
cell_index_type add_cell (const char *name = 0);
|
||||
|
||||
/**
|
||||
* @brief Adds a cell using another cell as a template
|
||||
*
|
||||
* This method will use the name of the other cell and initialize the
|
||||
* new cell with the meta info from the other cell.
|
||||
*/
|
||||
cell_index_type add_cell (const db::Layout &other, db::cell_index_type ci);
|
||||
|
||||
/**
|
||||
* @brief Add a cell without a name
|
||||
*
|
||||
|
|
@ -1014,27 +1027,69 @@ public:
|
|||
/**
|
||||
* @brief Creates a cold proxy representing the given context information
|
||||
*/
|
||||
cell_index_type create_cold_proxy (const db::ProxyContextInfo &info);
|
||||
cell_index_type create_cold_proxy (const db::LayoutOrCellContextInfo &info);
|
||||
|
||||
/**
|
||||
* @brief Subsitutes the given cell by a cold proxy representing the given context information
|
||||
*/
|
||||
void create_cold_proxy_as (const db::ProxyContextInfo &info, cell_index_type cell_index);
|
||||
void create_cold_proxy_as (const db::LayoutOrCellContextInfo &info, cell_index_type cell_index);
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether layout context info is provided / needed
|
||||
*/
|
||||
bool has_context_info() const;
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether layout context info is provided / needed
|
||||
*/
|
||||
bool has_context_info(cell_index_type cell_index) const;
|
||||
|
||||
/**
|
||||
* @brief Get the context information for the layout (for writing into a file)
|
||||
*
|
||||
* The context information is a sequence of strings which is pushed onto the given
|
||||
* vector. It can be used to fill meta information with fill_meta_info_from_context.
|
||||
*/
|
||||
bool get_context_info (std::vector <std::string> &strings) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the context information as a binary object
|
||||
*/
|
||||
bool get_context_info (LayoutOrCellContextInfo &context_info) const;
|
||||
|
||||
/**
|
||||
* @brief Fills the layout's meta information from the context
|
||||
*/
|
||||
void fill_meta_info_from_context (std::vector <std::string>::const_iterator from, std::vector <std::string>::const_iterator to);
|
||||
|
||||
/**
|
||||
* @brief Fills the layout's meta information from the binary context
|
||||
*/
|
||||
void fill_meta_info_from_context (const LayoutOrCellContextInfo &context_info);
|
||||
|
||||
/**
|
||||
* @brief Get the context information for a given cell (for writing into a file)
|
||||
*
|
||||
* The context information is a sequence of strings which is pushed onto the given
|
||||
* vector. It can be used to recover a respective proxy cell with the recover_proxy method.
|
||||
* If the given cell is not a valid proxy or library references are missing, the method
|
||||
* will return false.
|
||||
* vector. It can be used to recover a respective proxy cell with the recover_proxy method
|
||||
* or to fill meta information using fill_meta_info_from_context.
|
||||
*/
|
||||
bool get_context_info (cell_index_type cell_index, std::vector <std::string> &context_info) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the context information as a binary object
|
||||
*/
|
||||
bool get_context_info (cell_index_type cell_index, ProxyContextInfo &context_info) const;
|
||||
bool get_context_info (cell_index_type cell_index, LayoutOrCellContextInfo &context_info) const;
|
||||
|
||||
/**
|
||||
* @brief Fills the layout's meta information from the context
|
||||
*/
|
||||
void fill_meta_info_from_context (cell_index_type cell_index, std::vector <std::string>::const_iterator from, std::vector <std::string>::const_iterator to);
|
||||
|
||||
/**
|
||||
* @brief Fills the layout's meta information from the binary context
|
||||
*/
|
||||
void fill_meta_info_from_context (cell_index_type cell_index, const LayoutOrCellContextInfo &context_info);
|
||||
|
||||
/**
|
||||
* @brief Recover a proxy cell from the given context info.
|
||||
|
|
@ -1050,7 +1105,7 @@ public:
|
|||
/**
|
||||
* @brief Recover a proxy cell from the given binary context info object.
|
||||
*/
|
||||
db::Cell *recover_proxy (const ProxyContextInfo &context_info);
|
||||
db::Cell *recover_proxy (const LayoutOrCellContextInfo &context_info);
|
||||
|
||||
/**
|
||||
* @brief Recover a proxy cell from the given context info.
|
||||
|
|
@ -1072,7 +1127,7 @@ public:
|
|||
*
|
||||
* See the string-based version of "recover_proxy_as" for details.
|
||||
*/
|
||||
bool recover_proxy_as (cell_index_type cell_index, const ProxyContextInfo &context_info, ImportLayerMapping *layer_mapping = 0);
|
||||
bool recover_proxy_as (cell_index_type cell_index, const LayoutOrCellContextInfo &context_info, ImportLayerMapping *layer_mapping = 0);
|
||||
|
||||
/**
|
||||
* @brief Restores proxies as far as possible
|
||||
|
|
@ -1812,6 +1867,31 @@ public:
|
|||
return m_meta_info.end ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Delivers the meta information (begin iterator) per cell
|
||||
*/
|
||||
meta_info_iterator begin_meta (db::cell_index_type ci) const;
|
||||
|
||||
/**
|
||||
* @brief Delivers the meta information (end iterator) per cell
|
||||
*/
|
||||
meta_info_iterator end_meta (db::cell_index_type ci) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the meta informatio name by ID
|
||||
*/
|
||||
const std::string &meta_info_name (meta_info_name_id_type name_id) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the meta information name ID for a specific string
|
||||
*/
|
||||
meta_info_name_id_type meta_info_name_id (const std::string &name) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the meta information name ID for a specific string (const version)
|
||||
*/
|
||||
meta_info_name_id_type meta_info_name_id (const std::string &name);
|
||||
|
||||
/**
|
||||
* @brief Clears the meta information
|
||||
*/
|
||||
|
|
@ -1819,22 +1899,146 @@ public:
|
|||
|
||||
/**
|
||||
* @brief Adds meta information
|
||||
* The given meta information object is appended at the end of the meta information list.
|
||||
* The given meta information object is added to the meta information list.
|
||||
* If a meta info object with the same name already exists it is overwritten.
|
||||
*/
|
||||
void add_meta_info (const MetaInfo &i);
|
||||
void add_meta_info (const std::string &name, const MetaInfo &i)
|
||||
{
|
||||
add_meta_info (meta_info_name_id (name), i);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds meta information (variant with name ID)
|
||||
*/
|
||||
void add_meta_info (meta_info_name_id_type name_id, const MetaInfo &i);
|
||||
|
||||
/**
|
||||
* @brief Adds meta information from a sequence
|
||||
*/
|
||||
template <class I>
|
||||
void add_meta_info (const I &b, const I &e)
|
||||
{
|
||||
for (I i = b; i != e; ++i) {
|
||||
m_meta_info.insert (b, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes the meta information object with the given name
|
||||
* The method will do nothing if no object with that name exists.
|
||||
*/
|
||||
void remove_meta_info (const std::string &name);
|
||||
void remove_meta_info (const std::string &name)
|
||||
{
|
||||
remove_meta_info (meta_info_name_id (name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes the meta information object with the given name ID
|
||||
*/
|
||||
void remove_meta_info (meta_info_name_id_type name_id);
|
||||
|
||||
/**
|
||||
* @brief Gets the meta info value for a meta info object with the given name
|
||||
* If no object with that name exists, an empty string is returned
|
||||
*/
|
||||
const std::string &meta_info_value (const std::string &name) const;
|
||||
const MetaInfo &meta_info (const std::string &name) const
|
||||
{
|
||||
return meta_info (meta_info_name_id (name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the meta info value for a meta info object with the given name ID
|
||||
*/
|
||||
const MetaInfo &meta_info (meta_info_name_id_type name_id) const;
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether a meta info with the given name is present
|
||||
*/
|
||||
bool has_meta_info (const std::string &name) const
|
||||
{
|
||||
return has_meta_info (meta_info_name_id (name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether a meta info with the given name is present
|
||||
*/
|
||||
bool has_meta_info (meta_info_name_id_type name_id) const;
|
||||
|
||||
/**
|
||||
* @brief Clears the meta information for a specific cell
|
||||
*/
|
||||
void clear_meta (db::cell_index_type ci);
|
||||
|
||||
/**
|
||||
* @brief Adds meta information for a given cell
|
||||
* The given meta information object is to the meta information list for the given cell.
|
||||
* If a meta info object with the same name already exists it is overwritten.
|
||||
*/
|
||||
void add_meta_info (db::cell_index_type ci, const std::string &name, const MetaInfo &i)
|
||||
{
|
||||
add_meta_info (ci, meta_info_name_id (name), i);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds meta information for a given cell (version with name ID)
|
||||
* The given meta information object is appended at the end of the meta information list.
|
||||
* If a meta info object with the same name already exists it is overwritten.
|
||||
*/
|
||||
void add_meta_info (db::cell_index_type ci, meta_info_name_id_type name_id, const MetaInfo &i);
|
||||
|
||||
/**
|
||||
* @brief Adds meta information from a sequence
|
||||
*/
|
||||
template <class I>
|
||||
void add_meta_info (db::cell_index_type ci, const I &b, const I &e)
|
||||
{
|
||||
for (I i = b; i != e; ++i) {
|
||||
m_meta_info_by_cell [ci].insert (b, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether a meta info with the given name is present for the given cell
|
||||
*/
|
||||
bool has_meta_info (db::cell_index_type ci, const std::string &name) const
|
||||
{
|
||||
return has_meta_info (ci, meta_info_name_id (name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether a meta info with the given name is present for the given cell
|
||||
*/
|
||||
bool has_meta_info (db::cell_index_type ci, meta_info_name_id_type name_id) const;
|
||||
|
||||
/**
|
||||
* @brief Removes the meta information object with the given name from the given cell
|
||||
* The method will do nothing if no object with that name exists.
|
||||
*/
|
||||
void remove_meta_info (db::cell_index_type ci, const std::string &name)
|
||||
{
|
||||
remove_meta_info (ci, meta_info_name_id (name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes the meta information object with the given name ID from the given cell
|
||||
* The method will do nothing if no object with that name exists.
|
||||
*/
|
||||
void remove_meta_info (db::cell_index_type ci, meta_info_name_id_type name_id);
|
||||
|
||||
/**
|
||||
* @brief Gets the meta info value for a meta info object with the given name for the given cell
|
||||
* If no object with that name exists, an empty string is returned
|
||||
*/
|
||||
const MetaInfo &meta_info (db::cell_index_type ci, const std::string &name) const
|
||||
{
|
||||
return meta_info (ci, meta_info_name_id (name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the meta info value for a meta info object with the given name ID for the given cell
|
||||
* If no object with that name exists, an empty string is returned
|
||||
*/
|
||||
const MetaInfo &meta_info (db::cell_index_type ci, meta_info_name_id_type name_id) const;
|
||||
|
||||
/**
|
||||
* @brief This event is triggered when the technology changes
|
||||
|
|
@ -1876,7 +2080,11 @@ private:
|
|||
lib_proxy_map m_lib_proxy_map;
|
||||
bool m_do_cleanup;
|
||||
bool m_editable;
|
||||
meta_info m_meta_info;
|
||||
std::map<std::string, meta_info_name_id_type> m_meta_info_name_map;
|
||||
std::vector<std::string> m_meta_info_names;
|
||||
meta_info_map m_meta_info;
|
||||
std::map<db::cell_index_type, meta_info_map> m_meta_info_by_cell;
|
||||
|
||||
std::string m_tech_name;
|
||||
tl::Mutex m_lock;
|
||||
|
||||
|
|
@ -1920,7 +2128,7 @@ private:
|
|||
/**
|
||||
* @brief Recovers a proxy without considering the library from context_info
|
||||
*/
|
||||
db::Cell *recover_proxy_no_lib (const ProxyContextInfo &context_info);
|
||||
db::Cell *recover_proxy_no_lib (const LayoutOrCellContextInfo &context_info);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ merge_layouts (db::Layout &target,
|
|||
std::map<db::cell_index_type, db::cell_index_type> new_cell_mapping;
|
||||
for (std::set<db::cell_index_type>::const_iterator c = all_cells_to_copy.begin (); c != all_cells_to_copy.end (); ++c) {
|
||||
if (cell_mapping.find (*c) == cell_mapping.end ()) {
|
||||
new_cell_mapping.insert (std::make_pair (*c, target.add_cell (source.cell_name (*c))));
|
||||
new_cell_mapping.insert (std::make_pair (*c, target.add_cell (source, *c)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ Library::remap_to (db::Library *other)
|
|||
if (! pn.first) {
|
||||
|
||||
// substitute by a cold proxy
|
||||
db::ProxyContextInfo info;
|
||||
db::LayoutOrCellContextInfo info;
|
||||
r->first->get_context_info (ci, info);
|
||||
r->first->create_cold_proxy_as (info, ci);
|
||||
|
||||
|
|
@ -216,7 +216,7 @@ Library::remap_to (db::Library *other)
|
|||
if (! old_pcell_decl || ! new_pcell_decl) {
|
||||
|
||||
// substitute by a cold proxy
|
||||
db::ProxyContextInfo info;
|
||||
db::LayoutOrCellContextInfo info;
|
||||
r->first->get_context_info (ci, info);
|
||||
r->first->create_cold_proxy_as (info, ci);
|
||||
|
||||
|
|
@ -254,7 +254,7 @@ Library::remap_to (db::Library *other)
|
|||
if (! cn.first) {
|
||||
|
||||
// substitute by a cold proxy
|
||||
db::ProxyContextInfo info;
|
||||
db::LayoutOrCellContextInfo info;
|
||||
r->first->get_context_info (ci, info);
|
||||
r->first->create_cold_proxy_as (info, ci);
|
||||
|
||||
|
|
|
|||
|
|
@ -31,31 +31,34 @@
|
|||
namespace db
|
||||
{
|
||||
|
||||
// Switch for version-agnostic code
|
||||
#define KLAYOUT_META_INFO_V2
|
||||
|
||||
/**
|
||||
* @brief A structure describing the meta information from the reader
|
||||
*
|
||||
* In the meta information block, the reader provides additional information
|
||||
* about the file and content etc.
|
||||
* "name" is a unique name that can be used to identify the information.
|
||||
* "description" is a "speaking" description of the information.
|
||||
* "value" is the value of the specific part of meta information.
|
||||
*/
|
||||
struct DB_PUBLIC MetaInfo
|
||||
{
|
||||
MetaInfo (const std::string &n, const std::string &d, const std::string &v)
|
||||
: name (n), description (d), value (v)
|
||||
MetaInfo (const std::string &d, const tl::Variant &v, bool p = false)
|
||||
: description (d), value (v), persisted (p)
|
||||
{
|
||||
// .. nothing else ..
|
||||
}
|
||||
|
||||
MetaInfo ()
|
||||
: persisted (false)
|
||||
{
|
||||
// .. nothing else ..
|
||||
}
|
||||
|
||||
std::string name;
|
||||
std::string description;
|
||||
std::string value;
|
||||
tl::Variant value;
|
||||
bool persisted;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -63,7 +66,6 @@ struct DB_PUBLIC MetaInfo
|
|||
*/
|
||||
inline void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const MetaInfo &v, bool no_self, void *parent)
|
||||
{
|
||||
db::mem_stat (stat, purpose, cat, v.name, no_self, parent);
|
||||
db::mem_stat (stat, purpose, cat, v.description, no_self, parent);
|
||||
db::mem_stat (stat, purpose, cat, v.value, no_self, parent);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,9 +20,8 @@
|
|||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "gsiDecl.h"
|
||||
#include "gsiDeclDbMetaInfo.h"
|
||||
|
||||
#include "gsiDeclDbHelpers.h"
|
||||
#include "dbLayout.h"
|
||||
|
|
@ -984,6 +983,58 @@ static db::Layout *layout (db::Cell *cell)
|
|||
return cell->layout ();
|
||||
}
|
||||
|
||||
static void cell_clear_meta_info (db::Cell *cell)
|
||||
{
|
||||
if (cell->layout ()) {
|
||||
cell->layout ()->clear_meta (cell->cell_index ());
|
||||
}
|
||||
}
|
||||
|
||||
static void cell_remove_meta_info (db::Cell *cell, const std::string &name)
|
||||
{
|
||||
if (cell->layout ()) {
|
||||
cell->layout ()->remove_meta_info (cell->cell_index (), name);
|
||||
}
|
||||
}
|
||||
|
||||
static void cell_add_meta_info (db::Cell *cell, const MetaInfo &mi)
|
||||
{
|
||||
if (cell->layout ()) {
|
||||
cell->layout ()->add_meta_info (cell->cell_index (), mi.name, db::MetaInfo (mi.description, mi.value));
|
||||
}
|
||||
}
|
||||
|
||||
static const tl::Variant &cell_meta_info_value (db::Cell *cell, const std::string &name)
|
||||
{
|
||||
if (! cell->layout ()) {
|
||||
static tl::Variant null_value;
|
||||
return null_value;
|
||||
} else {
|
||||
return cell->layout ()->meta_info (cell->cell_index (), name).value;
|
||||
}
|
||||
}
|
||||
|
||||
static MetaInfo *cell_meta_info (db::Cell *cell, const std::string &name)
|
||||
{
|
||||
if (! cell->layout ()) {
|
||||
return 0;
|
||||
} else if (cell->layout ()->has_meta_info (cell->cell_index (), name)) {
|
||||
const db::MetaInfo &value = cell->layout ()->meta_info (cell->cell_index (), name);
|
||||
return new MetaInfo (name, value);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static gsi::MetaInfoIterator cell_each_meta_info (const db::Cell *cell)
|
||||
{
|
||||
if (! cell->layout ()) {
|
||||
return gsi::MetaInfoIterator ();
|
||||
} else {
|
||||
return gsi::MetaInfoIterator (cell->layout (), cell->layout ()->begin_meta (cell->cell_index ()), cell->layout ()->end_meta (cell->cell_index ()));
|
||||
}
|
||||
}
|
||||
|
||||
static bool cell_has_prop_id (const db::Cell *c)
|
||||
{
|
||||
return c->prop_id () != 0;
|
||||
|
|
@ -1780,6 +1831,47 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.23."
|
||||
) +
|
||||
gsi::method_ext ("add_meta_info", &cell_add_meta_info, gsi::arg ("info"),
|
||||
"@brief Adds meta information to the cell\n"
|
||||
"See \\LayoutMetaInfo for details about cells and meta information.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28.8."
|
||||
) +
|
||||
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"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28.8."
|
||||
) +
|
||||
gsi::method_ext ("remove_meta_info", &cell_remove_meta_info, gsi::arg ("name"),
|
||||
"@brief Removes meta information from the cell\n"
|
||||
"See \\LayoutMetaInfo for details about cells and meta information.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28.8."
|
||||
) +
|
||||
gsi::method_ext ("meta_info_value", &cell_meta_info_value, gsi::arg ("name"),
|
||||
"@brief Gets the meta information value for a given name\n"
|
||||
"See \\LayoutMetaInfo for details about cells and meta information.\n"
|
||||
"\n"
|
||||
"If no meta information with the given name exists, a nil value will be returned.\n"
|
||||
"A more generic version that delivers all fields of the meta information is \\meta_info.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28.8."
|
||||
) +
|
||||
gsi::factory_ext ("meta_info", &cell_meta_info, gsi::arg ("name"),
|
||||
"@brief Gets the meta information for a given name\n"
|
||||
"See \\LayoutMetaInfo for details about cells and meta information.\n"
|
||||
"\n"
|
||||
"If no meta information with the given name exists, a default object with empty fields will be returned.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28.8."
|
||||
) +
|
||||
gsi::iterator_ext ("each_meta_info", &cell_each_meta_info,
|
||||
"@brief Iterates over the meta information of the cell\n"
|
||||
"See \\LayoutMetaInfo for details about cells and meta information.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28.8."
|
||||
) +
|
||||
gsi::method_ext ("write", &write_simple, gsi::arg ("file_name"),
|
||||
"@brief Writes the cell to a layout file\n"
|
||||
"The format of the file will be determined from the file name. Only the cell and "
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
|
||||
#include "gsiDecl.h"
|
||||
#include "gsiDeclDbMetaInfo.h"
|
||||
#include "dbLayout.h"
|
||||
#include "dbClip.h"
|
||||
#include "dbRecursiveShapeIterator.h"
|
||||
|
|
@ -902,39 +903,30 @@ static db::Cell *create_cell4 (db::Layout *layout, const std::string &name, cons
|
|||
return &layout->cell (layout->get_lib_proxy (lib, lib_cell));
|
||||
}
|
||||
|
||||
static db::MetaInfo *layout_meta_info_ctor (const std::string &name, const std::string &value, const std::string &description)
|
||||
static void layout_add_meta_info (db::Layout *layout, const MetaInfo &mi)
|
||||
{
|
||||
return new db::MetaInfo (name, description, value);
|
||||
layout->add_meta_info (mi.name, db::MetaInfo (mi.description, mi.value));
|
||||
}
|
||||
|
||||
static void layout_meta_set_name (db::MetaInfo *mi, const std::string &n)
|
||||
static MetaInfo *layout_get_meta_info (db::Layout *layout, const std::string &name)
|
||||
{
|
||||
mi->name = n;
|
||||
if (layout->has_meta_info (name)) {
|
||||
const db::MetaInfo &value = layout->meta_info (name);
|
||||
return new MetaInfo (name, value);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const std::string &layout_meta_get_name (const db::MetaInfo *mi)
|
||||
static const tl::Variant &layout_get_meta_info_value (db::Layout *layout, const std::string &name)
|
||||
{
|
||||
return mi->name;
|
||||
const db::MetaInfo &value = layout->meta_info (name);
|
||||
return value.value;
|
||||
}
|
||||
|
||||
static void layout_meta_set_value (db::MetaInfo *mi, const std::string &n)
|
||||
static MetaInfoIterator layout_each_meta_info (const db::Layout *layout)
|
||||
{
|
||||
mi->value = n;
|
||||
}
|
||||
|
||||
static const std::string &layout_meta_get_value (const db::MetaInfo *mi)
|
||||
{
|
||||
return mi->value;
|
||||
}
|
||||
|
||||
static void layout_meta_set_description (db::MetaInfo *mi, const std::string &n)
|
||||
{
|
||||
mi->description = n;
|
||||
}
|
||||
|
||||
static const std::string &layout_meta_get_description (const db::MetaInfo *mi)
|
||||
{
|
||||
return mi->description;
|
||||
return MetaInfoIterator (layout, layout->begin_meta (), layout->end_meta ());
|
||||
}
|
||||
|
||||
static void scale_and_snap1 (db::Layout *layout, db::Cell &cell, db::Coord g, db::Coord m, db::Coord d)
|
||||
|
|
@ -997,45 +989,6 @@ static void move_tree_shapes3 (db::Layout *layout, db::Layout &source_layout, co
|
|||
db::move_shapes (*layout, source_layout, trans, cm.source_cells (), cm.table (), lm.table ());
|
||||
}
|
||||
|
||||
Class<db::MetaInfo> decl_LayoutMetaInfo ("db", "LayoutMetaInfo",
|
||||
gsi::constructor ("new", &layout_meta_info_ctor, gsi::arg ("name"), gsi::arg ("value"), gsi::arg ("description", std::string ()),
|
||||
"@brief Creates a layout meta info object\n"
|
||||
"@param name The name\n"
|
||||
"@param value The value\n"
|
||||
"@param description An optional description text\n"
|
||||
) +
|
||||
gsi::method_ext ("name", &layout_meta_get_name,
|
||||
"@brief Gets the name of the layout meta info object\n"
|
||||
) +
|
||||
gsi::method_ext ("name=", &layout_meta_set_name,
|
||||
"@brief Sets the name of the layout meta info object\n"
|
||||
) +
|
||||
gsi::method_ext ("value", &layout_meta_get_value,
|
||||
"@brief Gets the value of the layout meta info object\n"
|
||||
) +
|
||||
gsi::method_ext ("value=", &layout_meta_set_value,
|
||||
"@brief Sets the value of the layout meta info object\n"
|
||||
) +
|
||||
gsi::method_ext ("description", &layout_meta_get_description,
|
||||
"@brief Gets the description of the layout meta info object\n"
|
||||
) +
|
||||
gsi::method_ext ("description=", &layout_meta_set_description,
|
||||
"@brief Sets the description of the layout meta info object\n"
|
||||
),
|
||||
"@brief A piece of layout meta information\n"
|
||||
"Layout meta information is basically additional data that can be attached to a layout. "
|
||||
"Layout readers may generate meta information and some writers will add layout information to "
|
||||
"the layout object. Some writers will also read meta information to determine certain attributes.\n"
|
||||
"\n"
|
||||
"Multiple layout meta information objects can be attached to one layout using \\Layout#add_meta_info. "
|
||||
"Meta information is identified by a unique name and carries a string value plus an optional description string. "
|
||||
"The description string is for information only and is not evaluated by code.\n"
|
||||
"\n"
|
||||
"See also \\Layout#each_meta_info and \\Layout#meta_info_value and \\Layout#remove_meta_info"
|
||||
"\n"
|
||||
"This class has been introduced in version 0.25."
|
||||
);
|
||||
|
||||
static void dtransform (db::Layout *layout, const db::DTrans &trans)
|
||||
{
|
||||
db::CplxTrans dbu_trans (layout->dbu ());
|
||||
|
|
@ -1097,27 +1050,42 @@ Class<db::Layout> decl_Layout ("db", "Layout",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.27.9."
|
||||
) +
|
||||
gsi::method ("add_meta_info", &db::Layout::add_meta_info, gsi::arg ("info"),
|
||||
gsi::method_ext ("add_meta_info", &layout_add_meta_info, gsi::arg ("info"),
|
||||
"@brief Adds meta information to the layout\n"
|
||||
"See \\LayoutMetaInfo for details about layouts and meta information."
|
||||
"\n"
|
||||
"This method has been introduced in version 0.25."
|
||||
) +
|
||||
gsi::method ("remove_meta_info", &db::Layout::remove_meta_info, gsi::arg ("name"),
|
||||
gsi::method ("clear_meta_info", static_cast<void (db::Layout::*) ()> (&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 ("remove_meta_info", static_cast<void (db::Layout::*) (const std::string &name)> (&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."
|
||||
"\n"
|
||||
"This method has been introduced in version 0.25."
|
||||
) +
|
||||
gsi::method ("meta_info_value", &db::Layout::meta_info_value, gsi::arg ("name"),
|
||||
gsi::method_ext ("meta_info_value", &layout_get_meta_info_value, gsi::arg ("name"),
|
||||
"@brief Gets the meta information value for a given name\n"
|
||||
"See \\LayoutMetaInfo for details about layouts and meta information.\n"
|
||||
"\n"
|
||||
"If no meta information with the given name exists, an empty string will be returned.\n"
|
||||
"If no meta information with the given name exists, a nil value will be returned.\n"
|
||||
"A more generic version that delivers all fields of the meta information is \\meta_info.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.25."
|
||||
"This method has been introduced in version 0.25. Starting with version 0.28.8, the value is of variant type instead of string only.\n"
|
||||
) +
|
||||
gsi::iterator ("each_meta_info", &db::Layout::begin_meta, &db::Layout::end_meta,
|
||||
gsi::factory_ext ("meta_info", &layout_get_meta_info, gsi::arg ("name"),
|
||||
"@brief Gets the meta information for a given name\n"
|
||||
"See \\LayoutMetaInfo for details about layouts and meta information.\n"
|
||||
"\n"
|
||||
"If no meta information with the given name exists, nil is returned.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28.8.\n"
|
||||
) +
|
||||
gsi::iterator_ext ("each_meta_info", &layout_each_meta_info,
|
||||
"@brief Iterates over the meta information of the layout\n"
|
||||
"See \\LayoutMetaInfo for details about layouts and meta information.\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,168 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2023 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "gsiDecl.h"
|
||||
#include "gsiDeclDbMetaInfo.h"
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
||||
static MetaInfo *layout_meta_info_ctor (const std::string &name, const tl::Variant &value, const std::string &description, bool persisted)
|
||||
{
|
||||
return new MetaInfo (name, description, value, persisted);
|
||||
}
|
||||
|
||||
static void layout_meta_set_name (MetaInfo *mi, const std::string &n)
|
||||
{
|
||||
mi->name = n;
|
||||
}
|
||||
|
||||
static const std::string &layout_meta_get_name (const MetaInfo *mi)
|
||||
{
|
||||
return mi->name;
|
||||
}
|
||||
|
||||
static void layout_meta_set_value (MetaInfo *mi, const tl::Variant &n)
|
||||
{
|
||||
mi->value = n;
|
||||
}
|
||||
|
||||
static const tl::Variant &layout_meta_get_value (const MetaInfo *mi)
|
||||
{
|
||||
return mi->value;
|
||||
}
|
||||
|
||||
static void layout_meta_set_description (MetaInfo *mi, const std::string &n)
|
||||
{
|
||||
mi->description = n;
|
||||
}
|
||||
|
||||
static const std::string &layout_meta_get_description (const MetaInfo *mi)
|
||||
{
|
||||
return mi->description;
|
||||
}
|
||||
|
||||
static void layout_meta_set_persisted (MetaInfo *mi, bool f)
|
||||
{
|
||||
mi->persisted = f;
|
||||
}
|
||||
|
||||
static bool layout_meta_get_persisted (const MetaInfo *mi)
|
||||
{
|
||||
return mi->persisted;
|
||||
}
|
||||
|
||||
|
||||
Class<MetaInfo> decl_LayoutMetaInfo ("db", "LayoutMetaInfo",
|
||||
gsi::constructor ("new", &layout_meta_info_ctor, gsi::arg ("name"), gsi::arg ("value"), gsi::arg ("description", std::string ()), gsi::arg ("persisted", false),
|
||||
"@brief Creates a layout meta info object\n"
|
||||
"@param name The name\n"
|
||||
"@param value The value\n"
|
||||
"@param description An optional description text\n"
|
||||
"@param persisted If true, the meta information will be persisted in some file formats, like GDS2\n"
|
||||
"\n"
|
||||
"The 'persisted' attribute has been introduced in version 0.28.8.\n"
|
||||
) +
|
||||
gsi::method_ext ("name", &layout_meta_get_name,
|
||||
"@brief Gets the name of the layout meta info object\n"
|
||||
) +
|
||||
gsi::method_ext ("name=", &layout_meta_set_name, gsi::arg ("name"),
|
||||
"@brief Sets the name of the layout meta info object\n"
|
||||
) +
|
||||
gsi::method_ext ("value", &layout_meta_get_value,
|
||||
"@brief Gets the value of the layout meta info object\n"
|
||||
) +
|
||||
gsi::method_ext ("value=", &layout_meta_set_value, gsi::arg ("value"),
|
||||
"@brief Sets the value of the layout meta info object\n"
|
||||
) +
|
||||
gsi::method_ext ("description", &layout_meta_get_description,
|
||||
"@brief Gets the description of the layout meta info object\n"
|
||||
) +
|
||||
gsi::method_ext ("description=", &layout_meta_set_description, gsi::arg ("description"),
|
||||
"@brief Sets the description of the layout meta info object\n"
|
||||
) +
|
||||
gsi::method_ext ("is_persisted?", &layout_meta_get_persisted,
|
||||
"@brief Gets a value indicating whether the meta information will be persisted\n"
|
||||
"This predicate was introduced in version 0.28.8.\n"
|
||||
) +
|
||||
gsi::method_ext ("persisted=", &layout_meta_set_persisted, gsi::arg ("flag"),
|
||||
"@brief Sets a value indicating whether the meta information will be persisted\n"
|
||||
"This predicate was introduced in version 0.28.8.\n"
|
||||
),
|
||||
"@brief A piece of layout meta information\n"
|
||||
"Layout meta information is basically additional data that can be attached to a layout. "
|
||||
"Layout readers may generate meta information and some writers will add layout information to "
|
||||
"the layout object. Some writers will also read meta information to determine certain attributes.\n"
|
||||
"\n"
|
||||
"Multiple layout meta information objects can be attached to one layout using \\Layout#add_meta_info. "
|
||||
"Meta information is identified by a unique name and carries a string value plus an optional description string. "
|
||||
"The description string is for information only and is not evaluated by code.\n"
|
||||
"\n"
|
||||
"Meta information can be attached to the layout object and to cells. It is similar to "
|
||||
"user properties. The differences are:\n"
|
||||
"\n"
|
||||
"@ul\n"
|
||||
"@li Meta information is stored differently in GDS and OASIS files using the context information added "
|
||||
" by KLayout to annotated PCell or library cells too. Hence meta information does not pollute "
|
||||
" the standard user properties space. @/li\n"
|
||||
"@li The value of meta information can be complex serializable types such as lists, hashes and elementary "
|
||||
" objects such as \\Box or \\DBox. Scalar types include floats and booleans. @/li\n"
|
||||
"@li Meta information keys are strings and are supported also for GDS which only accepts integer number "
|
||||
" keys for user properties. @/li\n"
|
||||
"@/ul\n"
|
||||
"\n"
|
||||
"Elementary (serializable) objects are: \\Box, \\DBox, \\Edge, \\DEdge, \\EdgePair, \\DEdgePair, "
|
||||
"\\EdgePairs, \\Edges, \\LayerProperties, \\Matrix2d, \\Matrix3d, \\Path, \\DPath, \\Point, \\DPoint, "
|
||||
"\\Polygon, \\DPolygon, \\SimplePolygon, \\DSimplePolygon, \\Region, \\Text, \\DText, \\Texts, "
|
||||
"\\Trans, \\DTrans, \\CplxTrans, \\ICplxTrans, \\DCplxTrans, \\VCplxTrans, \\Vector, \\DVector "
|
||||
"(list may not be complete).\n"
|
||||
"\n"
|
||||
"KLayout itself also generates meta information with specific keys. "
|
||||
"For disambiguation, namespaces can be established by prefixing "
|
||||
"the key strings with some unique identifier in XML fashion, like a domain name - "
|
||||
"e.g. 'example.com:key'.\n"
|
||||
"\n"
|
||||
"@b Note: @/b only meta information marked with \\is_persisted? == true is stored in GDS or OASIS files. "
|
||||
"This is not the default setting, so you need to explicitly set that flag.\n"
|
||||
"\n"
|
||||
"See also \\Layout#each_meta_info, \\Layout#meta_info_value, \\Layout#meta_info and \\Layout#remove_meta_info as "
|
||||
"well as the corresponding \\Cell methods.\n"
|
||||
"\n"
|
||||
"An example of how to attach persisted meta information to a cell is here:\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"ly = RBA::Layout::new\n"
|
||||
"c1 = ly.create_cell(\"C1\")\n"
|
||||
"\n"
|
||||
"mi = RBA::LayoutMetaInfo::new(\"the-answer\", 42.0)\n"
|
||||
"mi.persisted = true\n"
|
||||
"c1.add_meta_info(mi)\n"
|
||||
"\n"
|
||||
"# will now hold this piece of meta information attached to cell 'C1':\n"
|
||||
"ly.write(\"to.gds\")\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"This class has been introduced in version 0.25 and was extended in version 0.28.8."
|
||||
);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2023 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _HDR_gsiDeclDbMetaInfo
|
||||
#define _HDR_gsiDeclDbMetaInfo
|
||||
|
||||
#include "dbLayout.h"
|
||||
#include "tlVariant.h"
|
||||
#include "tlObject.h"
|
||||
|
||||
#include <string>
|
||||
#include <iterator>
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
||||
struct MetaInfo
|
||||
{
|
||||
MetaInfo (const std::string &n, const std::string &d, const tl::Variant &v, bool p)
|
||||
: name (n), description (d), value (v), persisted (p)
|
||||
{ }
|
||||
|
||||
MetaInfo (const std::string &n, const db::MetaInfo &mi)
|
||||
: name (n), description (mi.description), value (mi.value), persisted (mi.persisted)
|
||||
{ }
|
||||
|
||||
MetaInfo ()
|
||||
: name (), description (), value (), persisted (false)
|
||||
{ }
|
||||
|
||||
std::string name;
|
||||
std::string description;
|
||||
tl::Variant value;
|
||||
bool persisted;
|
||||
};
|
||||
|
||||
struct MetaInfoIterator
|
||||
{
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
typedef MetaInfo value_type;
|
||||
typedef void difference_type;
|
||||
typedef MetaInfo reference;
|
||||
typedef void pointer;
|
||||
|
||||
MetaInfoIterator ()
|
||||
: mp_layout (), m_b (), m_e ()
|
||||
{ }
|
||||
|
||||
MetaInfoIterator (const db::Layout *layout, db::Layout::meta_info_iterator b, db::Layout::meta_info_iterator e)
|
||||
: mp_layout (const_cast<db::Layout *> (layout)), m_b (b), m_e (e)
|
||||
{ }
|
||||
|
||||
bool at_end () const
|
||||
{
|
||||
return !mp_layout || m_b == m_e;
|
||||
}
|
||||
|
||||
void operator++ ()
|
||||
{
|
||||
if (mp_layout) {
|
||||
++m_b;
|
||||
}
|
||||
}
|
||||
|
||||
MetaInfo operator* () const
|
||||
{
|
||||
if (mp_layout) {
|
||||
return MetaInfo (mp_layout->meta_info_name (m_b->first), m_b->second);
|
||||
} else {
|
||||
return MetaInfo ();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
tl::weak_ptr<db::Layout> mp_layout;
|
||||
db::Layout::meta_info_iterator m_b, m_e;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -66,6 +66,9 @@ public:
|
|||
void begin_edge_differences ();
|
||||
void detailed_diff (const db::PropertiesRepository &pr, const std::vector <std::pair <db::Edge, db::properties_id_type> > &a, const std::vector <std::pair <db::Edge, db::properties_id_type> > &b);
|
||||
void end_edge_differences ();
|
||||
void begin_edge_pair_differences ();
|
||||
void detailed_diff (const db::PropertiesRepository &pr, const std::vector <std::pair <db::EdgePair, db::properties_id_type> > &a, const std::vector <std::pair <db::EdgePair, db::properties_id_type> > &b);
|
||||
void end_edge_pair_differences ();
|
||||
void begin_text_differences ();
|
||||
void detailed_diff (const db::PropertiesRepository &pr, const std::vector <std::pair <db::Text, db::properties_id_type> > &a, const std::vector <std::pair <db::Text, db::properties_id_type> > &b);
|
||||
void end_text_differences ();
|
||||
|
|
@ -339,6 +342,26 @@ TestDifferenceReceiver::end_edge_differences ()
|
|||
{
|
||||
}
|
||||
|
||||
void
|
||||
TestDifferenceReceiver::begin_edge_pair_differences ()
|
||||
{
|
||||
m_os << "layout_diff: edge pairs differ for layer " << m_layer.to_string () << " in cell " << m_cellname << std::endl;
|
||||
}
|
||||
|
||||
void
|
||||
TestDifferenceReceiver::detailed_diff (const db::PropertiesRepository &pr, const std::vector <std::pair <db::EdgePair, db::properties_id_type> > &a, const std::vector <std::pair <db::EdgePair, db::properties_id_type> > &b)
|
||||
{
|
||||
m_os << "Not in b but in a:" << std::endl;
|
||||
print_diffs (pr, a, b);
|
||||
m_os << "Not in a but in b:" << std::endl;
|
||||
print_diffs (pr, b, a);
|
||||
}
|
||||
|
||||
void
|
||||
TestDifferenceReceiver::end_edge_pair_differences ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
TestDifferenceReceiver::begin_text_differences ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -543,7 +543,7 @@ TEST(5)
|
|||
db::Layout l (&m);
|
||||
EXPECT_EQ (l.technology_name (), "");
|
||||
|
||||
db::ProxyContextInfo info;
|
||||
db::LayoutOrCellContextInfo info;
|
||||
info.lib_name = "LIB";
|
||||
info.cell_name = "LIBCELL";
|
||||
|
||||
|
|
@ -624,7 +624,7 @@ TEST(6)
|
|||
|
||||
EXPECT_EQ (l.technology_name (), "");
|
||||
|
||||
db::ProxyContextInfo info;
|
||||
db::LayoutOrCellContextInfo info;
|
||||
info.lib_name = "Basic";
|
||||
info.pcell_name = "CIRCLE";
|
||||
info.pcell_parameters ["actual_radius"] = tl::Variant (10.0);
|
||||
|
|
@ -644,7 +644,7 @@ TEST(6)
|
|||
|
||||
EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {CIRCLE}\nboundary 1 0 {-4142 -10000} {-10000 -4142} {-10000 4142} {-4142 10000} {4142 10000} {10000 4142} {10000 -4142} {4142 -10000} {-4142 -10000}\nend_cell\nend_lib\n");
|
||||
|
||||
db::ProxyContextInfo info2;
|
||||
db::LayoutOrCellContextInfo info2;
|
||||
l.get_context_info (cell->cell_index (), info2);
|
||||
info2.pcell_parameters ["actual_radius"] = tl::Variant (5.0);
|
||||
|
||||
|
|
@ -677,7 +677,7 @@ TEST(7_LayerProperties)
|
|||
db::Layout l (&m);
|
||||
|
||||
EXPECT_EQ (l.is_valid_layer (0), false);
|
||||
EXPECT_EQ (l.guiding_shape_layer (), 0);
|
||||
EXPECT_EQ (l.guiding_shape_layer (), (unsigned int) 0);
|
||||
EXPECT_EQ (l.is_special_layer (0), true);
|
||||
EXPECT_EQ (int (l.layers ()), 1);
|
||||
|
||||
|
|
@ -737,3 +737,61 @@ TEST(7_LayerProperties)
|
|||
EXPECT_EQ (l.get_layer_maybe (db::LayerProperties (1, 0)), -1);
|
||||
EXPECT_EQ (l.get_layer_maybe (db::LayerProperties (2, 0)), -1);
|
||||
}
|
||||
|
||||
TEST(8_MetaInfo)
|
||||
{
|
||||
db::Layout ly;
|
||||
|
||||
EXPECT_EQ (ly.meta_info_name_id ("a"), (unsigned int) 0);
|
||||
EXPECT_EQ (ly.meta_info_name_id ("b"), (unsigned int) 1);
|
||||
EXPECT_EQ (ly.meta_info_name_id ("a"), (unsigned int) 0);
|
||||
EXPECT_EQ (ly.has_context_info (), false);
|
||||
|
||||
ly.add_meta_info ("a", db::MetaInfo ("description", tl::Variant (17.5), false));
|
||||
ly.add_meta_info ("b", db::MetaInfo ("", tl::Variant ("value"), true));
|
||||
|
||||
EXPECT_EQ (ly.has_context_info (), true);
|
||||
|
||||
EXPECT_EQ (ly.meta_info ("x").value.to_string (), "nil");
|
||||
EXPECT_EQ (ly.meta_info ("x").description, "");
|
||||
EXPECT_EQ (ly.meta_info ("x").persisted, false);
|
||||
|
||||
EXPECT_EQ (ly.meta_info ("a").value.to_string (), "17.5");
|
||||
EXPECT_EQ (ly.meta_info ("a").description, "description");
|
||||
EXPECT_EQ (ly.meta_info ("a").persisted, false);
|
||||
|
||||
EXPECT_EQ (ly.meta_info (1).value.to_string (), "value");
|
||||
EXPECT_EQ (ly.meta_info (1).description, "");
|
||||
EXPECT_EQ (ly.meta_info (1).persisted, true);
|
||||
|
||||
db::cell_index_type ci = ly.add_cell ("X");
|
||||
|
||||
EXPECT_EQ (ly.has_context_info (ci), false);
|
||||
|
||||
ly.add_meta_info (ci, "a", db::MetaInfo ("dd", tl::Variant (-1), false));
|
||||
ly.add_meta_info (ci, "b", db::MetaInfo ("d", tl::Variant ("u"), true));
|
||||
|
||||
EXPECT_EQ (ly.has_context_info (ci), true);
|
||||
|
||||
EXPECT_EQ (ly.meta_info (ci, "x").value.to_string (), "nil");
|
||||
EXPECT_EQ (ly.meta_info (ci, "x").description, "");
|
||||
EXPECT_EQ (ly.meta_info (ci, "x").persisted, false);
|
||||
|
||||
EXPECT_EQ (ly.meta_info (ci, "a").value.to_string (), "-1");
|
||||
EXPECT_EQ (ly.meta_info (ci, "a").description, "dd");
|
||||
EXPECT_EQ (ly.meta_info (ci, "a").persisted, false);
|
||||
|
||||
EXPECT_EQ (ly.meta_info (ci, 1).value.to_string (), "u");
|
||||
EXPECT_EQ (ly.meta_info (ci, 1).description, "d");
|
||||
EXPECT_EQ (ly.meta_info (ci, 1).persisted, true);
|
||||
|
||||
EXPECT_EQ (ly.has_context_info (), true);
|
||||
ly.clear_meta ();
|
||||
EXPECT_EQ (ly.has_context_info (), false);
|
||||
EXPECT_EQ (ly.meta_info ("a").value.to_string (), "nil");
|
||||
|
||||
EXPECT_EQ (ly.has_context_info (ci), true);
|
||||
ly.clear_meta (ci);
|
||||
EXPECT_EQ (ly.has_context_info (ci), false);
|
||||
EXPECT_EQ (ly.meta_info (ci, "a").value.to_string (), "nil");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -800,7 +800,7 @@ MainService::cm_make_cell_variants ()
|
|||
if (needs_variant) {
|
||||
|
||||
// need to create a variant: create a new cell
|
||||
db::cell_index_type new_cell_index = layout.add_cell (layout.cell_name (elem.inst_ptr.cell_index ()));
|
||||
db::cell_index_type new_cell_index = layout.add_cell (layout, elem.inst_ptr.cell_index ());
|
||||
|
||||
// prepare a new variant cell
|
||||
db::Cell &new_cell = layout.cell (new_cell_index);
|
||||
|
|
|
|||
|
|
@ -200,9 +200,10 @@ LibraryController::sync_files ()
|
|||
reader.read (lib->layout ());
|
||||
|
||||
// Use the libname if there is one
|
||||
db::Layout::meta_info_name_id_type libname_name_id = lib->layout ().meta_info_name_id ("libname");
|
||||
for (db::Layout::meta_info_iterator m = lib->layout ().begin_meta (); m != lib->layout ().end_meta (); ++m) {
|
||||
if (m->name == "libname" && ! m->value.empty ()) {
|
||||
lib->set_name (m->value);
|
||||
if (m->first == libname_name_id && ! m->second.value.is_nil ()) {
|
||||
lib->set_name (m->second.value.to_string ());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3202,6 +3202,25 @@ LayoutViewBase::reload_layout (unsigned int cv_index)
|
|||
goto_view (state);
|
||||
}
|
||||
|
||||
static void
|
||||
get_lyp_from_meta_info (const db::Layout &layout, std::string &lyp_file, bool &add_other_layers)
|
||||
{
|
||||
db::Layout::meta_info_name_id_type layer_properties_file_name_id = layout.meta_info_name_id ("layer-properties-file");
|
||||
db::Layout::meta_info_name_id_type layer_properties_add_other_layers_name_id = layout.meta_info_name_id ("layer-properties-add-other-layers");
|
||||
|
||||
for (db::Layout::meta_info_iterator meta = layout.begin_meta (); meta != layout.end_meta (); ++meta) {
|
||||
if (meta->first == layer_properties_file_name_id) {
|
||||
lyp_file = meta->second.value.to_string ();
|
||||
}
|
||||
if (meta->first == layer_properties_add_other_layers_name_id) {
|
||||
try {
|
||||
add_other_layers = meta->second.value.to_bool ();
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int
|
||||
LayoutViewBase::add_layout (lay::LayoutHandle *layout_handle, bool add_cellview, bool initialize_layers)
|
||||
{
|
||||
|
|
@ -3266,17 +3285,7 @@ LayoutViewBase::add_layout (lay::LayoutHandle *layout_handle, bool add_cellview,
|
|||
}
|
||||
|
||||
// Give the layout object a chance to specify a certain layer property file
|
||||
for (db::Layout::meta_info_iterator meta = cv->layout ().begin_meta (); meta != cv->layout ().end_meta (); ++meta) {
|
||||
if (meta->name == "layer-properties-file") {
|
||||
lyp_file = meta->value;
|
||||
}
|
||||
if (meta->name == "layer-properties-add-other-layers") {
|
||||
try {
|
||||
tl::from_string (meta->value, add_other_layers);
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
}
|
||||
get_lyp_from_meta_info (cv->layout (), lyp_file, add_other_layers);
|
||||
|
||||
// interpolate the layout properties file name
|
||||
tl::Eval expr;
|
||||
|
|
@ -3438,17 +3447,7 @@ LayoutViewBase::load_layout (const std::string &filename, const db::LoadLayoutOp
|
|||
}
|
||||
|
||||
// Give the layout object a chance to specify a certain layer property file
|
||||
for (db::Layout::meta_info_iterator meta = cv->layout().begin_meta (); meta != cv->layout().end_meta (); ++meta) {
|
||||
if (meta->name == "layer-properties-file") {
|
||||
lyp_file = meta->value;
|
||||
}
|
||||
if (meta->name == "layer-properties-add-other-layers") {
|
||||
try {
|
||||
tl::from_string (meta->value, add_other_layers);
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
}
|
||||
get_lyp_from_meta_info (cv->layout (), lyp_file, add_other_layers);
|
||||
|
||||
// interpolate the layout properties file name
|
||||
tl::Eval expr;
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@
|
|||
<item row="1" column="0">
|
||||
<widget class="QTabWidget" name="mode_tab">
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
|
|
@ -186,6 +186,48 @@
|
|||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_3">
|
||||
<attribute name="title">
|
||||
<string>Meta Info</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Meta Info is additional system data shown here for information. Entries marked with a "*" are persisted in the layout file.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="meta_info_list">
|
||||
<property name="rootIsDecorated">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="allColumnsShowFocus">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Key</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Description</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Value</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
|
|
|||
|
|
@ -1186,8 +1186,32 @@ UserPropertiesForm::set_properties (const db::PropertiesRepository::properties_s
|
|||
mp_ui->text_edit->setPlainText (tl::to_qstring (text));
|
||||
}
|
||||
|
||||
void
|
||||
UserPropertiesForm::set_meta_info (db::Layout::meta_info_iterator begin_meta, db::Layout::meta_info_iterator end_meta, const db::Layout &layout)
|
||||
{
|
||||
m_begin_meta = begin_meta;
|
||||
m_end_meta = end_meta;
|
||||
|
||||
mp_ui->mode_tab->setTabVisible (2, m_begin_meta != m_end_meta);
|
||||
|
||||
mp_ui->meta_info_list->clear ();
|
||||
|
||||
for (auto m = m_begin_meta; m != m_end_meta; ++m) {
|
||||
QTreeWidgetItem *entry = new QTreeWidgetItem (mp_ui->meta_info_list);
|
||||
entry->setText (0, tl::to_qstring ((m->second.persisted ? "*" : "") + layout.meta_info_name (m->first)));
|
||||
entry->setText (1, tl::to_qstring (m->second.description));
|
||||
entry->setText (2, tl::to_qstring (m->second.value.to_parsable_string ()));
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
UserPropertiesForm::show (LayoutViewBase *view, unsigned int cv_index, db::properties_id_type &prop_id)
|
||||
{
|
||||
return show (view, cv_index, prop_id, db::Layout::meta_info_iterator (), db::Layout::meta_info_iterator ());
|
||||
}
|
||||
|
||||
bool
|
||||
UserPropertiesForm::show (LayoutViewBase *view, unsigned int cv_index, db::properties_id_type &prop_id, db::Layout::meta_info_iterator begin_meta, db::Layout::meta_info_iterator end_meta)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
|
|
@ -1209,6 +1233,8 @@ BEGIN_PROTECTED
|
|||
const db::PropertiesRepository::properties_set &props = mp_prep->properties (prop_id);
|
||||
set_properties (props);
|
||||
|
||||
set_meta_info (begin_meta, end_meta, cv->layout ());
|
||||
|
||||
if (exec ()) {
|
||||
|
||||
if (m_editable) {
|
||||
|
|
|
|||
|
|
@ -25,10 +25,7 @@
|
|||
#ifndef HDR_layDialogs
|
||||
#define HDR_layDialogs
|
||||
|
||||
#include "dbPoint.h"
|
||||
#include "dbVector.h"
|
||||
#include "dbTypes.h"
|
||||
#include "dbPropertiesRepository.h"
|
||||
#include "dbLayout.h"
|
||||
#include "layuiCommon.h"
|
||||
|
||||
#include <QDialog>
|
||||
|
|
@ -36,12 +33,6 @@
|
|||
|
||||
class QTreeWidgetItem;
|
||||
|
||||
namespace db
|
||||
{
|
||||
class Layout;
|
||||
struct LayerProperties;
|
||||
}
|
||||
|
||||
namespace lay
|
||||
{
|
||||
class GenericSyntaxHighlighterAttributes;
|
||||
|
|
@ -431,6 +422,7 @@ public:
|
|||
virtual ~UserPropertiesForm ();
|
||||
|
||||
bool show (lay::LayoutViewBase *view, unsigned int cv_index, db::properties_id_type &prop_id);
|
||||
bool show (lay::LayoutViewBase *view, unsigned int cv_index, db::properties_id_type &prop_id, db::Layout::meta_info_iterator begin_meta, db::Layout::meta_info_iterator end_meta);
|
||||
|
||||
public slots:
|
||||
void add ();
|
||||
|
|
@ -442,11 +434,13 @@ public slots:
|
|||
private:
|
||||
db::PropertiesRepository::properties_set get_properties (int tab);
|
||||
void set_properties (const db::PropertiesRepository::properties_set &props);
|
||||
void set_meta_info (db::Layout::meta_info_iterator begin_meta, db::Layout::meta_info_iterator end_meta, const db::Layout &layout);
|
||||
void accept ();
|
||||
|
||||
bool m_editable;
|
||||
db::PropertiesRepository *mp_prep;
|
||||
Ui::UserPropertiesForm *mp_ui;
|
||||
db::Layout::meta_info_iterator m_begin_meta, m_end_meta;
|
||||
std::unique_ptr<lay::GenericSyntaxHighlighterAttributes> mp_hl_attributes, mp_hl_basic_attributes;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ LayoutPropertiesForm::prop_pb_clicked ()
|
|||
db::properties_id_type prop_id = layout.prop_id ();
|
||||
|
||||
lay::UserPropertiesForm props_form (this);
|
||||
if (props_form.show (mp_view, m_index, prop_id)) {
|
||||
if (props_form.show (mp_view, m_index, prop_id, layout.begin_meta (), layout.end_meta ())) {
|
||||
|
||||
mp_view->manager ()->transaction (tl::to_string (QObject::tr ("Edit layout's user properties")));
|
||||
layout.prop_id (prop_id);
|
||||
|
|
|
|||
|
|
@ -440,7 +440,7 @@ LayoutViewFunctions::cm_cell_user_properties ()
|
|||
db::properties_id_type prop_id = cell.prop_id ();
|
||||
|
||||
lay::UserPropertiesForm props_form (parent_widget ());
|
||||
if (props_form.show (view (), cv_index, prop_id)) {
|
||||
if (props_form.show (view (), cv_index, prop_id, layout.begin_meta (cell.cell_index ()), layout.end_meta (cell.cell_index ()))) {
|
||||
|
||||
view ()->transaction (tl::to_string (tr ("Edit cell's user properties")));
|
||||
cell.prop_id (prop_id);
|
||||
|
|
|
|||
|
|
@ -185,8 +185,8 @@ GDS2ReaderBase::do_read (db::Layout &layout)
|
|||
unsigned int mod_time[6] = { 0, 0, 0, 0, 0, 0 };
|
||||
unsigned int access_time[6] = { 0, 0, 0, 0, 0, 0 };
|
||||
get_time (mod_time, access_time);
|
||||
layout.add_meta_info (MetaInfo ("mod_time", tl::to_string (tr ("Modification Time")), tl::sprintf ("%d/%d/%d %d:%02d:%02d", mod_time[1], mod_time[2], mod_time[0], mod_time[3], mod_time[4], mod_time[5])));
|
||||
layout.add_meta_info (MetaInfo ("access_time", tl::to_string (tr ("Access Time")), tl::sprintf ("%d/%d/%d %d:%02d:%02d", access_time[1], access_time[2], access_time[0], access_time[3], access_time[4], access_time[5])));
|
||||
layout.add_meta_info ("mod_time", MetaInfo (tl::to_string (tr ("Modification Time")), tl::sprintf ("%d/%d/%d %d:%02d:%02d", mod_time[1], mod_time[2], mod_time[0], mod_time[3], mod_time[4], mod_time[5])));
|
||||
layout.add_meta_info ("access_time", MetaInfo (tl::to_string (tr ("Access Time")), tl::sprintf ("%d/%d/%d %d:%02d:%02d", access_time[1], access_time[2], access_time[0], access_time[3], access_time[4], access_time[5])));
|
||||
|
||||
long attr = 0;
|
||||
db::PropertiesRepository::properties_set layout_properties;
|
||||
|
|
@ -234,9 +234,9 @@ GDS2ReaderBase::do_read (db::Layout &layout)
|
|||
double dbuu = get_double ();
|
||||
double dbum = get_double ();
|
||||
|
||||
layout.add_meta_info (MetaInfo ("dbuu", tl::to_string (tr ("Database unit in user units")), tl::to_string (dbuu)));
|
||||
layout.add_meta_info (MetaInfo ("dbum", tl::to_string (tr ("Database unit in meter")), tl::to_string (dbum)));
|
||||
layout.add_meta_info (MetaInfo ("libname", tl::to_string (tr ("Library name")), m_libname));
|
||||
layout.add_meta_info ("dbuu", MetaInfo (tl::to_string (tr ("Database unit in user units")), tl::to_string (dbuu)));
|
||||
layout.add_meta_info ("dbum", MetaInfo (tl::to_string (tr ("Database unit in meter")), tl::to_string (dbum)));
|
||||
layout.add_meta_info ("libname", MetaInfo (tl::to_string (tr ("Library name")), m_libname));
|
||||
|
||||
m_dbuu = dbuu;
|
||||
m_dbu = dbum * 1e6; /*in micron*/
|
||||
|
|
@ -289,13 +289,19 @@ GDS2ReaderBase::do_read (db::Layout &layout)
|
|||
db::cell_index_type cell_index = make_cell (layout, m_cellname);
|
||||
|
||||
bool ignore_cell = false;
|
||||
std::map <tl::string, std::vector <std::string> >::const_iterator ctx = m_context_info.find (m_cellname);
|
||||
auto ctx = m_context_info.find (m_cellname);
|
||||
if (ctx != m_context_info.end ()) {
|
||||
|
||||
CommonReaderLayerMapping layer_mapping (this, &layout);
|
||||
if (layout.recover_proxy_as (cell_index, ctx->second.begin (), ctx->second.end (), &layer_mapping)) {
|
||||
LayoutOrCellContextInfo ci = LayoutOrCellContextInfo::deserialize (ctx->second.begin (), ctx->second.end ());
|
||||
|
||||
if (ci.has_proxy_info () && layout.recover_proxy_as (cell_index, ci, &layer_mapping)) {
|
||||
// ignore everything in that cell since it is created by the import:
|
||||
ignore_cell = true;
|
||||
}
|
||||
|
||||
layout.fill_meta_info_from_context (cell_index, ci);
|
||||
|
||||
}
|
||||
|
||||
db::Cell *cell = 0;
|
||||
|
|
@ -386,6 +392,13 @@ GDS2ReaderBase::do_read (db::Layout &layout)
|
|||
|
||||
}
|
||||
|
||||
// deserialize global context information
|
||||
auto ctx = m_context_info.find (std::string ());
|
||||
if (ctx != m_context_info.end ()) {
|
||||
LayoutOrCellContextInfo ci = LayoutOrCellContextInfo::deserialize (ctx->second.begin (), ctx->second.end ());
|
||||
layout.fill_meta_info_from_context (ci);
|
||||
}
|
||||
|
||||
// check, if the last record is a ENDLIB
|
||||
if (rec_id != sENDLIB) {
|
||||
error (tl::to_string (tr ("ENDLIB record expected")));
|
||||
|
|
@ -396,12 +409,16 @@ void
|
|||
GDS2ReaderBase::read_context_info_cell ()
|
||||
{
|
||||
short rec_id = 0;
|
||||
std::string cn;
|
||||
|
||||
// read cell content
|
||||
while ((rec_id = get_record ()) != sENDSTR) {
|
||||
|
||||
progress_checkpoint ();
|
||||
|
||||
bool valid_hook = false;
|
||||
cn.clear ();
|
||||
|
||||
if (rec_id == sSREF) {
|
||||
|
||||
do {
|
||||
|
|
@ -411,7 +428,7 @@ GDS2ReaderBase::read_context_info_cell ()
|
|||
error (tl::to_string (tr ("SNAME record expected")));
|
||||
}
|
||||
|
||||
std::string cn = get_string ();
|
||||
cn = get_string ();
|
||||
|
||||
rec_id = get_record ();
|
||||
while (rec_id == sSTRANS || rec_id == sANGLE || rec_id == sMAG) {
|
||||
|
|
@ -421,6 +438,24 @@ GDS2ReaderBase::read_context_info_cell ()
|
|||
error (tl::to_string (tr ("XY record expected")));
|
||||
}
|
||||
|
||||
valid_hook = true;
|
||||
|
||||
} else if (rec_id == sBOUNDARY) {
|
||||
|
||||
rec_id = get_record ();
|
||||
while (rec_id == sLAYER || rec_id == sDATATYPE) {
|
||||
rec_id = get_record ();
|
||||
}
|
||||
if (rec_id != sXY) {
|
||||
error (tl::to_string (tr ("XY record expected")));
|
||||
}
|
||||
|
||||
valid_hook = true;
|
||||
|
||||
}
|
||||
|
||||
if (valid_hook) {
|
||||
|
||||
std::vector <std::string> &strings = m_context_info.insert (std::make_pair (cn, std::vector <std::string> ())).first->second;
|
||||
|
||||
size_t attr = 0;
|
||||
|
|
|
|||
|
|
@ -72,6 +72,109 @@ inline int scale (double sf, int value)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
GDS2WriterBase::write_context_cell (db::Layout &layout, const short *time_data, const std::vector<db::cell_index_type> &cells)
|
||||
{
|
||||
write_record_size (4 + 12 * 2);
|
||||
write_record (sBGNSTR);
|
||||
write_time (time_data);
|
||||
write_time (time_data);
|
||||
|
||||
write_string_record (sSTRNAME, "$$$CONTEXT_INFO$$$");
|
||||
|
||||
std::vector <std::string> context_prop_strings;
|
||||
|
||||
if (layout.has_context_info ()) {
|
||||
|
||||
// Use a dummy BOUNDARY element to attach the global context
|
||||
|
||||
write_record_size (4);
|
||||
write_record (sBOUNDARY);
|
||||
|
||||
write_record_size (6);
|
||||
write_record (sLAYER);
|
||||
write_short (0);
|
||||
|
||||
write_record_size (6);
|
||||
write_record (sDATATYPE);
|
||||
write_short (0);
|
||||
|
||||
write_record_size (4 + 5 * 2 * 4);
|
||||
write_record (sXY);
|
||||
for (unsigned int i = 0; i < 10; ++i) {
|
||||
write_int (0);
|
||||
}
|
||||
|
||||
context_prop_strings.clear ();
|
||||
|
||||
if (layout.get_context_info (context_prop_strings)) {
|
||||
|
||||
// Hint: write in the reverse order since this way, the reader is more efficient (it knows how many strings
|
||||
// will arrive)
|
||||
for (std::vector <std::string>::const_iterator s = context_prop_strings.end (); s != context_prop_strings.begin (); ) {
|
||||
|
||||
--s;
|
||||
|
||||
write_record_size (6);
|
||||
write_record (sPROPATTR);
|
||||
write_short (short (std::distance (std::vector <std::string>::const_iterator (context_prop_strings.begin ()), s))); // = user string
|
||||
|
||||
write_string_record (sPROPVALUE, *s);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
write_record_size (4);
|
||||
write_record (sENDEL);
|
||||
|
||||
}
|
||||
|
||||
for (std::vector<db::cell_index_type>::const_iterator cell = cells.begin (); cell != cells.end (); ++cell) {
|
||||
|
||||
if (layout.has_context_info (*cell)) {
|
||||
|
||||
write_record_size (4);
|
||||
write_record (sSREF);
|
||||
|
||||
write_string_record (sSNAME, m_cell_name_map.cell_name (*cell));
|
||||
|
||||
write_record_size (12);
|
||||
write_record (sXY);
|
||||
write_int (0);
|
||||
write_int (0);
|
||||
|
||||
context_prop_strings.clear ();
|
||||
|
||||
if (layout.get_context_info (*cell, context_prop_strings)) {
|
||||
|
||||
// Hint: write in the reverse order since this way, the reader is more efficient (it knows how many strings
|
||||
// will arrive)
|
||||
for (std::vector <std::string>::const_iterator s = context_prop_strings.end (); s != context_prop_strings.begin (); ) {
|
||||
|
||||
--s;
|
||||
|
||||
write_record_size (6);
|
||||
write_record (sPROPATTR);
|
||||
write_short (short (std::distance (std::vector <std::string>::const_iterator (context_prop_strings.begin ()), s))); // = user string
|
||||
|
||||
write_string_record (sPROPVALUE, *s);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
write_record_size (4);
|
||||
write_record (sENDEL);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
write_record_size (4);
|
||||
write_record (sENDSTR);
|
||||
}
|
||||
|
||||
void
|
||||
GDS2WriterBase::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLayoutOptions &options)
|
||||
{
|
||||
|
|
@ -86,9 +189,9 @@ GDS2WriterBase::write (db::Layout &layout, tl::OutputStream &stream, const db::S
|
|||
|
||||
db::GDS2WriterOptions gds2_options = options.get_options<db::GDS2WriterOptions> ();
|
||||
|
||||
layout.add_meta_info (MetaInfo ("dbuu", tl::to_string (tr ("Database unit in user units")), tl::to_string (dbu / std::max (1e-9, gds2_options.user_units))));
|
||||
layout.add_meta_info (MetaInfo ("dbum", tl::to_string (tr ("Database unit in meter")), tl::to_string (dbu * 1e-6)));
|
||||
layout.add_meta_info (MetaInfo ("libname", tl::to_string (tr ("Library name")), gds2_options.libname));
|
||||
layout.add_meta_info ("dbuu", MetaInfo (tl::to_string (tr ("Database unit in user units")), tl::to_string (dbu / std::max (1e-9, gds2_options.user_units))));
|
||||
layout.add_meta_info ("dbum", MetaInfo (tl::to_string (tr ("Database unit in meter")), tl::to_string (dbu * 1e-6)));
|
||||
layout.add_meta_info ("libname", MetaInfo (tl::to_string (tr ("Library name")), gds2_options.libname));
|
||||
|
||||
std::vector <std::pair <unsigned int, db::LayerProperties> > layers;
|
||||
options.get_valid_layers (layout, layers, db::SaveLayoutOptions::LP_AssignNumber);
|
||||
|
|
@ -123,8 +226,8 @@ GDS2WriterBase::write (db::Layout &layout, tl::OutputStream &stream, const db::S
|
|||
}
|
||||
|
||||
std::string str_time = tl::sprintf ("%d/%d/%d %d:%02d:%02d", time_data[1], time_data[2], time_data[0], time_data[3], time_data[4], time_data[5]);
|
||||
layout.add_meta_info (MetaInfo ("mod_time", tl::to_string (tr ("Modification Time")), str_time));
|
||||
layout.add_meta_info (MetaInfo ("access_time", tl::to_string (tr ("Access Time")), str_time));
|
||||
layout.add_meta_info ("mod_time", MetaInfo (tl::to_string (tr ("Modification Time")), str_time));
|
||||
layout.add_meta_info ("access_time", MetaInfo (tl::to_string (tr ("Access Time")), str_time));
|
||||
|
||||
bool multi_xy = gds2_options.multi_xy_records;
|
||||
size_t max_cellname_length = std::max (gds2_options.max_cellname_length, (unsigned int)8);
|
||||
|
|
@ -178,73 +281,17 @@ GDS2WriterBase::write (db::Layout &layout, tl::OutputStream &stream, const db::S
|
|||
|
||||
// write context info
|
||||
|
||||
bool any_proxy = false;
|
||||
bool has_context = false;
|
||||
|
||||
if (options.write_context_info ()) {
|
||||
for (std::vector<db::cell_index_type>::const_iterator cell = cells.begin (); cell != cells.end () && !any_proxy; ++cell) {
|
||||
const db::Cell &cref = layout.cell (*cell);
|
||||
if (cref.is_proxy () && ! cref.is_top ()) {
|
||||
any_proxy = true;
|
||||
}
|
||||
has_context = layout.has_context_info ();
|
||||
for (std::vector<db::cell_index_type>::const_iterator cell = cells.begin (); cell != cells.end () && !has_context; ++cell) {
|
||||
has_context = layout.has_context_info (*cell);
|
||||
}
|
||||
}
|
||||
|
||||
if (any_proxy) {
|
||||
|
||||
write_record_size (4 + 12 * 2);
|
||||
write_record (sBGNSTR);
|
||||
write_time (time_data);
|
||||
write_time (time_data);
|
||||
|
||||
write_string_record (sSTRNAME, "$$$CONTEXT_INFO$$$");
|
||||
|
||||
std::vector <std::string> context_prop_strings;
|
||||
|
||||
for (std::vector<db::cell_index_type>::const_iterator cell = cells.begin (); cell != cells.end (); ++cell) {
|
||||
|
||||
const db::Cell &cref = layout.cell (*cell);
|
||||
if (cref.is_proxy () && ! cref.is_top ()) {
|
||||
|
||||
write_record_size (4);
|
||||
write_record (sSREF);
|
||||
|
||||
write_string_record (sSNAME, m_cell_name_map.cell_name (*cell));
|
||||
|
||||
write_record_size (12);
|
||||
write_record (sXY);
|
||||
write_int (0);
|
||||
write_int (0);
|
||||
|
||||
context_prop_strings.clear ();
|
||||
|
||||
if (layout.get_context_info (*cell, context_prop_strings)) {
|
||||
|
||||
// Hint: write in the reverse order since this way, the reader is more efficient (it knows how many strings
|
||||
// will arrive)
|
||||
for (std::vector <std::string>::const_iterator s = context_prop_strings.end (); s != context_prop_strings.begin (); ) {
|
||||
|
||||
--s;
|
||||
|
||||
write_record_size (6);
|
||||
write_record (sPROPATTR);
|
||||
write_short (short (std::distance (std::vector <std::string>::const_iterator (context_prop_strings.begin ()), s))); // = user string
|
||||
|
||||
write_string_record (sPROPVALUE, *s);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
write_record_size (4);
|
||||
write_record (sENDEL);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
write_record_size (4);
|
||||
write_record (sENDSTR);
|
||||
|
||||
if (has_context) {
|
||||
write_context_cell (layout, time_data, cells);
|
||||
}
|
||||
|
||||
// body
|
||||
|
|
|
|||
|
|
@ -168,6 +168,7 @@ private:
|
|||
db::WriterCellNameMap m_cell_name_map;
|
||||
|
||||
void write_properties (const db::Layout &layout, db::properties_id_type prop_id);
|
||||
void write_context_cell (db::Layout &layout, const short *time_data, const std::vector<cell_index_type> &cells);
|
||||
};
|
||||
|
||||
} // namespace db
|
||||
|
|
|
|||
|
|
@ -145,9 +145,10 @@ public:
|
|||
// Initialize the libname property from meta data with key "libname".
|
||||
db::GDS2WriterOptions *options = dynamic_cast<db::GDS2WriterOptions *> (o);
|
||||
if (options) {
|
||||
db::Layout::meta_info_name_id_type libname_name_id = lh.layout().meta_info_name_id ("libname");
|
||||
for (db::Layout::meta_info_iterator meta = lh.layout().begin_meta (); meta != lh.layout().end_meta (); ++meta) {
|
||||
if (meta->name == "libname" && !meta->value.empty ()) {
|
||||
options->libname = meta->value;
|
||||
if (meta->first == libname_name_id && !meta->second.value.is_nil ()) {
|
||||
options->libname = meta->second.value.to_string ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ TEST(1)
|
|||
db::LayerMap map = reader.read (layout);
|
||||
|
||||
EXPECT_EQ (fabs (layout.dbu () / 0.001 - 1.0) < 1e-6, true);
|
||||
EXPECT_EQ (layout.meta_info_value ("libname"), "LIB.DB");
|
||||
EXPECT_EQ (layout.meta_info ("libname").value.to_string (), "LIB.DB");
|
||||
|
||||
EXPECT_EQ (layout.layers (), size_t (11));
|
||||
EXPECT_EQ (map.mapping_str (0), "2/0 : 2/0");
|
||||
|
|
@ -289,7 +289,7 @@ TEST(2)
|
|||
db::Reader reader (file);
|
||||
map = reader.read (layout_none, options);
|
||||
EXPECT_EQ (fabs (layout_none.dbu () / 0.001 - 1.0) < 1e-6, true);
|
||||
EXPECT_EQ (layout.meta_info_value ("libname"), "LIB.DB");
|
||||
EXPECT_EQ (layout.meta_info ("libname").value.to_string (), "LIB.DB");
|
||||
}
|
||||
|
||||
EXPECT_EQ (layout_none.layers (), size_t (0));
|
||||
|
|
|
|||
|
|
@ -1193,6 +1193,104 @@ TEST(121)
|
|||
run_test (_this, "t121.oas.gz", "t121_au.gds.gz", true, opt);
|
||||
}
|
||||
|
||||
// Meta info
|
||||
TEST(130a)
|
||||
{
|
||||
db::Layout layout_org;
|
||||
|
||||
layout_org.add_cell ("U");
|
||||
db::cell_index_type ci = layout_org.add_cell ("X");
|
||||
|
||||
layout_org.add_meta_info ("a", db::MetaInfo ("description", 17.5, true));
|
||||
layout_org.add_meta_info ("b", db::MetaInfo ("", "value", true));
|
||||
|
||||
layout_org.add_meta_info (ci, "a", db::MetaInfo ("dd", true, true));
|
||||
layout_org.add_meta_info (ci, "c", db::MetaInfo ("d", -1, true));
|
||||
|
||||
// complex type
|
||||
tl::Variant v2;
|
||||
v2.set_array ();
|
||||
v2.insert ("x", "value_for_x");
|
||||
v2.insert ("y", db::DBox (1.5, 2.5, 3.5, 4.5));
|
||||
tl::Variant v1;
|
||||
v1.set_list (0);
|
||||
v1.push (-1.5);
|
||||
v1.push (v2);
|
||||
layout_org.add_meta_info (ci, "complex", db::MetaInfo ("", v1, true));
|
||||
layout_org.add_meta_info ("complex", db::MetaInfo ("", v1, true));
|
||||
|
||||
std::string tmp_file = tl::TestBase::tmp_file ("tmp_GDS2Writer_130a.gds");
|
||||
|
||||
{
|
||||
tl::OutputStream out (tmp_file);
|
||||
db::SaveLayoutOptions options;
|
||||
db::Writer writer (options);
|
||||
writer.write (layout_org, out);
|
||||
}
|
||||
|
||||
db::Layout layout_read;
|
||||
|
||||
{
|
||||
tl::InputStream in (tmp_file);
|
||||
db::Reader reader (in);
|
||||
reader.read (layout_read);
|
||||
}
|
||||
|
||||
EXPECT_EQ (layout_read.has_meta_info ("x"), false);
|
||||
EXPECT_EQ (layout_read.has_meta_info ("a"), true);
|
||||
EXPECT_EQ (layout_read.meta_info ("x").value.to_string (), "nil");
|
||||
EXPECT_EQ (layout_read.meta_info ("a").value.to_string (), "17.5");
|
||||
EXPECT_EQ (layout_read.meta_info ("a").description, "description");
|
||||
EXPECT_EQ (layout_read.has_meta_info ("b"), true);
|
||||
EXPECT_EQ (layout_read.meta_info ("b").value.to_string (), "value");
|
||||
EXPECT_EQ (layout_read.meta_info ("b").description, "");
|
||||
EXPECT_EQ (layout_read.has_meta_info ("complex"), true);
|
||||
EXPECT_EQ (layout_read.meta_info ("complex").value.is_list (), true);
|
||||
EXPECT_EQ (layout_read.meta_info ("complex").value.size (), size_t (2));
|
||||
EXPECT_EQ (layout_read.meta_info ("complex").value.begin () [1].is_array (), true);
|
||||
EXPECT_EQ (layout_read.meta_info ("complex").value.to_string (), "-1.5,x=>value_for_x,y=>(1.5,2.5;3.5,4.5)");
|
||||
|
||||
db::cell_index_type ci2 = layout_read.cell_by_name ("X").second;
|
||||
|
||||
EXPECT_EQ (layout_read.meta_info (ci2, "x").value.to_string (), "nil");
|
||||
EXPECT_EQ (layout_read.meta_info (ci2, "a").value.to_string (), "true");
|
||||
EXPECT_EQ (layout_read.meta_info (ci2, "a").description, "dd");
|
||||
EXPECT_EQ (layout_read.meta_info (ci2, "c").value.to_string (), "-1");
|
||||
EXPECT_EQ (layout_read.meta_info (ci2, "c").description, "d");
|
||||
EXPECT_EQ (layout_read.meta_info (ci2, "complex").value.is_list (), true);
|
||||
EXPECT_EQ (layout_read.meta_info (ci2, "complex").value.size (), size_t (2));
|
||||
EXPECT_EQ (layout_read.meta_info (ci2, "complex").value.begin () [1].is_array (), true);
|
||||
EXPECT_EQ (layout_read.meta_info (ci2, "complex").value.to_string (), "-1.5,x=>value_for_x,y=>(1.5,2.5;3.5,4.5)");
|
||||
|
||||
tmp_file = tl::TestBase::tmp_file ("tmp_GDS2Writer_130b.gds");
|
||||
|
||||
{
|
||||
tl::OutputStream out (tmp_file);
|
||||
db::SaveLayoutOptions options;
|
||||
options.set_write_context_info (false);
|
||||
db::Writer writer (options);
|
||||
writer.write (layout_org, out);
|
||||
}
|
||||
|
||||
layout_read = db::Layout ();
|
||||
|
||||
{
|
||||
tl::InputStream in (tmp_file);
|
||||
db::Reader reader (in);
|
||||
reader.read (layout_read);
|
||||
}
|
||||
|
||||
EXPECT_EQ (layout_read.meta_info ("x").value.to_string (), "nil");
|
||||
EXPECT_EQ (layout_read.meta_info ("a").value.to_string (), "nil");
|
||||
EXPECT_EQ (layout_read.meta_info ("b").value.to_string (), "nil");
|
||||
|
||||
ci2 = layout_read.cell_by_name ("X").second;
|
||||
|
||||
EXPECT_EQ (layout_read.meta_info (ci2, "x").value.to_string (), "nil");
|
||||
EXPECT_EQ (layout_read.meta_info ("a").value.to_string (), "nil");
|
||||
EXPECT_EQ (layout_read.meta_info ("b").value.to_string (), "nil");
|
||||
}
|
||||
|
||||
// Extreme fracturing by max. points
|
||||
TEST(166)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -316,7 +316,7 @@ MAGReader::do_read_part (db::Layout &layout, db::cell_index_type cell_index, tl:
|
|||
error (tl::to_string (tr ("Could not find 'magic' header line - is this a MAGIC file?")));
|
||||
}
|
||||
|
||||
layout.add_meta_info (db::MetaInfo ("lambda", "lambda value (tech scaling)", tl::to_string (m_lambda)));
|
||||
layout.add_meta_info ("lambda", db::MetaInfo ("lambda value (tech scaling)", tl::to_string (m_lambda)));
|
||||
|
||||
bool valid_layer = false;
|
||||
unsigned int current_layer = 0;
|
||||
|
|
@ -339,11 +339,11 @@ MAGReader::do_read_part (db::Layout &layout, db::cell_index_type cell_index, tl:
|
|||
if (&m_stream == &stream) {
|
||||
|
||||
// initial file - store technology
|
||||
layout.add_meta_info (db::MetaInfo ("magic_technology", tl::to_string (tr ("MAGIC technology string")), m_tech));
|
||||
layout.add_meta_info ("magic_technology", db::MetaInfo (tl::to_string (tr ("MAGIC technology string")), m_tech));
|
||||
|
||||
// propose this is the KLayout technology unless a good one is given
|
||||
if (! mp_klayout_tech) {
|
||||
layout.add_meta_info (db::MetaInfo ("technology", tl::to_string (tr ("Technology name")), m_tech));
|
||||
layout.add_meta_info ("technology", db::MetaInfo (tl::to_string (tr ("Technology name")), m_tech));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -357,7 +357,7 @@ MAGReader::do_read_part (db::Layout &layout, db::cell_index_type cell_index, tl:
|
|||
|
||||
if (&m_stream == &stream) {
|
||||
// initial file - store timestamp
|
||||
layout.add_meta_info (db::MetaInfo ("magic_timestamp", "MAGIC main file timestamp", tl::to_string (ts)));
|
||||
layout.add_meta_info ("magic_timestamp", db::MetaInfo ("MAGIC main file timestamp", tl::to_string (ts)));
|
||||
}
|
||||
|
||||
ex.expect_end ();
|
||||
|
|
|
|||
|
|
@ -82,11 +82,14 @@ MAGWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLa
|
|||
|
||||
double lambda = m_options.lambda;
|
||||
if (lambda <= 0.0) {
|
||||
const std::string &lv = layout.meta_info_value ("lambda");
|
||||
if (lv.empty ()) {
|
||||
const tl::Variant &lv = layout.meta_info ("lambda").value;
|
||||
if (lv.is_nil ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("No lambda value configured for MAG writer and no 'lambda' metadata present in layout.")));
|
||||
} else if (lv.is_a_string ()) {
|
||||
tl::from_string (lv.to_string (), lambda);
|
||||
} else if (lv.can_convert_to_double ()) {
|
||||
lambda = lv.to_double ();
|
||||
}
|
||||
tl::from_string (lv, lambda);
|
||||
}
|
||||
|
||||
m_sf = layout.dbu () / lambda;
|
||||
|
|
|
|||
|
|
@ -101,7 +101,8 @@ public:
|
|||
* @brief The constructor
|
||||
*/
|
||||
OASISWriterOptions ()
|
||||
: compression_level (2), write_cblocks (true), strict_mode (true), recompress (false), permissive (false), write_std_properties (1), subst_char ("*")
|
||||
: compression_level (2), write_cblocks (true), strict_mode (true), recompress (false), permissive (false),
|
||||
write_std_properties (1), subst_char ("*"), tables_at_end (false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -166,6 +167,11 @@ public:
|
|||
*/
|
||||
std::string subst_char;
|
||||
|
||||
/**
|
||||
* @brief Hidden option, for testing mainly: write tables at end to force forward references
|
||||
*/
|
||||
bool tables_at_end;
|
||||
|
||||
/**
|
||||
* @brief Implementation of FormatSpecificWriterOptions
|
||||
*/
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -172,6 +172,8 @@ private:
|
|||
std::map <unsigned long, std::string> m_propstrings;
|
||||
std::map <unsigned long, std::string> m_propnames;
|
||||
|
||||
std::map <db::cell_index_type, std::vector<tl::Variant> > m_context_strings_per_cell;
|
||||
|
||||
tl::vector<db::CellInstArray> m_instances;
|
||||
tl::vector<db::CellInstArrayWithProperties> m_instances_with_props;
|
||||
|
||||
|
|
@ -210,6 +212,7 @@ private:
|
|||
void read_properties (db::PropertiesRepository &rep);
|
||||
void store_last_properties (db::PropertiesRepository &rep, db::PropertiesRepository::properties_set &properties, bool ignore_special);
|
||||
std::pair <bool, db::properties_id_type> read_element_properties (db::PropertiesRepository &rep, bool ignore_special);
|
||||
void replace_forward_references_in_variant (tl::Variant &v);
|
||||
|
||||
unsigned char get_byte ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -666,9 +666,11 @@ OASISWriter::OASISWriter ()
|
|||
mp_layout (0),
|
||||
mp_cell (0),
|
||||
m_layer (0), m_datatype (0),
|
||||
m_write_context_info (false),
|
||||
m_in_cblock (false),
|
||||
m_propname_id (0),
|
||||
m_propstring_id (0),
|
||||
m_textstring_id (0),
|
||||
m_proptables_written (false),
|
||||
m_progress (tl::to_string (tr ("Writing OASIS file")), 10000)
|
||||
{
|
||||
|
|
@ -1150,6 +1152,313 @@ OASISWriter::reset_modal_variables ()
|
|||
mm_last_value_list.reset ();
|
||||
}
|
||||
|
||||
void
|
||||
OASISWriter::write_propname_table (size_t &propnames_table_pos, const std::vector<db::cell_index_type> &cells, const db::Layout &layout, const std::vector<std::pair<unsigned int, LayerProperties> > &layers)
|
||||
{
|
||||
// write the property names collected so far in the order of the ID's.
|
||||
|
||||
std::vector<std::pair<unsigned long, std::string> > rev_pn;
|
||||
rev_pn.reserve (m_propnames.size ());
|
||||
for (auto p = m_propnames.begin (); p != m_propnames.end (); ++p) {
|
||||
rev_pn.push_back (std::make_pair (p->second, p->first));
|
||||
}
|
||||
std::sort (rev_pn.begin (), rev_pn.end ());
|
||||
|
||||
for (auto p = rev_pn.begin (); p != rev_pn.end (); ++p) {
|
||||
tl_assert (p->first == (unsigned long)(p - rev_pn.begin ()));
|
||||
begin_table (propnames_table_pos);
|
||||
write_record_id (7);
|
||||
write_nstring (p->second.c_str ());
|
||||
}
|
||||
|
||||
// collect and write the future property names
|
||||
|
||||
std::set <db::properties_id_type> prop_ids_done;
|
||||
|
||||
for (auto cell = cells.begin (); cell != cells.end (); ++cell) {
|
||||
|
||||
const db::Cell &cref (layout.cell (*cell));
|
||||
|
||||
if (cref.prop_id () != 0) {
|
||||
begin_table (propnames_table_pos);
|
||||
emit_propname_def (cref.prop_id ());
|
||||
}
|
||||
|
||||
for (db::Cell::const_iterator inst = cref.begin (); ! inst.at_end (); ++inst) {
|
||||
if (inst->has_prop_id () && inst->prop_id () != 0 && prop_ids_done.find (inst->prop_id ()) == prop_ids_done.end ()) {
|
||||
prop_ids_done.insert (inst->prop_id ());
|
||||
begin_table (propnames_table_pos);
|
||||
emit_propname_def (inst->prop_id ());
|
||||
m_progress.set (mp_stream->pos ());
|
||||
}
|
||||
}
|
||||
|
||||
for (auto l = layers.begin (); l != layers.end (); ++l) {
|
||||
db::ShapeIterator shape (cref.shapes (l->first).begin (db::ShapeIterator::Properties | db::ShapeIterator::Boxes | db::ShapeIterator::Polygons | db::ShapeIterator::Edges | db::ShapeIterator::Paths | db::ShapeIterator::Texts));
|
||||
while (! shape.at_end ()) {
|
||||
if (shape->has_prop_id () && shape->prop_id () != 0 && prop_ids_done.find (shape->prop_id ()) == prop_ids_done.end ()) {
|
||||
prop_ids_done.insert (shape->prop_id ());
|
||||
begin_table (propnames_table_pos);
|
||||
emit_propname_def (shape->prop_id ());
|
||||
m_progress.set (mp_stream->pos ());
|
||||
}
|
||||
shape.finish_array ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if needed, emit property name required for the PCell or meta info context information
|
||||
|
||||
if (m_write_context_info && m_propnames.find (std::string (klayout_context_name)) == m_propnames.end ()) {
|
||||
|
||||
bool has_context = false;
|
||||
for (auto cell = cells.begin (); cell != cells.end () && ! has_context; ++cell) {
|
||||
LayoutOrCellContextInfo ci;
|
||||
has_context = layout.has_context_info (*cell) && layout.get_context_info (*cell, ci);
|
||||
}
|
||||
|
||||
if (has_context) {
|
||||
m_propnames.insert (std::make_pair (std::string (klayout_context_name), m_propname_id++));
|
||||
begin_table (propnames_table_pos);
|
||||
write_record_id (7);
|
||||
write_nstring (klayout_context_name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
end_table (propnames_table_pos);
|
||||
}
|
||||
|
||||
void
|
||||
OASISWriter::write_propstring_table (size_t &propstrings_table_pos, const std::vector<db::cell_index_type> &cells, const db::Layout &layout, const std::vector<std::pair<unsigned int, LayerProperties> > &layers)
|
||||
{
|
||||
// write the property strings collected so far in the order of the ID's.
|
||||
|
||||
std::vector<std::pair<unsigned long, const std::string *> > rev_ps;
|
||||
rev_ps.reserve (m_propstrings.size ());
|
||||
for (auto p = m_propstrings.begin (); p != m_propstrings.end (); ++p) {
|
||||
rev_ps.push_back (std::make_pair (p->second, &p->first));
|
||||
}
|
||||
std::sort (rev_ps.begin (), rev_ps.end ());
|
||||
|
||||
tl_assert (rev_ps.size () == size_t (m_propstring_id));
|
||||
|
||||
for (auto p = rev_ps.begin (); p != rev_ps.end (); ++p) {
|
||||
tl_assert (p->first == (unsigned long)(p - rev_ps.begin ()));
|
||||
begin_table (propstrings_table_pos);
|
||||
write_record_id (9);
|
||||
write_bstring (p->second->c_str ());
|
||||
}
|
||||
|
||||
// collect and write the future property strings
|
||||
|
||||
std::set <db::properties_id_type> prop_ids_done;
|
||||
|
||||
for (auto cell = cells.begin (); cell != cells.end (); ++cell) {
|
||||
|
||||
const db::Cell &cref (layout.cell (*cell));
|
||||
|
||||
if (cref.prop_id () != 0 && prop_ids_done.find (cref.prop_id ()) == prop_ids_done.end ()) {
|
||||
prop_ids_done.insert (cref.prop_id ());
|
||||
begin_table (propstrings_table_pos);
|
||||
emit_propstring_def (cref.prop_id ());
|
||||
}
|
||||
|
||||
for (db::Cell::const_iterator inst = cref.begin (); ! inst.at_end (); ++inst) {
|
||||
if (inst->has_prop_id () && inst->prop_id () != 0 && prop_ids_done.find (inst->prop_id ()) == prop_ids_done.end ()) {
|
||||
prop_ids_done.insert (inst->prop_id ());
|
||||
begin_table (propstrings_table_pos);
|
||||
emit_propstring_def (inst->prop_id ());
|
||||
m_progress.set (mp_stream->pos ());
|
||||
}
|
||||
}
|
||||
|
||||
for (auto l = layers.begin (); l != layers.end (); ++l) {
|
||||
db::ShapeIterator shape (cref.shapes (l->first).begin (db::ShapeIterator::Properties | db::ShapeIterator::Boxes | db::ShapeIterator::Polygons | db::ShapeIterator::Edges | db::ShapeIterator::Paths | db::ShapeIterator::Texts));
|
||||
while (! shape.at_end ()) {
|
||||
if (shape->has_prop_id () && shape->prop_id () != 0 && prop_ids_done.find (shape->prop_id ()) == prop_ids_done.end ()) {
|
||||
prop_ids_done.insert (shape->prop_id ());
|
||||
begin_table (propstrings_table_pos);
|
||||
emit_propstring_def (shape->prop_id ());
|
||||
m_progress.set (mp_stream->pos ());
|
||||
}
|
||||
shape.finish_array ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (m_write_context_info) {
|
||||
|
||||
// emit property string id's required for the PCell and meta info context information
|
||||
std::vector <std::string> context_prop_strings;
|
||||
|
||||
for (auto cell = cells.begin (); cell != cells.end (); ++cell) {
|
||||
|
||||
m_progress.set (mp_stream->pos ());
|
||||
context_prop_strings.clear ();
|
||||
|
||||
if (layout.has_context_info (*cell) && layout.get_context_info (*cell, context_prop_strings)) {
|
||||
|
||||
for (auto c = context_prop_strings.begin (); c != context_prop_strings.end (); ++c) {
|
||||
if (m_propstrings.insert (std::make_pair (*c, m_propstring_id)).second) {
|
||||
begin_table (propstrings_table_pos);
|
||||
write_record_id (9);
|
||||
write_bstring (c->c_str ());
|
||||
++m_propstring_id;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
end_table (propstrings_table_pos);
|
||||
}
|
||||
|
||||
void
|
||||
OASISWriter::write_cellname_table (size_t &cellnames_table_pos, const std::vector<db::cell_index_type> &cells_by_index, const std::map<db::cell_index_type, size_t> *cell_positions, const db::Layout &layout)
|
||||
{
|
||||
bool sequential = true;
|
||||
for (auto cell = cells_by_index.begin (); cell != cells_by_index.end () && sequential; ++cell) {
|
||||
sequential = (*cell == db::cell_index_type (cell - cells_by_index.begin ()));
|
||||
}
|
||||
|
||||
// CELLNAME (implicit or explicit)
|
||||
for (auto cell = cells_by_index.begin (); cell != cells_by_index.end (); ++cell) {
|
||||
|
||||
begin_table (cellnames_table_pos);
|
||||
|
||||
write_record_id (sequential ? 3 : 4);
|
||||
write_nstring (layout.cell_name (*cell));
|
||||
if (! sequential) {
|
||||
write ((unsigned long) *cell);
|
||||
}
|
||||
|
||||
if (m_options.write_std_properties > 1) {
|
||||
|
||||
reset_modal_variables ();
|
||||
|
||||
// write S_BOUNDING_BOX entries
|
||||
|
||||
std::vector<tl::Variant> values;
|
||||
|
||||
// TODO: how to set the "depends on external cells" flag?
|
||||
db::Box bbox = layout.cell (*cell).bbox ();
|
||||
if (bbox.empty ()) {
|
||||
// empty box
|
||||
values.push_back (tl::Variant ((unsigned int) 0x2));
|
||||
bbox = db::Box (0, 0, 0, 0);
|
||||
} else {
|
||||
values.push_back (tl::Variant ((unsigned int) 0x0));
|
||||
}
|
||||
|
||||
values.push_back (tl::Variant (bbox.left ()));
|
||||
values.push_back (tl::Variant (bbox.bottom ()));
|
||||
values.push_back (tl::Variant (bbox.width ()));
|
||||
values.push_back (tl::Variant (bbox.height ()));
|
||||
|
||||
write_property_def (s_bounding_box_name, values, true);
|
||||
|
||||
// PROPERTY record with S_CELL_OFFSET
|
||||
if (cell_positions) {
|
||||
std::map<db::cell_index_type, size_t>::const_iterator pp = cell_positions->find (*cell);
|
||||
if (pp != cell_positions->end ()) {
|
||||
write_property_def (s_cell_offset_name, tl::Variant (pp->second), true);
|
||||
} else {
|
||||
write_property_def (s_cell_offset_name, tl::Variant (size_t (0)), true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
end_table (cellnames_table_pos);
|
||||
}
|
||||
|
||||
void
|
||||
OASISWriter::write_textstring_table (size_t &textstrings_table_pos, const std::vector<db::cell_index_type> &cells, const db::Layout &layout, const std::vector<std::pair<unsigned int, LayerProperties> > &layers)
|
||||
{
|
||||
// write present text strings
|
||||
|
||||
// collect present strings by ID
|
||||
std::vector<std::pair<unsigned long, const std::string *> > rev_ts;
|
||||
rev_ts.reserve (m_textstrings.size ());
|
||||
for (auto p = m_textstrings.begin (); p != m_textstrings.end (); ++p) {
|
||||
rev_ts.push_back (std::make_pair (p->second, &p->first));
|
||||
}
|
||||
std::sort (rev_ts.begin (), rev_ts.end ());
|
||||
|
||||
tl_assert (rev_ts.size () == size_t (m_textstring_id));
|
||||
|
||||
for (auto t = rev_ts.begin (); t != rev_ts.end (); ++t) {
|
||||
tl_assert (t->first == (unsigned long)(t - rev_ts.begin ()));
|
||||
begin_table (textstrings_table_pos);
|
||||
write_record_id (5);
|
||||
write_nstring (t->second->c_str ());
|
||||
}
|
||||
|
||||
// collect future test strings
|
||||
|
||||
for (auto cell = cells.begin (); cell != cells.end (); ++cell) {
|
||||
|
||||
const db::Cell &cref (layout.cell (*cell));
|
||||
for (auto l = layers.begin (); l != layers.end (); ++l) {
|
||||
db::ShapeIterator shape (cref.shapes (l->first).begin (db::ShapeIterator::Texts));
|
||||
while (! shape.at_end ()) {
|
||||
if (m_textstrings.insert (std::make_pair (shape->text_string (), m_textstring_id)).second) {
|
||||
begin_table (textstrings_table_pos);
|
||||
write_record_id (5);
|
||||
write_astring (shape->text_string ());
|
||||
++m_textstring_id;
|
||||
m_progress.set (mp_stream->pos ());
|
||||
}
|
||||
++shape;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
end_table (textstrings_table_pos);
|
||||
}
|
||||
|
||||
void
|
||||
OASISWriter::write_layername_table (size_t &layernames_table_pos, const std::vector <std::pair <unsigned int, db::LayerProperties> > &layers)
|
||||
{
|
||||
for (auto l = layers.begin (); l != layers.end (); ++l) {
|
||||
|
||||
if (! l->second.name.empty ()) {
|
||||
|
||||
begin_table (layernames_table_pos);
|
||||
|
||||
// write mappings to text layer and shape layers
|
||||
write_record_id (11);
|
||||
write_nstring (l->second.name.c_str ());
|
||||
write_byte (3);
|
||||
write ((unsigned long) l->second.layer);
|
||||
write_byte (3);
|
||||
write ((unsigned long) l->second.datatype);
|
||||
|
||||
write_record_id (12);
|
||||
write_nstring (l->second.name.c_str ());
|
||||
write_byte (3);
|
||||
write ((unsigned long) l->second.layer);
|
||||
write_byte (3);
|
||||
write ((unsigned long) l->second.datatype);
|
||||
|
||||
m_progress.set (mp_stream->pos ());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
end_table (layernames_table_pos);
|
||||
}
|
||||
|
||||
static bool must_write_cell (const db::Cell &cref)
|
||||
{
|
||||
// Don't write proxy cells which are not employed
|
||||
|
|
@ -1162,6 +1471,7 @@ static bool skip_cell_body (const db::Cell &cref)
|
|||
return cref.is_ghost_cell () && cref.empty ();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLayoutOptions &options)
|
||||
{
|
||||
|
|
@ -1172,6 +1482,7 @@ OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::Save
|
|||
m_layer = m_datatype = 0;
|
||||
m_in_cblock = false;
|
||||
m_cblock_buffer.clear ();
|
||||
m_write_context_info = options.write_context_info ();
|
||||
|
||||
m_options = options.get_options<OASISWriterOptions> ();
|
||||
mp_stream = &stream;
|
||||
|
|
@ -1252,6 +1563,7 @@ OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::Save
|
|||
// We will collect the standard properties here:
|
||||
|
||||
m_propstring_id = m_propname_id = 0;
|
||||
m_textstring_id = 0;
|
||||
m_proptables_written = false;
|
||||
std::vector<std::pair<std::string, unsigned int> > init_props;
|
||||
|
||||
|
|
@ -1303,306 +1615,47 @@ OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::Save
|
|||
write_props (layout.prop_id ());
|
||||
}
|
||||
|
||||
// build property name and value string tables
|
||||
|
||||
{
|
||||
|
||||
// write the property names collected so far in the order of the ID's.
|
||||
|
||||
std::vector<std::pair<unsigned long, std::string> > rev_pn;
|
||||
rev_pn.reserve (m_propnames.size ());
|
||||
for (std::map <std::string, unsigned long>::const_iterator p = m_propnames.begin (); p != m_propnames.end (); ++p) {
|
||||
rev_pn.push_back (std::make_pair (p->second, p->first));
|
||||
}
|
||||
std::sort (rev_pn.begin (), rev_pn.end ());
|
||||
|
||||
for (std::vector<std::pair<unsigned long, std::string> >::const_iterator p = rev_pn.begin (); p != rev_pn.end (); ++p) {
|
||||
tl_assert (p->first == (unsigned long)(p - rev_pn.begin ()));
|
||||
begin_table (propnames_table_pos);
|
||||
write_record_id (7);
|
||||
write_nstring (p->second.c_str ());
|
||||
}
|
||||
|
||||
// collect and write the future property names
|
||||
|
||||
std::set <db::properties_id_type> prop_ids_done;
|
||||
|
||||
for (std::vector<db::cell_index_type>::const_iterator cell = cells.begin (); cell != cells.end (); ++cell) {
|
||||
|
||||
const db::Cell &cref (layout.cell (*cell));
|
||||
|
||||
if (cref.prop_id () != 0) {
|
||||
begin_table (propnames_table_pos);
|
||||
emit_propname_def (cref.prop_id ());
|
||||
}
|
||||
|
||||
for (db::Cell::const_iterator inst = cref.begin (); ! inst.at_end (); ++inst) {
|
||||
if (inst->has_prop_id () && inst->prop_id () != 0 && prop_ids_done.find (inst->prop_id ()) == prop_ids_done.end ()) {
|
||||
prop_ids_done.insert (inst->prop_id ());
|
||||
begin_table (propnames_table_pos);
|
||||
emit_propname_def (inst->prop_id ());
|
||||
m_progress.set (mp_stream->pos ());
|
||||
}
|
||||
}
|
||||
|
||||
for (std::vector <std::pair <unsigned int, db::LayerProperties> >::const_iterator l = layers.begin (); l != layers.end (); ++l) {
|
||||
db::ShapeIterator shape (cref.shapes (l->first).begin (db::ShapeIterator::Properties | db::ShapeIterator::Boxes | db::ShapeIterator::Polygons | db::ShapeIterator::Edges | db::ShapeIterator::Paths | db::ShapeIterator::Texts));
|
||||
while (! shape.at_end ()) {
|
||||
if (shape->has_prop_id () && shape->prop_id () != 0 && prop_ids_done.find (shape->prop_id ()) == prop_ids_done.end ()) {
|
||||
prop_ids_done.insert (shape->prop_id ());
|
||||
begin_table (propnames_table_pos);
|
||||
emit_propname_def (shape->prop_id ());
|
||||
m_progress.set (mp_stream->pos ());
|
||||
}
|
||||
shape.finish_array ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (options.write_context_info ()) {
|
||||
|
||||
// emit property name required for the PCell context information
|
||||
std::vector <std::string> context_prop_strings;
|
||||
for (std::vector<db::cell_index_type>::const_iterator cell = cells.begin (); cell != cells.end (); ++cell) {
|
||||
|
||||
const db::Cell &cref (layout.cell (*cell));
|
||||
if (cref.is_proxy () && ! cref.is_top () && layout.get_context_info (*cell, context_prop_strings)) {
|
||||
|
||||
if (m_propnames.insert (std::make_pair (std::string (klayout_context_name), m_propname_id)).second) {
|
||||
begin_table (propnames_table_pos);
|
||||
write_record_id (7);
|
||||
write_nstring (klayout_context_name);
|
||||
++m_propname_id;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
end_table (propnames_table_pos);
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
// write the property strings collected so far in the order of the ID's.
|
||||
|
||||
std::vector<std::pair<unsigned long, std::string> > rev_ps;
|
||||
rev_ps.reserve (m_propstrings.size ());
|
||||
for (std::map <std::string, unsigned long>::const_iterator p = m_propstrings.begin (); p != m_propstrings.end (); ++p) {
|
||||
rev_ps.push_back (std::make_pair (p->second, p->first));
|
||||
}
|
||||
std::sort (rev_ps.begin (), rev_ps.end ());
|
||||
|
||||
for (std::vector<std::pair<unsigned long, std::string> >::const_iterator p = rev_ps.begin (); p != rev_ps.end (); ++p) {
|
||||
tl_assert (p->first == (unsigned long)(p - rev_ps.begin ()));
|
||||
begin_table (propstrings_table_pos);
|
||||
write_record_id (9);
|
||||
write_nstring (p->second.c_str ());
|
||||
}
|
||||
|
||||
// collect and write the future property strings
|
||||
|
||||
std::set <db::properties_id_type> prop_ids_done;
|
||||
|
||||
for (std::vector<db::cell_index_type>::const_iterator cell = cells.begin (); cell != cells.end (); ++cell) {
|
||||
|
||||
const db::Cell &cref (layout.cell (*cell));
|
||||
|
||||
if (cref.prop_id () != 0 && prop_ids_done.find (cref.prop_id ()) == prop_ids_done.end ()) {
|
||||
prop_ids_done.insert (cref.prop_id ());
|
||||
begin_table (propnames_table_pos);
|
||||
emit_propstring_def (cref.prop_id ());
|
||||
}
|
||||
|
||||
for (db::Cell::const_iterator inst = cref.begin (); ! inst.at_end (); ++inst) {
|
||||
if (inst->has_prop_id () && inst->prop_id () != 0 && prop_ids_done.find (inst->prop_id ()) == prop_ids_done.end ()) {
|
||||
prop_ids_done.insert (inst->prop_id ());
|
||||
begin_table (propstrings_table_pos);
|
||||
emit_propstring_def (inst->prop_id ());
|
||||
m_progress.set (mp_stream->pos ());
|
||||
}
|
||||
}
|
||||
|
||||
for (std::vector <std::pair <unsigned int, db::LayerProperties> >::const_iterator l = layers.begin (); l != layers.end (); ++l) {
|
||||
db::ShapeIterator shape (cref.shapes (l->first).begin (db::ShapeIterator::Properties | db::ShapeIterator::Boxes | db::ShapeIterator::Polygons | db::ShapeIterator::Edges | db::ShapeIterator::Paths | db::ShapeIterator::Texts));
|
||||
while (! shape.at_end ()) {
|
||||
if (shape->has_prop_id () && shape->prop_id () != 0 && prop_ids_done.find (shape->prop_id ()) == prop_ids_done.end ()) {
|
||||
prop_ids_done.insert (shape->prop_id ());
|
||||
begin_table (propstrings_table_pos);
|
||||
emit_propstring_def (shape->prop_id ());
|
||||
m_progress.set (mp_stream->pos ());
|
||||
}
|
||||
shape.finish_array ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (options.write_context_info ()) {
|
||||
|
||||
// emit property string id's required for the PCell context information
|
||||
std::vector <std::string> context_prop_strings;
|
||||
for (std::vector<db::cell_index_type>::const_iterator cell = cells.begin (); cell != cells.end (); ++cell) {
|
||||
|
||||
m_progress.set (mp_stream->pos ());
|
||||
|
||||
const db::Cell &cref (layout.cell (*cell));
|
||||
if (cref.is_proxy () && ! cref.is_top ()) {
|
||||
|
||||
context_prop_strings.clear ();
|
||||
if (layout.get_context_info (*cell, context_prop_strings)) {
|
||||
|
||||
for (std::vector <std::string>::const_iterator c = context_prop_strings.begin (); c != context_prop_strings.end (); ++c) {
|
||||
if (m_propstrings.insert (std::make_pair (*c, m_propstring_id)).second) {
|
||||
begin_table (propstrings_table_pos);
|
||||
write_record_id (9);
|
||||
write_bstring (c->c_str ());
|
||||
++m_propstring_id;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
end_table (propstrings_table_pos);
|
||||
|
||||
}
|
||||
|
||||
// Now we cannot open new property ID's in strict mode
|
||||
m_proptables_written = true;
|
||||
|
||||
// build cell name table now in non-strict mode (in strict mode it is written at the
|
||||
// end because then we have the cell positions fo S_CELL_OFFSET)
|
||||
|
||||
if (! m_options.strict_mode) {
|
||||
|
||||
size_t pos = 0;
|
||||
|
||||
bool sequential = true;
|
||||
for (std::vector<db::cell_index_type>::const_iterator cell = cells_by_index.begin (); cell != cells_by_index.end () && sequential; ++cell) {
|
||||
sequential = (*cell == db::cell_index_type (cell - cells_by_index.begin ()));
|
||||
}
|
||||
|
||||
// CELLNAME (implicit or explicit)
|
||||
for (std::vector<db::cell_index_type>::const_iterator cell = cells_by_index.begin (); cell != cells_by_index.end (); ++cell) {
|
||||
|
||||
begin_table (pos);
|
||||
|
||||
write_record_id (sequential ? 3 : 4);
|
||||
write_nstring (layout.cell_name (*cell));
|
||||
if (! sequential) {
|
||||
write ((unsigned long) *cell);
|
||||
}
|
||||
|
||||
if (m_options.write_std_properties > 1) {
|
||||
|
||||
reset_modal_variables ();
|
||||
|
||||
// write S_BOUNDING_BOX entries
|
||||
|
||||
std::vector<tl::Variant> values;
|
||||
|
||||
// TODO: how to set the "depends on external cells" flag?
|
||||
db::Box bbox = layout.cell (*cell).bbox ();
|
||||
if (bbox.empty ()) {
|
||||
// empty box
|
||||
values.push_back (tl::Variant ((unsigned int) 0x2));
|
||||
bbox = db::Box (0, 0, 0, 0);
|
||||
} else {
|
||||
values.push_back (tl::Variant ((unsigned int) 0x0));
|
||||
}
|
||||
|
||||
values.push_back (tl::Variant (bbox.left ()));
|
||||
values.push_back (tl::Variant (bbox.bottom ()));
|
||||
values.push_back (tl::Variant (bbox.width ()));
|
||||
values.push_back (tl::Variant (bbox.height ()));
|
||||
|
||||
write_property_def (s_bounding_box_name, values, true);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
end_table (pos);
|
||||
|
||||
}
|
||||
|
||||
// build text string table
|
||||
|
||||
{
|
||||
|
||||
unsigned int id = 0;
|
||||
|
||||
for (std::vector<db::cell_index_type>::const_iterator cell = cells.begin (); cell != cells.end (); ++cell) {
|
||||
|
||||
const db::Cell &cref (layout.cell (*cell));
|
||||
for (std::vector <std::pair <unsigned int, db::LayerProperties> >::const_iterator l = layers.begin (); l != layers.end (); ++l) {
|
||||
db::ShapeIterator shape (cref.shapes (l->first).begin (db::ShapeIterator::Texts));
|
||||
while (! shape.at_end ()) {
|
||||
if (m_textstrings.insert (std::make_pair (shape->text_string (), id)).second) {
|
||||
begin_table (textstrings_table_pos);
|
||||
write_record_id (5);
|
||||
write_astring (shape->text_string ());
|
||||
++id;
|
||||
m_progress.set (mp_stream->pos ());
|
||||
}
|
||||
++shape;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
end_table (textstrings_table_pos);
|
||||
|
||||
}
|
||||
|
||||
// write layernames table
|
||||
|
||||
{
|
||||
|
||||
for (std::vector <std::pair <unsigned int, db::LayerProperties> >::const_iterator l = layers.begin (); l != layers.end (); ++l) {
|
||||
|
||||
if (! l->second.name.empty ()) {
|
||||
|
||||
begin_table (layernames_table_pos);
|
||||
|
||||
// write mappings to text layer and shape layers
|
||||
write_record_id (11);
|
||||
write_nstring (l->second.name.c_str ());
|
||||
write_byte (3);
|
||||
write ((unsigned long) l->second.layer);
|
||||
write_byte (3);
|
||||
write ((unsigned long) l->second.datatype);
|
||||
|
||||
write_record_id (12);
|
||||
write_nstring (l->second.name.c_str ());
|
||||
write_byte (3);
|
||||
write ((unsigned long) l->second.layer);
|
||||
write_byte (3);
|
||||
write ((unsigned long) l->second.datatype);
|
||||
|
||||
m_progress.set (mp_stream->pos ());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
end_table (layernames_table_pos);
|
||||
|
||||
}
|
||||
|
||||
std::vector <std::string> context_prop_strings;
|
||||
|
||||
// write the global layout context information
|
||||
|
||||
if (options.write_context_info () && layout.has_context_info () && layout.get_context_info (context_prop_strings)) {
|
||||
|
||||
std::vector<tl::Variant> values;
|
||||
values.reserve (context_prop_strings.size ());
|
||||
for (auto i = context_prop_strings.begin (); i != context_prop_strings.end (); ++i) {
|
||||
values.push_back (tl::Variant (*i));
|
||||
}
|
||||
|
||||
write_property_def (klayout_context_name, values, false);
|
||||
|
||||
context_prop_strings.clear ();
|
||||
|
||||
}
|
||||
|
||||
// write the tables
|
||||
|
||||
if (! m_options.tables_at_end) {
|
||||
|
||||
write_propname_table (propnames_table_pos, cells, layout, layers);
|
||||
write_propstring_table (propstrings_table_pos, cells, layout, layers);
|
||||
|
||||
// Now we cannot open new property ID's in strict mode
|
||||
m_proptables_written = true;
|
||||
|
||||
// build cell name table now in non-strict mode (in strict mode it is written at the
|
||||
// end because then we have the cell positions fo S_CELL_OFFSET)
|
||||
if (! m_options.strict_mode) {
|
||||
write_cellname_table (cellnames_table_pos, cells_by_index, 0, layout);
|
||||
}
|
||||
|
||||
write_textstring_table (textstrings_table_pos, cells, layout, layers);
|
||||
write_layername_table (layernames_table_pos, layers);
|
||||
|
||||
}
|
||||
|
||||
// write cells
|
||||
|
||||
for (std::vector<db::cell_index_type>::const_iterator cell = cells.begin (); cell != cells.end (); ++cell) {
|
||||
|
||||
m_progress.set (mp_stream->pos ());
|
||||
|
|
@ -1630,7 +1683,7 @@ OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::Save
|
|||
}
|
||||
|
||||
// context information as property named KLAYOUT_CONTEXT
|
||||
if (cref.is_proxy () && options.write_context_info ()) {
|
||||
if (options.write_context_info () && layout.has_context_info (*cell)) {
|
||||
|
||||
context_prop_strings.clear ();
|
||||
|
||||
|
|
@ -1638,17 +1691,29 @@ OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::Save
|
|||
|
||||
write_record_id (28);
|
||||
write_byte (char (0xf6));
|
||||
unsigned long pnid = 0;
|
||||
std::map <std::string, unsigned long>::const_iterator pni = m_propnames.find (klayout_context_name);
|
||||
tl_assert (pni != m_propnames.end ());
|
||||
write (pni->second);
|
||||
if (pni == m_propnames.end ()) {
|
||||
pnid = m_propname_id++;
|
||||
m_propnames.insert (std::make_pair (klayout_context_name, pnid));
|
||||
} else {
|
||||
pnid = pni->second;
|
||||
}
|
||||
write (pnid);
|
||||
|
||||
write ((unsigned long) context_prop_strings.size ());
|
||||
|
||||
for (std::vector <std::string>::const_iterator c = context_prop_strings.begin (); c != context_prop_strings.end (); ++c) {
|
||||
write_byte (14); // b-string by reference number
|
||||
unsigned long psid = 0;
|
||||
std::map <std::string, unsigned long>::const_iterator psi = m_propstrings.find (*c);
|
||||
tl_assert (psi != m_propstrings.end ());
|
||||
write (psi->second);
|
||||
if (psi == m_propstrings.end ()) {
|
||||
psid = m_propstring_id++;
|
||||
m_propstrings.insert (std::make_pair (*c, psid)).second;
|
||||
} else {
|
||||
psid = psi->second;
|
||||
}
|
||||
write (psid);
|
||||
}
|
||||
|
||||
mm_last_property_name = klayout_context_name;
|
||||
|
|
@ -1686,66 +1751,31 @@ OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::Save
|
|||
|
||||
}
|
||||
|
||||
// write the tables if at end
|
||||
|
||||
if (m_options.tables_at_end) {
|
||||
|
||||
// do not consider future items as everything has been collected
|
||||
std::vector<cell_index_type> no_cells;
|
||||
std::vector <std::pair <unsigned int, db::LayerProperties> > no_layers;
|
||||
|
||||
write_propname_table (propnames_table_pos, no_cells, layout, no_layers);
|
||||
write_propstring_table (propstrings_table_pos, no_cells, layout, no_layers);
|
||||
|
||||
// Now we cannot open new property ID's in strict mode
|
||||
m_proptables_written = true;
|
||||
|
||||
write_textstring_table (textstrings_table_pos, no_cells, layout, no_layers);
|
||||
|
||||
// write all layers here
|
||||
write_layername_table (layernames_table_pos, layers);
|
||||
|
||||
}
|
||||
|
||||
// write cell table at the end in strict mode (in that mode we need the cell positions
|
||||
// for the S_CELL_OFFSET properties)
|
||||
|
||||
if (m_options.strict_mode) {
|
||||
|
||||
bool sequential = true;
|
||||
for (std::vector<db::cell_index_type>::const_iterator cell = cells_by_index.begin (); cell != cells_by_index.end () && sequential; ++cell) {
|
||||
sequential = (*cell == db::cell_index_type (cell - cells_by_index.begin ()));
|
||||
}
|
||||
|
||||
for (std::vector<db::cell_index_type>::const_iterator cell = cells_by_index.begin (); cell != cells_by_index.end (); ++cell) {
|
||||
|
||||
begin_table (cellnames_table_pos);
|
||||
|
||||
// CELLNAME (explicit)
|
||||
write_record_id (sequential ? 3 : 4);
|
||||
write_nstring (layout.cell_name (*cell));
|
||||
if (! sequential) {
|
||||
write ((unsigned long) *cell);
|
||||
}
|
||||
|
||||
reset_modal_variables ();
|
||||
|
||||
if (m_options.write_std_properties > 1) {
|
||||
|
||||
// write S_BOUNDING_BOX entries
|
||||
|
||||
std::vector<tl::Variant> values;
|
||||
|
||||
// TODO: how to set the "depends on external cells" flag?
|
||||
db::Box bbox = layout.cell (*cell).bbox ();
|
||||
if (bbox.empty ()) {
|
||||
// empty box
|
||||
values.push_back (tl::Variant ((unsigned int) 0x2));
|
||||
bbox = db::Box (0, 0, 0, 0);
|
||||
} else {
|
||||
values.push_back (tl::Variant ((unsigned int) 0x0));
|
||||
}
|
||||
|
||||
values.push_back (tl::Variant (bbox.left ()));
|
||||
values.push_back (tl::Variant (bbox.bottom ()));
|
||||
values.push_back (tl::Variant (bbox.width ()));
|
||||
values.push_back (tl::Variant (bbox.height ()));
|
||||
|
||||
write_property_def (s_bounding_box_name, values, true);
|
||||
|
||||
}
|
||||
|
||||
// PROPERTY record with S_CELL_OFFSET
|
||||
std::map<db::cell_index_type, size_t>::const_iterator pp = cell_positions.find (*cell);
|
||||
if (pp != cell_positions.end ()) {
|
||||
write_property_def (s_cell_offset_name, tl::Variant (pp->second), true);
|
||||
} else {
|
||||
write_property_def (s_cell_offset_name, tl::Variant (size_t (0)), true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
end_table (cellnames_table_pos);
|
||||
|
||||
if (m_options.tables_at_end || m_options.strict_mode) {
|
||||
write_cellname_table (cellnames_table_pos, cells_by_index, &cell_positions, layout);
|
||||
}
|
||||
|
||||
// END record
|
||||
|
|
@ -2341,9 +2371,15 @@ OASISWriter::write (const db::Text &text, db::properties_id_type prop_id, const
|
|||
m_progress.set (mp_stream->pos ());
|
||||
|
||||
db::Trans trans = text.trans ();
|
||||
|
||||
unsigned long text_id = 0;
|
||||
std::map <std::string, unsigned long>::const_iterator ts = m_textstrings.find (text.string ());
|
||||
tl_assert (ts != m_textstrings.end ());
|
||||
unsigned long text_id = ts->second;
|
||||
if (ts == m_textstrings.end ()) {
|
||||
text_id = m_textstring_id++;
|
||||
m_textstrings.insert (std::make_pair (text.string (), text_id));
|
||||
} else {
|
||||
text_id = ts->second;
|
||||
}
|
||||
|
||||
unsigned char info = 0x20;
|
||||
|
||||
|
|
|
|||
|
|
@ -203,12 +203,14 @@ private:
|
|||
const db::Cell *mp_cell;
|
||||
int m_layer;
|
||||
int m_datatype;
|
||||
bool m_write_context_info;
|
||||
std::vector<db::Vector> m_pointlist;
|
||||
tl::OutputMemoryStream m_cblock_buffer;
|
||||
tl::OutputMemoryStream m_cblock_compressed;
|
||||
bool m_in_cblock;
|
||||
unsigned long m_propname_id;
|
||||
unsigned long m_propstring_id;
|
||||
unsigned long m_textstring_id;
|
||||
bool m_proptables_written;
|
||||
|
||||
std::map <std::string, unsigned long> m_textstrings;
|
||||
|
|
@ -308,6 +310,12 @@ private:
|
|||
void write_pointlist (const std::vector<db::Vector> &pointlist, bool for_polygons);
|
||||
|
||||
void write_inst_with_rep (const db::CellInstArray &inst, db::properties_id_type prop_id, const db::Vector &disp, const db::Repetition &rep);
|
||||
|
||||
void write_propname_table (size_t &propnames_table_pos, const std::vector<db::cell_index_type> &cells, const Layout &layout, const std::vector<std::pair<unsigned int, LayerProperties> > &layers);
|
||||
void write_propstring_table (size_t &propstrings_table_pos, const std::vector<db::cell_index_type> &cells, const Layout &layout, const std::vector<std::pair<unsigned int, LayerProperties> > &layers);
|
||||
void write_cellname_table (size_t &cellnames_table_pos, const std::vector<db::cell_index_type> &cells_by_index, const std::map<cell_index_type, size_t> *cell_positions, const Layout &layout);
|
||||
void write_textstring_table (size_t &textstrings_table_pos, const std::vector<db::cell_index_type> &cells, const Layout &layout, const std::vector<std::pair<unsigned int, LayerProperties> > &layers);
|
||||
void write_layername_table (size_t &layernames_table_pos, const std::vector<std::pair<unsigned int, LayerProperties> > &layers);
|
||||
};
|
||||
|
||||
} // namespace db
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
|
||||
#include <cstdlib>
|
||||
|
||||
void run_test (tl::TestBase *_this, const char *file, bool scaling_test, int compr, bool recompress)
|
||||
void run_test (tl::TestBase *_this, const char *file, bool scaling_test, int compr, bool recompress, bool tables_at_end)
|
||||
{
|
||||
{
|
||||
db::Manager m (false);
|
||||
|
|
@ -60,6 +60,7 @@ void run_test (tl::TestBase *_this, const char *file, bool scaling_test, int com
|
|||
db::OASISWriterOptions oasis_options;
|
||||
oasis_options.write_cblocks = false;
|
||||
oasis_options.strict_mode = false;
|
||||
oasis_options.tables_at_end = tables_at_end;
|
||||
options.set_options (oasis_options);
|
||||
writer.write (layout, stream, options);
|
||||
}
|
||||
|
|
@ -115,6 +116,7 @@ void run_test (tl::TestBase *_this, const char *file, bool scaling_test, int com
|
|||
db::OASISWriterOptions oasis_options;
|
||||
oasis_options.write_cblocks = true;
|
||||
oasis_options.strict_mode = true;
|
||||
oasis_options.tables_at_end = tables_at_end;
|
||||
options.set_options (oasis_options);
|
||||
writer.write (layout, stream, options);
|
||||
}
|
||||
|
|
@ -164,6 +166,7 @@ void run_test (tl::TestBase *_this, const char *file, bool scaling_test, int com
|
|||
db::OASISWriterOptions oasis_options;
|
||||
oasis_options.write_cblocks = false;
|
||||
oasis_options.strict_mode = false;
|
||||
oasis_options.tables_at_end = tables_at_end;
|
||||
oasis_options.write_std_properties = 2;
|
||||
options.set_options (oasis_options);
|
||||
writer.write (layout, stream, options);
|
||||
|
|
@ -214,6 +217,7 @@ void run_test (tl::TestBase *_this, const char *file, bool scaling_test, int com
|
|||
db::OASISWriterOptions oasis_options;
|
||||
oasis_options.write_cblocks = true;
|
||||
oasis_options.strict_mode = true;
|
||||
oasis_options.tables_at_end = tables_at_end;
|
||||
oasis_options.write_std_properties = 2;
|
||||
options.set_options (oasis_options);
|
||||
writer.write (layout, stream, options);
|
||||
|
|
@ -255,6 +259,7 @@ void run_test (tl::TestBase *_this, const char *file, bool scaling_test, int com
|
|||
db::OASISWriterOptions oasis_options;
|
||||
oasis_options.compression_level = compr;
|
||||
oasis_options.recompress = recompress;
|
||||
oasis_options.tables_at_end = tables_at_end;
|
||||
options.set_options (oasis_options);
|
||||
options.set_scale_factor (3.0);
|
||||
options.set_dbu (0.0005);
|
||||
|
|
@ -308,11 +313,14 @@ void run_test (tl::TestBase *_this, const char *file, bool scaling_test, int com
|
|||
void run_test (tl::TestBase *_this, const char *file, bool scaling_test = true)
|
||||
{
|
||||
for (int recompress = 0; recompress < 2; ++recompress) {
|
||||
run_test (_this, file, scaling_test, 0, recompress);
|
||||
run_test (_this, file, scaling_test, 1, recompress);
|
||||
run_test (_this, file, scaling_test, 2, recompress);
|
||||
run_test (_this, file, scaling_test, 10, recompress);
|
||||
run_test (_this, file, scaling_test, 0, recompress, false);
|
||||
run_test (_this, file, scaling_test, 1, recompress, false);
|
||||
run_test (_this, file, scaling_test, 2, recompress, false);
|
||||
run_test (_this, file, scaling_test, 10, recompress, false);
|
||||
}
|
||||
|
||||
// tables at end
|
||||
run_test (_this, file, scaling_test, 2, false, true);
|
||||
}
|
||||
|
||||
TEST(1)
|
||||
|
|
@ -1860,3 +1868,111 @@ TEST(120_IrregularInstRepetitions)
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
// Meta info
|
||||
static void
|
||||
run_test130 (tl::TestBase *_this, bool strict, bool tables_at_end)
|
||||
{
|
||||
db::Layout layout_org;
|
||||
|
||||
layout_org.add_cell ("U");
|
||||
db::cell_index_type ci = layout_org.add_cell ("X");
|
||||
|
||||
layout_org.add_meta_info ("a", db::MetaInfo ("description", 17.5, true));
|
||||
layout_org.add_meta_info ("b", db::MetaInfo ("", "value", true));
|
||||
|
||||
layout_org.add_meta_info (ci, "a", db::MetaInfo ("dd", true, true));
|
||||
layout_org.add_meta_info (ci, "c", db::MetaInfo ("d", -1, true));
|
||||
|
||||
std::string tmp_file = _this->tmp_file ("tmp_OASISWriter1.oas");
|
||||
|
||||
{
|
||||
tl::OutputStream out (tmp_file);
|
||||
db::OASISWriterOptions oasis_options;
|
||||
oasis_options.strict_mode = strict;
|
||||
oasis_options.tables_at_end = tables_at_end;
|
||||
db::SaveLayoutOptions options;
|
||||
options.set_format ("OASIS");
|
||||
options.set_options (oasis_options);
|
||||
db::Writer writer (options);
|
||||
writer.write (layout_org, out);
|
||||
}
|
||||
|
||||
db::Layout layout_read;
|
||||
|
||||
{
|
||||
tl::InputStream in (tmp_file);
|
||||
db::Reader reader (in);
|
||||
reader.read (layout_read);
|
||||
}
|
||||
|
||||
EXPECT_EQ (layout_read.meta_info ("x").value.to_string (), "nil");
|
||||
EXPECT_EQ (layout_read.meta_info ("a").value.to_string (), "17.5");
|
||||
EXPECT_EQ (layout_read.meta_info ("a").description, "description");
|
||||
EXPECT_EQ (layout_read.meta_info ("b").value.to_string (), "value");
|
||||
EXPECT_EQ (layout_read.meta_info ("b").description, "");
|
||||
|
||||
db::cell_index_type ci2 = layout_read.cell_by_name ("X").second;
|
||||
|
||||
EXPECT_EQ (layout_read.meta_info (ci2, "x").value.to_string (), "nil");
|
||||
EXPECT_EQ (layout_read.meta_info (ci2, "a").value.to_string (), "true");
|
||||
EXPECT_EQ (layout_read.meta_info (ci2, "a").description, "dd");
|
||||
EXPECT_EQ (layout_read.meta_info (ci2, "c").value.to_string (), "-1");
|
||||
EXPECT_EQ (layout_read.meta_info (ci2, "c").description, "d");
|
||||
|
||||
tmp_file = _this->tmp_file ("tmp_OASISWriter2.oas");
|
||||
|
||||
{
|
||||
tl::OutputStream out (tmp_file);
|
||||
db::OASISWriterOptions oasis_options;
|
||||
oasis_options.strict_mode = strict;
|
||||
oasis_options.tables_at_end = tables_at_end;
|
||||
db::SaveLayoutOptions options;
|
||||
options.set_format ("OASIS");
|
||||
options.set_options (oasis_options);
|
||||
options.set_write_context_info (false);
|
||||
db::Writer writer (options);
|
||||
writer.write (layout_org, out);
|
||||
}
|
||||
|
||||
layout_read = db::Layout ();
|
||||
|
||||
{
|
||||
tl::InputStream in (tmp_file);
|
||||
db::Reader reader (in);
|
||||
reader.read (layout_read);
|
||||
}
|
||||
|
||||
EXPECT_EQ (layout_read.meta_info ("x").value.to_string (), "nil");
|
||||
EXPECT_EQ (layout_read.meta_info ("a").value.to_string (), "nil");
|
||||
EXPECT_EQ (layout_read.meta_info ("b").value.to_string (), "nil");
|
||||
|
||||
ci2 = layout_read.cell_by_name ("X").second;
|
||||
|
||||
EXPECT_EQ (layout_read.meta_info (ci2, "x").value.to_string (), "nil");
|
||||
EXPECT_EQ (layout_read.meta_info ("a").value.to_string (), "nil");
|
||||
EXPECT_EQ (layout_read.meta_info ("b").value.to_string (), "nil");
|
||||
}
|
||||
|
||||
// Meta info
|
||||
|
||||
TEST(130a)
|
||||
{
|
||||
run_test130 (_this, false, false);
|
||||
}
|
||||
|
||||
TEST(130b)
|
||||
{
|
||||
run_test130 (_this, true, false);
|
||||
}
|
||||
|
||||
TEST(130c)
|
||||
{
|
||||
run_test130 (_this, false, true);
|
||||
}
|
||||
|
||||
TEST(130d)
|
||||
{
|
||||
run_test130 (_this, true, true);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1146,7 +1146,7 @@ public:
|
|||
|
||||
std::string lyr_file = data.get_layer_properties_file ();
|
||||
if (! lyr_file.empty ()) {
|
||||
layout.add_meta_info (db::MetaInfo ("layer-properties-file", "Layer Properties File", lyr_file));
|
||||
layout.add_meta_info ("layer-properties-file", db::MetaInfo ("Layer Properties File", lyr_file));
|
||||
}
|
||||
|
||||
return m_layers;
|
||||
|
|
|
|||
|
|
@ -1044,36 +1044,39 @@ class DBLayoutTests2_TestClass < TestBase
|
|||
end
|
||||
|
||||
# Meta information
|
||||
def test_12
|
||||
def test_12a
|
||||
|
||||
mi = RBA::LayoutMetaInfo::new("myinfo", "a")
|
||||
|
||||
assert_equal(mi.name, "myinfo")
|
||||
assert_equal(mi.description, "")
|
||||
assert_equal(mi.value, "a")
|
||||
assert_equal(mi.is_persisted?, false)
|
||||
|
||||
mi.name = "x"
|
||||
mi.description = "y"
|
||||
mi.value = "z"
|
||||
mi.persisted = true
|
||||
|
||||
assert_equal(mi.name, "x")
|
||||
assert_equal(mi.description, "y")
|
||||
assert_equal(mi.value, "z")
|
||||
assert_equal(mi.is_persisted?, true)
|
||||
|
||||
ly = RBA::Layout::new
|
||||
|
||||
ly.add_meta_info(RBA::LayoutMetaInfo::new("myinfo", "a"))
|
||||
ly.add_meta_info(RBA::LayoutMetaInfo::new("another", "42", "description"))
|
||||
ly.add_meta_info(RBA::LayoutMetaInfo::new("another", 42, "description"))
|
||||
|
||||
assert_equal(ly.meta_info_value("myinfo"), "a")
|
||||
assert_equal(ly.meta_info_value("doesnotexist"), "")
|
||||
assert_equal(ly.meta_info_value("another"), "42")
|
||||
assert_equal(ly.meta_info_value("doesnotexist"), nil)
|
||||
assert_equal(ly.meta_info_value("another"), 42)
|
||||
|
||||
a = []
|
||||
ly.each_meta_info { |mi| a << mi.name }
|
||||
assert_equal(a.join(","), "myinfo,another")
|
||||
a = []
|
||||
ly.each_meta_info { |mi| a << mi.value }
|
||||
ly.each_meta_info { |mi| a << mi.value.to_s }
|
||||
assert_equal(a.join(","), "a,42")
|
||||
a = []
|
||||
ly.each_meta_info { |mi| a << mi.description }
|
||||
|
|
@ -1081,13 +1084,64 @@ class DBLayoutTests2_TestClass < TestBase
|
|||
|
||||
ly.add_meta_info(RBA::LayoutMetaInfo::new("myinfo", "b"))
|
||||
assert_equal(ly.meta_info_value("myinfo"), "b")
|
||||
assert_equal(ly.meta_info_value("doesnotexist"), "")
|
||||
assert_equal(ly.meta_info_value("another"), "42")
|
||||
assert_equal(ly.meta_info_value("doesnotexist"), nil)
|
||||
assert_equal(ly.meta_info_value("another"), 42)
|
||||
|
||||
ly.remove_meta_info("doesnotexist") # should not fail
|
||||
|
||||
ly.remove_meta_info("myinfo")
|
||||
assert_equal(ly.meta_info_value("myinfo"), "")
|
||||
assert_equal(ly.meta_info_value("doesnotexist"), "")
|
||||
assert_equal(ly.meta_info_value("another"), "42")
|
||||
assert_equal(ly.meta_info_value("myinfo"), nil)
|
||||
assert_equal(ly.meta_info_value("doesnotexist"), nil)
|
||||
assert_equal(ly.meta_info_value("another"), 42)
|
||||
|
||||
assert_equal(ly.meta_info("doesnotexist"), nil)
|
||||
assert_equal(ly.meta_info("another").value, 42)
|
||||
assert_equal(ly.meta_info("another").description, "description")
|
||||
|
||||
ly.clear_meta_info
|
||||
assert_equal(ly.meta_info_value("another"), nil)
|
||||
assert_equal(ly.meta_info("another"), nil)
|
||||
|
||||
# cellwise
|
||||
|
||||
c1 = ly.create_cell("X")
|
||||
c2 = ly.create_cell("U")
|
||||
|
||||
c1.add_meta_info(RBA::LayoutMetaInfo::new("a", true))
|
||||
c1.add_meta_info(RBA::LayoutMetaInfo::new("b", [ 1, 17, 42 ]))
|
||||
|
||||
assert_equal(c2.meta_info("a"), nil)
|
||||
assert_equal(c2.meta_info_value("a"), nil)
|
||||
|
||||
a = []
|
||||
c2.each_meta_info { |mi| a << mi.value.to_s }
|
||||
assert_equal(a.join(","), "")
|
||||
|
||||
assert_equal(c1.meta_info("a").value, true)
|
||||
assert_equal(c1.meta_info("b").value, [ 1, 17, 42 ])
|
||||
assert_equal(c1.meta_info_value("b"), [ 1, 17, 42 ])
|
||||
|
||||
a = []
|
||||
c1.each_meta_info { |mi| a << mi.value.to_s }
|
||||
assert_equal(a.join(","), "true,[1, 17, 42]")
|
||||
|
||||
c1.remove_meta_info("doesnotexist") # should not fail
|
||||
|
||||
a = []
|
||||
c1.each_meta_info { |mi| a << mi.value.to_s }
|
||||
assert_equal(a.join(","), "true,[1, 17, 42]")
|
||||
|
||||
c1.remove_meta_info("b")
|
||||
|
||||
a = []
|
||||
c1.each_meta_info { |mi| a << mi.value.to_s }
|
||||
assert_equal(a.join(","), "true")
|
||||
|
||||
c1.clear_meta_info
|
||||
|
||||
a = []
|
||||
c1.each_meta_info { |mi| a << mi.value.to_s }
|
||||
assert_equal(a.join(","), "")
|
||||
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue