From ab36a660fb1291cd9a2878be62de44c5756c4fab Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 13 Dec 2020 19:11:12 +0100 Subject: [PATCH] WIP: cold references - keep reference information while libraries are not there or cells are missing. --- src/db/db/db.pro | 2 + src/db/db/dbColdProxy.cc | 128 +++++++ src/db/db/dbColdProxy.h | 111 ++++++ src/db/db/dbLayout.cc | 340 ++++++++++++------ src/db/db/dbLayout.h | 69 +++- src/db/db/dbLibrary.cc | 30 +- src/db/db/dbLibraryManager.cc | 16 + src/db/db/dbLibraryProxy.cc | 2 - .../gds2/db_plugin/dbGDS2ReaderBase.cc | 10 +- 9 files changed, 578 insertions(+), 130 deletions(-) create mode 100644 src/db/db/dbColdProxy.cc create mode 100644 src/db/db/dbColdProxy.h diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 94c5d291b..82c60a7bb 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -19,6 +19,7 @@ SOURCES = \ dbClipboard.cc \ dbClipboardData.cc \ dbClip.cc \ + dbColdProxy.cc \ dbCommonReader.cc \ dbEdge.cc \ dbEdgePair.cc \ @@ -214,6 +215,7 @@ HEADERS = \ dbClipboardData.h \ dbClipboard.h \ dbClip.h \ + dbColdProxy.h \ dbCommonReader.h \ dbEdge.h \ dbEdgePair.h \ diff --git a/src/db/db/dbColdProxy.cc b/src/db/db/dbColdProxy.cc new file mode 100644 index 000000000..a387f2838 --- /dev/null +++ b/src/db/db/dbColdProxy.cc @@ -0,0 +1,128 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 "dbColdProxy.h" +#include "dbLibraryManager.h" +#include "dbLibrary.h" +#include "dbLayout.h" +#include "dbLayoutUtils.h" + +#include "tlThreads.h" + +namespace db +{ + +static tl::Mutex s_map_mutex; +static std::map > s_proxies_per_library_name; + +const tl::weak_collection & +ColdProxy::cold_proxies_per_lib_name (const std::string &libname) +{ + tl::MutexLocker locker (&s_map_mutex); + + std::map >::const_iterator i = s_proxies_per_library_name.find (libname); + if (i != s_proxies_per_library_name.end ()) { + return i->second; + } else { + static tl::weak_collection s_empty; + return s_empty; + } +} + +ColdProxy::ColdProxy (db::cell_index_type ci, db::Layout &layout, const ProxyContextInfo &info) + : Cell (ci, layout), mp_context_info (new ProxyContextInfo (info)) +{ + if (! info.lib_name.empty ()) { + tl::MutexLocker locker (&s_map_mutex); + s_proxies_per_library_name [info.lib_name].push_back (this); + } +} + +ColdProxy::~ColdProxy () +{ + delete mp_context_info; + mp_context_info = 0; +} + +Cell * +ColdProxy::clone (Layout &layout) const +{ + Cell *cell = new ColdProxy (db::Cell::cell_index (), layout, *mp_context_info); + // copy the cell content + *cell = *this; + return cell; +} + +std::string +ColdProxy::get_basic_name () const +{ + if (! mp_context_info->pcell_name.empty ()) { + return "" + mp_context_info->pcell_name; + } else if (! mp_context_info->cell_name.empty ()) { + return "" + mp_context_info->cell_name; + } else { + return Cell::get_basic_name (); + } +} + +std::string +ColdProxy::get_display_name () const +{ + if (! mp_context_info->lib_name.empty ()) { + std::string stem = "" + mp_context_info->lib_name + "."; + if (! mp_context_info->pcell_name.empty ()) { + return stem + mp_context_info->pcell_name; + } else if (! mp_context_info->cell_name.empty ()) { + return stem + mp_context_info->cell_name; + } else { + return stem + ""; + } + } else { + return Cell::get_display_name (); + } +} + +std::string +ColdProxy::get_qualified_name () const +{ + if (! mp_context_info->lib_name.empty ()) { + std::string stem = "" + mp_context_info->lib_name + "."; + if (! mp_context_info->pcell_name.empty ()) { + if (mp_context_info->pcell_parameters.empty ()) { + return stem + mp_context_info->pcell_name; + } else { + // TODO: list parameters? Might be long. + return stem + mp_context_info->pcell_name + "(...)"; + } + } else if (! mp_context_info->cell_name.empty ()) { + return stem + mp_context_info->cell_name; + } else { + return stem + ""; + } + } else { + return Cell::get_qualified_name (); + } +} + +} + diff --git a/src/db/db/dbColdProxy.h b/src/db/db/dbColdProxy.h new file mode 100644 index 000000000..13a586c1c --- /dev/null +++ b/src/db/db/dbColdProxy.h @@ -0,0 +1,111 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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_dbColdProxy +#define HDR_dbColdProxy + +#include "dbCommon.h" + +#include "dbTypes.h" +#include "dbCell.h" + +#include "tlObject.h" + +namespace db +{ + +struct ProxyContextInfo; + +/** + * @brief A cell specialization: a cold proxy representing a library or PCell which has gone out of scope + * + * If a PCell or library cell gets disconnected - for example, because the technology has changed or during + * development of PCell code - this proxy replaces the original one. It stores the connection information, so + * it can be regenerated when it becomes valid again. + */ +class DB_PUBLIC ColdProxy + : public Cell, public tl::Object +{ +public: + /** + * @brief The constructor + * + * Creates a cold proxy represented by the ProxyContextInfo data. + */ + ColdProxy (db::cell_index_type ci, db::Layout &layout, const ProxyContextInfo &info); + + /** + * @brief The destructor + */ + ~ColdProxy (); + + /** + * @brief Cloning + */ + virtual Cell *clone (Layout &layout) const; + + /** + * @brief Get the library id + */ + const ProxyContextInfo &context_info () const + { + return *mp_context_info; + } + + /** + * @brief Indicates that this cell is a proxy cell + */ + virtual bool is_proxy () const + { + return true; + } + + /** + * @brief Gets a list of cold proxies for a given library name + */ + static const tl::weak_collection &cold_proxies_per_lib_name (const std::string &libname); + + /** + * @brief Gets the basic name + */ + virtual std::string get_basic_name () const; + + /** + * @brief Gets the display name + */ + virtual std::string get_display_name () const; + + /** + * @brief Gets the qualified name + */ + virtual std::string get_qualified_name () const; + +private: + ProxyContextInfo *mp_context_info; +}; + +} + +#endif + + diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index 4aa45d4b4..a9c94c2ad 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -30,6 +30,7 @@ #include "dbPCellVariant.h" #include "dbPCellDeclaration.h" #include "dbLibraryProxy.h" +#include "dbColdProxy.h" #include "dbLibraryManager.h" #include "dbLibrary.h" #include "dbRegion.h" @@ -260,6 +261,65 @@ LayerIterator::operator*() const return std::pair (m_layer_index, &m_layout.get_properties (m_layer_index)); } +// ----------------------------------------------------------------- +// Implementation of the ProxyContextInfo class + +ProxyContextInfo +ProxyContextInfo::deserialize (std::vector::const_iterator from, std::vector::const_iterator to) +{ + ProxyContextInfo info; + + for (std::vector::const_iterator i = from; i != to; ++i) { + + tl::Extractor ex (i->c_str ()); + + if (ex.test ("LIB=")) { + + info.lib_name = ex.skip (); + + } else if (ex.test ("P(")) { + + std::pair vv; + + ex.read_word_or_quoted (vv.first); + ex.test (")"); + ex.test ("="); + ex.read (vv.second); + + info.pcell_parameters.insert (vv); + + } else if (ex.test ("PCELL=")) { + + info.pcell_name = ex.skip (); + + } else if (ex.test ("CELL=")) { + + info.cell_name = ex.skip (); + + } + + } + + return info; +} + +void +ProxyContextInfo::serialize (std::vector &strings) +{ + if (! lib_name.empty ()) { + strings.push_back ("LIB=" + lib_name); + } + for (std::map ::const_iterator 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 ()) { + strings.push_back ("PCELL=" + pcell_name); + } + if (! cell_name.empty ()) { + strings.push_back ("CELL=" + cell_name); + } +} + // ----------------------------------------------------------------- // Implementation of the Layout class @@ -522,12 +582,10 @@ Layout::set_technology_name (const std::string &tech) if (! pn.first) { - // substitute by static layout cell - // @@@ TODO: keep reference so we don't loose the connection immediately. - std::string name = cell_name (ci); - db::Cell *old_cell = take_cell (ci); - insert_cell (ci, name, new db::Cell (*old_cell)); - delete old_cell; + // substitute by a cold proxy + db::ProxyContextInfo info; + get_context_info (ci, info); + create_cold_proxy_as (info, ci); } else { @@ -537,12 +595,10 @@ Layout::set_technology_name (const std::string &tech) const db::PCellDeclaration *new_pcell_decl = new_lib->layout ().pcell_declaration (pn.second); if (! old_pcell_decl || ! new_pcell_decl) { - // substitute by static layout cell - // @@@ TODO: keep reference so we don't loose the connection immediately. - std::string name = cell_name (ci); - db::Cell *old_cell = take_cell (ci); - insert_cell (ci, name, new db::Cell (*old_cell)); - delete old_cell; + // substitute by a cold proxy + db::ProxyContextInfo info; + get_context_info (ci, info); + create_cold_proxy_as (info, ci); } else { @@ -566,12 +622,10 @@ Layout::set_technology_name (const std::string &tech) if (! cn.first) { - // unlink this proxy: substitute by static layout cell - // @@@ TODO: keep reference so we don't loose the connection immediately. - std::string name = cell_name (ci); - db::Cell *old_cell = take_cell (ci); - insert_cell (ci, name, new db::Cell (*old_cell)); - delete old_cell; + // unlink this proxy: substitute by a cold proxy + db::ProxyContextInfo info; + get_context_info (ci, info); + create_cold_proxy_as (info, ci); } else { @@ -588,6 +642,9 @@ Layout::set_technology_name (const std::string &tech) } m_tech_name = tech; + + // we may have re-established a connection for pending ("cold") proxies so we can try to restore them + restore_proxies (); } void @@ -1948,8 +2005,26 @@ static const std::vector &gauge_parameters (const std::vectorunregister (); + if (retain_layout) { + new_cell->Cell::operator= (*old_cell); + } + } + + m_cells.erase (iterator (old_cell)); + m_cells.push_back_ptr (new_cell); + m_cell_ptrs [target_cell_index] = new_cell; +} + void -Layout::get_pcell_variant_as (pcell_id_type pcell_id, const std::vector &p, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping) +Layout::get_pcell_variant_as (pcell_id_type pcell_id, const std::vector &p, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping, bool retain_layout) { pcell_header_type *header = pcell_header (pcell_id); tl_assert (header != 0); @@ -1963,16 +2038,13 @@ Layout::get_pcell_variant_as (pcell_id_type pcell_id, const std::vectortransacting ())); tl_assert (m_cell_ptrs [target_cell_index] != 0); - invalidate_hier (); - - m_cells.erase (iterator (m_cell_ptrs [target_cell_index])); - pcell_variant_type *variant = new pcell_variant_type (target_cell_index, *this, pcell_id, parameters); - m_cells.push_back_ptr (variant); - m_cell_ptrs [target_cell_index] = variant; + replace_cell (target_cell_index, variant, retain_layout); - // produce the layout - variant->update (layer_mapping); + if (! retain_layout) { + // produce the layout unless we retained it + variant->update (layer_mapping); + } } cell_index_type @@ -2316,8 +2388,20 @@ Layout::get_pcell_variant_cell (cell_index_type cell_index, const std::vector &context_info) const +bool +Layout::get_context_info (cell_index_type cell_index, std::vector &strings) const +{ + ProxyContextInfo info; + if (! get_context_info (cell_index, info)) { + return false; + } else { + info.serialize (strings); + return true; + } +} + +bool +Layout::get_context_info (cell_index_type cell_index, ProxyContextInfo &info) const { const db::Cell *cptr = &cell (cell_index); const db::Layout *ly = this; @@ -2333,7 +2417,7 @@ Layout::get_context_info (cell_index_type cell_index, std::vector // one level of library indirection ly = &lib->layout (); cptr = &ly->cell (lib_proxy->library_cell_index ()); - context_info.push_back ("LIB=" + lib->get_name ()); + info.lib_name = lib->get_name (); } @@ -2347,19 +2431,36 @@ Layout::get_context_info (cell_index_type cell_index, std::vector const std::vector &pcp = pcell_decl->parameter_declarations (); std::vector::const_iterator pd = pcp.begin (); for (std::vector::const_iterator p = pcell_variant->parameters ().begin (); p != pcell_variant->parameters ().end () && pd != pcp.end (); ++p, ++pd) { - context_info.push_back ("P(" + tl::to_word_or_quoted_string (pd->get_name ()) + ")=" + p->to_parsable_string ()); + info.pcell_parameters.insert (std::make_pair (pd->get_name (), *p)); } const db::PCellHeader *header = ly->pcell_header (pcell_variant->pcell_id ()); - context_info.push_back ("PCELL=" + header->get_name ()); + info.pcell_name = header->get_name (); } else { - context_info.push_back ("CELL=" + std::string (ly->cell_name (cptr->cell_index ()))); + info.cell_name = ly->cell_name (cptr->cell_index ()); } return true; } +void +Layout::restore_proxies (ImportLayerMapping *layer_mapping) +{ + std::vector cold_proxies; + + for (iterator c = begin (); c != end (); ++c) { + db::ColdProxy *proxy = dynamic_cast (c.operator-> ()); + if (proxy) { + cold_proxies.push_back (proxy); + } + } + + for (std::vector::const_iterator p = cold_proxies.begin (); p != cold_proxies.end (); ++p) { + recover_proxy_as ((*p)->cell_index (), (*p)->context_info (), layer_mapping); + } +} + bool Layout::recover_proxy_as (cell_index_type cell_index, std::vector ::const_iterator from, std::vector ::const_iterator to, ImportLayerMapping *layer_mapping) { @@ -2367,17 +2468,21 @@ Layout::recover_proxy_as (cell_index_type cell_index, std::vector : return false; } - tl::Extractor ex (from->c_str ()); + return recover_proxy_as (cell_index, ProxyContextInfo::deserialize (from, to), layer_mapping); +} - if (ex.test ("LIB=")) { +bool +Layout::recover_proxy_as (cell_index_type cell_index, const ProxyContextInfo &info, ImportLayerMapping *layer_mapping) +{ + if (! info.lib_name.empty ()) { - std::string lib_name = ex.skip (); - Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (lib_name, m_tech_name); - if (! lib) { - return false; + db::Cell *lib_cell = 0; + + Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (info.lib_name, m_tech_name); + if (lib) { + lib_cell = lib->layout ().recover_proxy_no_lib (info); } - db::Cell *lib_cell = lib->layout ().recover_proxy (from + 1, to); if (lib_cell) { get_lib_proxy_as (lib, lib_cell->cell_index (), cell_index, layer_mapping); return true; @@ -2385,38 +2490,28 @@ Layout::recover_proxy_as (cell_index_type cell_index, std::vector : } else { - std::map parameters; + if (! info.pcell_name.empty ()) { - while (from != to && (ex = tl::Extractor (from->c_str ())).test ("P(")) { - - std::string name; - ex.read_word_or_quoted (name); - ex.test (")"); - ex.test ("="); - - ex.read (parameters.insert (std::make_pair (name, tl::Variant ())).first->second); - - ++from; - - } - - if (ex.test ("PCELL=")) { - - std::pair pc = pcell_by_name (ex.skip ()); + std::pair pc = pcell_by_name (info.pcell_name.c_str ()); if (pc.first) { - get_pcell_variant_as (pc.second, pcell_declaration (pc.second)->map_parameters (parameters), cell_index, layer_mapping); + get_pcell_variant_as (pc.second, pcell_declaration (pc.second)->map_parameters (info.pcell_parameters), cell_index, layer_mapping); return true; } - } else if (ex.test ("CELL=")) { + } else if (! info.cell_name.empty ()) { - // This should not happen. A cell (given by the cell index) cannot be proxy to another cell in the same layout. + // This should not happen. A cell (given by the cell name) cannot be proxy to another cell in the same layout. tl_assert (false); } } + if (! dynamic_cast (m_cell_ptrs [cell_index])) { + // create a cold proxy representing the context information so we can restore it + create_cold_proxy_as (info, cell_index); + } + return false; } @@ -2427,55 +2522,54 @@ Layout::recover_proxy (std::vector ::const_iterator from, std::vect return 0; } - tl::Extractor ex (from->c_str ()); + return recover_proxy (ProxyContextInfo::deserialize (from, to)); +} - if (ex.test ("LIB=")) { +db::Cell * +Layout::recover_proxy (const ProxyContextInfo &info) +{ + if (! info.lib_name.empty ()) { - std::string lib_name = ex.skip (); - Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (lib_name, m_tech_name); - if (! lib) { - return 0; + Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (info.lib_name, m_tech_name); + + db::Cell *lib_cell = 0; + if (lib) { + lib_cell = lib->layout ().recover_proxy_no_lib (info); } - db::Cell *lib_cell = lib->layout ().recover_proxy (from + 1, to); if (lib_cell) { - cell_index_type cell_index = get_lib_proxy (lib, lib_cell->cell_index ()); - return &cell (cell_index); + return m_cell_ptrs [get_lib_proxy (lib, lib_cell->cell_index ())]; } } else { - std::map parameters; - - while (from != to && (ex = tl::Extractor (from->c_str ())).test ("P(")) { - - std::string name; - ex.read_word_or_quoted (name); - ex.test (")"); - ex.test ("="); - - ex.read (parameters.insert (std::make_pair (name, tl::Variant ())).first->second); - - ++from; - + db::Cell *proxy = recover_proxy_no_lib (info); + if (proxy) { + return proxy; } - if (ex.test ("PCELL=")) { + } - std::pair pc = pcell_by_name (ex.skip ()); - if (pc.first) { - cell_index_type cell_index = get_pcell_variant (pc.second, pcell_declaration (pc.second)->map_parameters (parameters)); - return &cell (cell_index); - } + return m_cell_ptrs [create_cold_proxy (info)]; +} - } else if (ex.test ("CELL=")) { +db::Cell * +Layout::recover_proxy_no_lib (const ProxyContextInfo &info) +{ + if (! info.pcell_name.empty ()) { - std::pair cc = cell_by_name (ex.skip ()); - if (cc.first) { - return &cell (cc.second); - } + std::pair pc = pcell_by_name (info.pcell_name.c_str ()); + if (pc.first) { + cell_index_type cell_index = get_pcell_variant (pc.second, pcell_declaration (pc.second)->map_parameters (info.pcell_parameters)); + return m_cell_ptrs [cell_index]; + } - } + } else if (! info.cell_name.empty ()) { + + std::pair cc = cell_by_name (info.cell_name.c_str ()); + if (cc.first) { + return m_cell_ptrs [cc.second]; + } } @@ -2507,21 +2601,18 @@ Layout::unregister_lib_proxy (db::LibraryProxy *lib_proxy) } void -Layout::get_lib_proxy_as (Library *lib, cell_index_type cell_index, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping) +Layout::get_lib_proxy_as (Library *lib, cell_index_type cell_index, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping, bool retain_layout) { tl_assert (! (manager () && manager ()->transacting ())); tl_assert (m_cell_ptrs [target_cell_index] != 0); - invalidate_hier (); - - m_cells.erase (iterator (m_cell_ptrs [target_cell_index])); - LibraryProxy *proxy = new LibraryProxy (target_cell_index, *this, lib->get_id (), cell_index); - m_cells.push_back_ptr (proxy); - m_cell_ptrs [target_cell_index] = proxy; + replace_cell (target_cell_index, proxy, retain_layout); - // produce the layout - proxy->update (layer_mapping); + if (! retain_layout) { + // produce the layout unless we retained it + proxy->update (layer_mapping); + } } cell_index_type @@ -2552,7 +2643,7 @@ Layout::get_lib_proxy (Library *lib, cell_index_type cell_index) manager ()->queue (this, new NewRemoveCellOp (new_index, m_cell_names [new_index], false /*new*/, 0)); } - // produce the layout + // produce the layout proxy->update (); return new_index; @@ -2560,6 +2651,47 @@ Layout::get_lib_proxy (Library *lib, cell_index_type cell_index) } } +cell_index_type +Layout::create_cold_proxy (const db::ProxyContextInfo &info) +{ + // create a new unique name + std::string b; + if (! info.cell_name.empty ()) { + b = info.cell_name; + } else if (! info.pcell_name.empty ()) { + b = info.pcell_name; + } + if (m_cell_map.find (b.c_str ()) != m_cell_map.end ()) { + b = uniquify_cell_name (b.c_str ()); + } + + // create a new cell (a LibraryProxy) + cell_index_type new_index = allocate_new_cell (); + + ColdProxy *proxy = new ColdProxy (new_index, *this, info); + m_cells.push_back_ptr (proxy); + m_cell_ptrs [new_index] = proxy; + + // enter it's index and cell_name + register_cell_name (b.c_str (), new_index); + + if (manager () && manager ()->transacting ()) { + manager ()->queue (this, new NewRemoveCellOp (new_index, m_cell_names [new_index], false /*new*/, 0)); + } + + return new_index; +} + +void +Layout::create_cold_proxy_as (const db::ProxyContextInfo &info, cell_index_type target_cell_index) +{ + tl_assert (! (manager () && manager ()->transacting ())); + tl_assert (m_cell_ptrs [target_cell_index] != 0); + + ColdProxy *proxy = new ColdProxy (target_cell_index, *this, info); + replace_cell (target_cell_index, proxy, true); +} + void Layout::redo (db::Op *op) { diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h index c79629567..779a1ee2f 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -457,6 +457,20 @@ public: virtual std::pair map_layer (const LayerProperties &lprops) = 0; }; +/** + * @brief A binary object representing context information for regenerating library proxies and PCells + */ +struct DB_PUBLIC ProxyContextInfo +{ + std::string lib_name; + std::string cell_name; + std::string pcell_name; + std::map pcell_parameters; + + static ProxyContextInfo deserialize (std::vector::const_iterator from, std::vector::const_iterator to); + void serialize (std::vector &strings); +}; + /** * @brief The layout object * @@ -863,8 +877,9 @@ public: * @param parameters The PCell parameters * @param cell_index The cell index which is to be replaced by the PCell variant proxy * @param layer_mapping The optional layer mapping object that maps the PCell layers to the layout's layers + * @param retain_layout Set to true for not using update() on the PCell but to retain existing layout (conservative approach) */ - void get_pcell_variant_as (pcell_id_type pcell_id, const std::vector ¶meters, cell_index_type cell_index, ImportLayerMapping *layer_mapping = 0); + void get_pcell_variant_as (pcell_id_type pcell_id, const std::vector ¶meters, cell_index_type cell_index, ImportLayerMapping *layer_mapping = 0, bool retain_layout = false); /** * @brief Get the PCell variant cell of a existing cell with new parameters @@ -1010,9 +1025,21 @@ public: /** * @brief Get the proxy cell (index) for a given library an cell index (inside that library) * - * This method replaces the cell with the given target cell index by a library. + * @param retain_layout Set to true for not using update() on the PCell but to retain existing layout (conservative approach) + * + * This method replaces the cell with the given target cell index by a library. */ - void get_lib_proxy_as (Library *lib, cell_index_type cell_index, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping = 0); + void get_lib_proxy_as (Library *lib, cell_index_type cell_index, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping = 0, bool retain_layout = false); + + /** + * @brief Creates a cold proxy representing the given context information + */ + cell_index_type create_cold_proxy (const db::ProxyContextInfo &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); /** * @brief Get the context information for a given cell (for writing into a file) @@ -1024,6 +1051,11 @@ public: */ bool get_context_info (cell_index_type cell_index, std::vector &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; + /** * @brief Recover a proxy cell from the given context info. * @@ -1035,6 +1067,11 @@ public: */ db::Cell *recover_proxy (std::vector ::const_iterator from, std::vector ::const_iterator to); + /** + * @brief Recover a proxy cell from the given binary context info object. + */ + db::Cell *recover_proxy (const ProxyContextInfo &context_info); + /** * @brief Recover a proxy cell from the given context info. * @@ -1050,6 +1087,27 @@ public: */ bool recover_proxy_as (cell_index_type cell_index, std::vector ::const_iterator from, std::vector ::const_iterator to, ImportLayerMapping *layer_mapping = 0); + /** + * @brief Recover a proxy cell from the given binary context info object + * + * 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); + + /** + * @brief Restores proxies as far as possible + * + * This feature can be used after a library update to make sure that proxies are updated. + * Library updates may enabled lost connections which are help in cold proxies. This method will recover + * these connections. + */ + void restore_proxies(ImportLayerMapping *layer_mapping = 0); + + /** + * @brief Replaces the given cell index with the new cell + */ + void replace_cell (cell_index_type target_cell_index, db::Cell *new_cell, bool retain_layout); + /** * @brief Delete a cell plus the subcells not used otherwise * @@ -1853,6 +1911,11 @@ private: * @brief Implementation of prune_cells and some prune_subcells variants */ void do_prune_cells_or_subcells (const std::set &ids, int levels, bool subcells); + + /** + * @brief Recovers a proxy without considering the library from context_info + */ + db::Cell *recover_proxy_no_lib (const ProxyContextInfo &context_info); }; /** diff --git a/src/db/db/dbLibrary.cc b/src/db/db/dbLibrary.cc index 3103f0c56..c22dff473 100644 --- a/src/db/db/dbLibrary.cc +++ b/src/db/db/dbLibrary.cc @@ -191,12 +191,10 @@ Library::remap_to (db::Library *other) if (! pn.first) { - // substitute by static layout cell - // @@@ TODO: keep reference so we don't loose the connection immediately. - std::string name = r->first->cell_name (ci); - db::Cell *old_cell = r->first->take_cell (ci); - r->first->insert_cell (ci, name, new db::Cell (*old_cell)); - delete old_cell; + // substitute by a cold proxy + db::ProxyContextInfo info; + r->first->get_context_info (ci, info); + r->first->create_cold_proxy_as (info, ci); } else { @@ -204,12 +202,10 @@ Library::remap_to (db::Library *other) const db::PCellDeclaration *new_pcell_decl = other->layout ().pcell_declaration (pn.second); if (! old_pcell_decl || ! new_pcell_decl) { - // substitute by static layout cell - // @@@ TODO: keep reference so we don't loose the connection immediately. - std::string name = r->first->cell_name (ci); - db::Cell *old_cell = r->first->take_cell (ci); - r->first->insert_cell (ci, name, new db::Cell (*old_cell)); - delete old_cell; + // substitute by a cold proxy + db::ProxyContextInfo info; + r->first->get_context_info (ci, info); + r->first->create_cold_proxy_as (info, ci); } else { @@ -234,12 +230,10 @@ Library::remap_to (db::Library *other) if (! cn.first) { - // unlink this proxy: substitute by static layout cell - // @@@ TODO: keep reference so we don't loose the connection immediately. - std::string name = r->first->cell_name (ci); - db::Cell *old_cell = r->first->take_cell (ci); - r->first->insert_cell (ci, name, new db::Cell (*old_cell)); - delete old_cell; + // substitute by a cold proxy + db::ProxyContextInfo info; + r->first->get_context_info (ci, info); + r->first->create_cold_proxy_as (info, ci); } else { diff --git a/src/db/db/dbLibraryManager.cc b/src/db/db/dbLibraryManager.cc index 2e5e7df86..88e526c7c 100644 --- a/src/db/db/dbLibraryManager.cc +++ b/src/db/db/dbLibraryManager.cc @@ -24,6 +24,7 @@ #include "dbLibraryManager.h" #include "dbLibrary.h" #include "dbCommon.h" +#include "dbColdProxy.h" #include "tlAssert.h" #include "tlStaticObjects.h" @@ -158,6 +159,21 @@ LibraryManager::register_lib (Library *library) l = m_lib_by_name.find (library->get_name ()); m_lib_by_name.insert (l, std::make_pair (library->get_name (), id)); + // take care of cold referrers - these may not get valid + // NOTE: this will try to substitute the cold proxies we may have generated during "remap_to" above, but + // "restore_proxies" takes care not to re-substitute cold proxies. + + const tl::weak_collection &cold_proxies = db::ColdProxy::cold_proxies_per_lib_name (library->get_name ()); + std::set to_refresh; + for (tl::weak_collection::const_iterator p = cold_proxies.begin (); p != cold_proxies.end (); ++p) { + to_refresh.insert (const_cast (p->layout ())); + } + + for (std::set::const_iterator l = to_refresh.begin (); l != to_refresh.end (); ++l) { + (*l)->restore_proxies (0); + } + + // issue the change notification changed_event (); return id; diff --git a/src/db/db/dbLibraryProxy.cc b/src/db/db/dbLibraryProxy.cc index 195c82b99..241df85ad 100644 --- a/src/db/db/dbLibraryProxy.cc +++ b/src/db/db/dbLibraryProxy.cc @@ -99,8 +99,6 @@ LibraryProxy::remap (lib_id_type lib_id, cell_index_type lib_cell_index) m_lib_id = lib_id; m_library_cell_index = lib_cell_index; - // It's important to register at the new library, but the old library is about to the deleted, so we don't unregister. - // That does not disturb the old library iterating over the layouts. db::Library *lib = db::LibraryManager::instance ().lib (m_lib_id); if (lib) { lib->register_proxy (this, layout ()); diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc b/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc index d79793638..71b6561fc 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc @@ -358,17 +358,21 @@ GDS2ReaderBase::do_read (db::Layout &layout) db::cell_index_type cell_index = make_cell (layout, m_cellname); - db::Cell *cell = &layout.cell (cell_index); - + bool ignore_cell = false; std::map >::const_iterator ctx = m_context_info.find (m_cellname); if (ctx != m_context_info.end ()) { GDS2ReaderLayerMapping layer_mapping (this, &layout, m_create_layers); if (layout.recover_proxy_as (cell_index, ctx->second.begin (), ctx->second.end (), &layer_mapping)) { // ignore everything in that cell since it is created by the import: - cell = 0; + ignore_cell = true; } } + db::Cell *cell = 0; + if (! ignore_cell) { + cell = &layout.cell (cell_index); + } + long attr = 0; db::PropertiesRepository::properties_set cell_properties;