Next steps - persistency of meta info

This commit is contained in:
Matthias Koefferlein 2023-04-18 21:24:26 +02:00
parent b14c630ce9
commit 78da3effa2
9 changed files with 368 additions and 107 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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,20 @@ 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);
}
}
// -----------------------------------------------------------------
@ -593,7 +621,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 +634,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 +661,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 +678,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);
@ -2446,10 +2474,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 {
@ -2459,8 +2562,19 @@ 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
{
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;
}
}
}
const db::Cell *cptr = &cell (cell_index);
const db::ColdProxy *cold_proxy = dynamic_cast <const db::ColdProxy *> (cptr);
@ -2509,6 +2623,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)
{
@ -2540,11 +2675,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 ()) {
@ -2594,11 +2729,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 ()) {
@ -2626,7 +2761,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 ()) {
@ -2723,7 +2858,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;
@ -2754,7 +2889,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);

View File

@ -417,14 +417,15 @@ 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);
};
@ -1015,27 +1016,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.
@ -1051,7 +1094,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.
@ -1073,7 +1116,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
@ -2026,7 +2069,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);
};
/**

View File

@ -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);

View File

@ -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);

View File

@ -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 (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;

View File

@ -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)
{
@ -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

View File

@ -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