From 4226ab0078657ae859adb3fd3260d1d9d80c7fa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20K=C3=B6fferlein?= Date: Sat, 12 Feb 2022 21:26:28 +0100 Subject: [PATCH] =?UTF-8?q?issue-996=20Providing=20a=20"refresh"=20functio?= =?UTF-8?q?n=20for=20triggering=20a=20refresh=20from=20inside=20t=E2=80=A6?= =?UTF-8?q?=20(#998)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Providing a "refresh" function for triggering a refresh from inside the lib Some other glitches were fixed too: * LibraryManager wasn't thread-safe * Library destructor wasn't unregistering * Crash when re-registering the same library again * In LibrariesTest normalization of layouts must not include re-creation of library references to avoid side effects. Save without context. * Added missing files * Fixed unit tests. --- src/db/db/dbLibrary.cc | 18 +- src/db/db/dbLibrary.h | 7 + src/db/db/dbLibraryManager.cc | 148 ++++-- src/db/db/dbLibraryManager.h | 10 + src/db/db/dbLibraryProxy.cc | 2 + src/db/db/dbTestSupport.cc | 12 +- src/db/db/dbTestSupport.h | 10 +- src/db/db/gsiDeclDbLibrary.cc | 6 + src/db/unit_tests/dbLibrariesTests.cc | 673 ++++++++++++-------------- testdata/gds/lib_test2.gds | Bin 1464 -> 876 bytes testdata/gds/lib_test4.gds | Bin 706 -> 520 bytes testdata/gds/lib_test6a.gds | Bin 0 -> 298 bytes testdata/gds/lib_test6b.gds | Bin 0 -> 298 bytes testdata/ruby/dbLibrary.rb | 4 +- 14 files changed, 464 insertions(+), 426 deletions(-) create mode 100644 testdata/gds/lib_test6a.gds create mode 100644 testdata/gds/lib_test6b.gds diff --git a/src/db/db/dbLibrary.cc b/src/db/db/dbLibrary.cc index 5620373c1..5c012dc52 100644 --- a/src/db/db/dbLibrary.cc +++ b/src/db/db/dbLibrary.cc @@ -25,25 +25,31 @@ #include "dbLibraryProxy.h" #include "dbPCellDeclaration.h" #include "dbPCellVariant.h" +#include "dbLibraryManager.h" + +#include namespace db { Library::Library() - : m_id (0), m_layout (true) + : m_id (std::numeric_limits::max ()), m_layout (true) { m_layout.set_library (this); } Library::Library(const Library &d) - : gsi::ObjectBase (), tl::Object (), m_name (d.m_name), m_description (d.m_description), m_id (0), m_layout (d.m_layout) + : gsi::ObjectBase (), tl::Object (), m_name (d.m_name), m_description (d.m_description), m_id (std::numeric_limits::max ()), m_layout (d.m_layout) { m_layout.set_library (this); } Library::~Library () { - // .. nothing yet .. + // unregister if not done yet + if (db::LibraryManager::initialized ()) { + db::LibraryManager::instance ().unregister_lib (this); + } } bool @@ -139,6 +145,12 @@ Library::is_retired (const db::cell_index_type library_cell_index) const return (i != m_refcount.end () && j != m_retired_count.end () && i->second == j->second); } +void +Library::refresh () +{ + remap_to (this); +} + void Library::remap_to (db::Library *other) { diff --git a/src/db/db/dbLibrary.h b/src/db/db/dbLibrary.h index dea48cba4..3dcfc8f50 100644 --- a/src/db/db/dbLibrary.h +++ b/src/db/db/dbLibrary.h @@ -204,6 +204,13 @@ public: */ bool is_retired (const cell_index_type library_cell_index) const; + /** + * @brief Refreshes the library on all clients + * + * This will refresh PCells, retire cells (turn them into "cold proxies") and reload layouts. + */ + void refresh (); + /** * @brief Remap the library proxies to a different library * diff --git a/src/db/db/dbLibraryManager.cc b/src/db/db/dbLibraryManager.cc index 7b7e24d6b..140c4d12f 100644 --- a/src/db/db/dbLibraryManager.cc +++ b/src/db/db/dbLibraryManager.cc @@ -29,6 +29,7 @@ #include "tlAssert.h" #include "tlStaticObjects.h" #include "tlClassRegistry.h" +#include "tlThreads.h" #include @@ -69,13 +70,15 @@ LibraryManager::~LibraryManager () std::pair LibraryManager::lib_by_name (const std::string &name, const std::set &for_technologies) const { + tl::MutexLocker locker (&m_lock); + iterator l; if (! for_technologies.empty ()) { l = m_lib_by_name.find (name); while (l != m_lib_by_name.end () && l->first == name) { - const db::Library *lptr = lib (l->second); + const db::Library *lptr = lib_internal (l->second); bool found = lptr->for_technologies (); for (std::set::const_iterator t = for_technologies.begin (); t != for_technologies.end () && found; ++t) { if (! lptr->is_for_technology (*t)) { @@ -93,7 +96,7 @@ LibraryManager::lib_by_name (const std::string &name, const std::setfirst == name) { - if (! lib (l->second)->for_technologies ()) { + if (! lib_internal (l->second)->for_technologies ()) { return std::make_pair (true, l->second); } ++l; @@ -103,68 +106,99 @@ LibraryManager::lib_by_name (const std::string &name, const std::setget_name ()); + { + tl::MutexLocker locker (&m_lock); - for (lib_id_type id = 0; id < m_libs.size (); ++id) { - if (m_libs [id] == library) { - library->remap_to (0); - delete library; - m_libs [id] = 0; - break; + for (lib_id_type id = 0; id < m_libs.size (); ++id) { + if (m_libs [id] == library) { + m_lib_by_name.erase (library->get_name ()); + m_libs [id] = 0; + break; + } } } + + library->remap_to (0); + library->set_id (std::numeric_limits::max ()); +} + +void +LibraryManager::delete_lib (Library *library) +{ + if (library) { + unregister_lib (library); + delete library; + } } lib_id_type LibraryManager::register_lib (Library *library) { - library->keep (); // marks the library owned by the C++ side of GSI + lib_id_type id = std::numeric_limits::max (); + Library *old_lib = 0; - lib_id_type id; - for (id = 0; id < m_libs.size (); ++id) { - if (m_libs [id] == 0) { - break; + { + tl::MutexLocker locker (&m_lock); + + if (library->get_id () < m_libs.size ()) { + // ignore re-registration attempts (they crash) + tl_assert (m_libs [library->get_id ()] == library); + return library->get_id (); } - } - if (id == m_libs.size ()) { - m_libs.push_back (library); - } else { - m_libs [id] = library; - } + library->keep (); // marks the library owned by the C++ side of GSI - library->set_id (id); - - // if the new library replaces the old one, remap existing library proxies before deleting the library - // (replacement is done only when all technologies are substituted) - lib_name_map::iterator l = m_lib_by_name.find (library->get_name ()); - bool found = false; - while (l != m_lib_by_name.end () && l->first == library->get_name ()) { - if (m_libs [l->second] && m_libs [l->second]->get_technologies () == library->get_technologies ()) { - found = true; - break; + for (id = 0; id < m_libs.size (); ++id) { + if (m_libs [id] == 0) { + break; + } } - ++l; + + if (id == m_libs.size ()) { + m_libs.push_back (library); + } else { + m_libs [id] = library; + } + + library->set_id (id); + + // if the new library replaces the old one, remap existing library proxies before deleting the library + // (replacement is done only when all technologies are substituted) + lib_name_map::iterator l = m_lib_by_name.find (library->get_name ()); + bool found = false; + while (l != m_lib_by_name.end () && l->first == library->get_name ()) { + if (m_libs [l->second] && m_libs [l->second]->get_technologies () == library->get_technologies ()) { + found = true; + break; + } + ++l; + } + + if (found) { + // substitute + old_lib = m_libs [l->second]; + m_libs [l->second] = 0; + m_lib_by_name.erase (l); + } + + // insert new lib as first of this name + l = m_lib_by_name.find (library->get_name ()); + m_lib_by_name.insert (l, std::make_pair (library->get_name (), id)); } - if (found) { - // substitute - m_libs [l->second]->remap_to (library); - delete m_libs [l->second]; - m_libs [l->second] = 0; - m_lib_by_name.erase (l); + if (old_lib) { + old_lib->remap_to (library); + old_lib->set_id (std::numeric_limits::max ()); + delete old_lib; + old_lib = 0; } - // insert new lib as first of this name - 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. @@ -187,6 +221,13 @@ LibraryManager::register_lib (Library *library) Library * LibraryManager::lib (lib_id_type id) const +{ + tl::MutexLocker locker (&m_lock); + return lib_internal (id); +} + +Library * +LibraryManager::lib_internal (lib_id_type id) const { if (id >= m_libs.size ()) { return 0; @@ -198,17 +239,24 @@ LibraryManager::lib (lib_id_type id) const void LibraryManager::clear () { - if (m_libs.empty ()) { - return; - } - - // empty the library table before we delete them - this avoid accesses to invalid libraries while doing so. std::vector libs; - libs.swap (m_libs); - m_lib_by_name.clear (); + + { + tl::MutexLocker locker (&m_lock); + + if (m_libs.empty ()) { + return; + } + + // empty the library table before we delete them - this avoid accesses to invalid libraries while doing so. + libs.swap (m_libs); + m_lib_by_name.clear (); + } for (std::vector::iterator l = libs.begin (); l != libs.end (); ++l) { if (*l) { + (*l)->remap_to (0); + (*l)->set_id (std::numeric_limits::max ()); delete *l; } } diff --git a/src/db/db/dbLibraryManager.h b/src/db/db/dbLibraryManager.h index d4c818518..f4cd25609 100644 --- a/src/db/db/dbLibraryManager.h +++ b/src/db/db/dbLibraryManager.h @@ -29,6 +29,7 @@ #include "dbTypes.h" #include "tlClassRegistry.h" #include "tlEvents.h" +#include "tlThreads.h" #include #include @@ -185,6 +186,13 @@ public: */ lib_id_type register_lib (Library *library); + /** + * @brief Unregisters a library + * + * This will release the library from the manager's control and lifetime management. + */ + void unregister_lib (Library *library); + /** * @brief Deletes a library */ @@ -207,8 +215,10 @@ public: private: std::vector m_libs; lib_name_map m_lib_by_name; + mutable tl::Mutex m_lock; LibraryManager (); + Library *lib_internal (lib_id_type id) const; }; } diff --git a/src/db/db/dbLibraryProxy.cc b/src/db/db/dbLibraryProxy.cc index 657fc566f..8401acc48 100644 --- a/src/db/db/dbLibraryProxy.cc +++ b/src/db/db/dbLibraryProxy.cc @@ -89,6 +89,8 @@ void LibraryProxy::remap (lib_id_type lib_id, cell_index_type lib_cell_index) { if (lib_id == m_lib_id && m_library_cell_index == lib_cell_index) { + // we trigger an update in any case to implement the library's "refresh" + update (); return; } diff --git a/src/db/db/dbTestSupport.cc b/src/db/db/dbTestSupport.cc index bb41c713c..aa5522df0 100644 --- a/src/db/db/dbTestSupport.cc +++ b/src/db/db/dbTestSupport.cc @@ -62,10 +62,10 @@ void compare_layouts (tl::TestBase *_this, const db::Layout &layout, const std:: std::string tmp_file; db::SaveLayoutOptions options; - if (norm == WriteGDS2) { + if ((norm & db::NormFileMask) == WriteGDS2) { tmp_file = _this->tmp_file (tl::sprintf ("tmp_%x.gds", hash)); options.set_format ("GDS2"); - } else if (norm == WriteOAS) { + } else if ((norm & db::NormFileMask) == WriteOAS) { tmp_file = _this->tmp_file (tl::sprintf ("tmp_%x.oas", hash)); options.set_format ("OASIS"); } else { @@ -74,13 +74,17 @@ void compare_layouts (tl::TestBase *_this, const db::Layout &layout, const std:: options.set_format_from_filename (tmp_file); } + if ((norm & NoContext) != 0) { + options.set_write_context_info (false); + } + { tl::OutputStream stream (tmp_file.c_str ()); db::Writer writer (options); writer.write (const_cast (layout), stream); } - if (norm == WriteGDS2 || norm == WriteOAS) { + if ((norm & db::NormFileMask) == WriteGDS2 || (norm & db::NormFileMask) == WriteOAS) { // read all layers from the original layout, so the layer table is the same for (db::Layout::layer_iterator l = layout.begin_layers (); l != layout.end_layers (); ++l) { @@ -133,7 +137,7 @@ void compare_layouts (tl::TestBase *_this, const db::Layout &layout, const std:: equal = db::compare_layouts (*subject, layout_au, (n > 0 ? db::layout_diff::f_silent : db::layout_diff::f_verbose) - | (norm == AsPolygons ? db::layout_diff::f_boxes_as_polygons + db::layout_diff::f_paths_as_polygons : 0) + | ((norm & AsPolygons) != 0 ? db::layout_diff::f_boxes_as_polygons + db::layout_diff::f_paths_as_polygons : 0) | db::layout_diff::f_flatten_array_insts /*| db::layout_diff::f_no_text_details | db::layout_diff::f_no_text_orientation*/ , tolerance, 100 /*max diff lines*/); diff --git a/src/db/db/dbTestSupport.h b/src/db/db/dbTestSupport.h index 430bacb76..9b031fdce 100644 --- a/src/db/db/dbTestSupport.h +++ b/src/db/db/dbTestSupport.h @@ -51,10 +51,12 @@ class Texts; */ enum NormalizationMode { - NoNormalization, // no normalization - take the test subject as it is - AsPolygons, // paths and boxes are treated as polygons - WriteGDS2, // normalize subject by writing to GDS2 and reading back - WriteOAS // normalize subject by writing to OASIS and reading back + NoNormalization = 0, // no normalization - take the test subject as it is + WriteGDS2 = 1, // normalize subject by writing to GDS2 and reading back + WriteOAS = 2, // normalize subject by writing to OASIS and reading back + NormFileMask = 7, // bits the extract for file mode + NoContext = 8, // write tmp file without context + AsPolygons = 16 // paths and boxes are treated as polygons }; /** diff --git a/src/db/db/gsiDeclDbLibrary.cc b/src/db/db/gsiDeclDbLibrary.cc index 1b5439da3..6b3c64c19 100644 --- a/src/db/db/gsiDeclDbLibrary.cc +++ b/src/db/db/gsiDeclDbLibrary.cc @@ -233,6 +233,12 @@ LibraryClass decl_Library ("db", "Library", ) + gsi::method ("layout", (db::Layout &(db::Library::*)()) &db::Library::layout, "@brief The layout object where the cells reside that this library defines\n" + ) + + gsi::method ("refresh", &db::Library::refresh, + "@brief Updates all layouts using this library.\n" + "This method will retire cells or update layouts in the attached clients.\n" + "\n" + "This method has been introduced in version 0.27.8." ), "@brief A Library \n" "\n" diff --git a/src/db/unit_tests/dbLibrariesTests.cc b/src/db/unit_tests/dbLibrariesTests.cc index 7961a750e..6e30885a1 100644 --- a/src/db/unit_tests/dbLibrariesTests.cc +++ b/src/db/unit_tests/dbLibrariesTests.cc @@ -31,6 +31,7 @@ #include "dbWriter.h" #include "dbReader.h" #include "dbLayoutDiff.h" +#include "dbTestSupport.h" #include "tlStream.h" #include "tlStaticObjects.h" #include "tlUnitTest.h" @@ -187,6 +188,14 @@ public: cell_a.shapes(l1).insert(db::Box (50, 50, 150, 150)); cell_a.shapes(l2).insert(db::Box (0, 0, 200, 1000)); } + + void modify () + { + db::Cell &cell_a = layout ().cell (layout ().cell_by_name ("A").second); + unsigned int l1 = layout ().get_layer (db::LayerProperties (1, 0)); + cell_a.shapes (l1).clear (); + cell_a.shapes (l1).insert(db::Box (60, 60, 160, 160)); + } }; class LIBT_B @@ -226,221 +235,164 @@ public: } }; -static bool compare_vs_au (const tl::TestBase *tb, const db::Layout &layout, const std::string &filename) -{ - db::Layout layout_au; - - std::string fn (tl::testdata ()); - fn += "/gds/"; - fn += filename; - tl::InputStream stream (fn); - db::Reader reader (stream); - reader.read (layout_au); - - // generate a "unique" name ... - unsigned int hash = 0; - for (const char *cp = filename.c_str (); *cp; ++cp) { - hash = (hash << 4) ^ (hash >> 4) ^ ((unsigned int) *cp); - } - - std::string tmp_file = tb->tmp_file (tl::sprintf ("tmp_%x.gds", hash)); - - // "normalize" the layout by writing and reading ... - { - db::Writer writer = db::Writer (db::SaveLayoutOptions ()); - tl::OutputStream stream (tmp_file); - writer.write (const_cast (layout), stream); - } - - db::Layout tmp; - tl::InputStream tmp_stream (tmp_file); - db::Reader reader_tmp (tmp_stream); - reader_tmp.read (tmp); - - bool equal = db::compare_layouts (tmp, layout_au, db::layout_diff::f_verbose, 0); - if (! equal) { - tl::warn << tl::sprintf ("Compare failed - see %s vs %s\n", tmp_file, fn); - } - return equal; -} - TEST(1) { - bool equal; - std::vector libnames_before; for (db::LibraryManager::iterator il = db::LibraryManager::instance ().begin (); il != db::LibraryManager::instance ().end (); ++il) { libnames_before.push_back (il->first); } std::sort (libnames_before.begin (), libnames_before.end ()); - LIBT_L *l = new LIBT_L (_this); - db::lib_id_type lib_id = db::LibraryManager::instance ().register_lib (l); + std::unique_ptr l (new LIBT_L (_this)); + db::lib_id_type lib_id = db::LibraryManager::instance ().register_lib (l.get ()); - try { + std::vector libnames_withl; + for (db::LibraryManager::iterator il = db::LibraryManager::instance ().begin (); il != db::LibraryManager::instance ().end (); ++il) { + libnames_withl.push_back (il->first); + } + std::sort (libnames_withl.begin (), libnames_withl.end ()); - std::vector libnames_withl; - for (db::LibraryManager::iterator il = db::LibraryManager::instance ().begin (); il != db::LibraryManager::instance ().end (); ++il) { - libnames_withl.push_back (il->first); - } - std::sort (libnames_withl.begin (), libnames_withl.end ()); + std::vector ll = libnames_before; + ll.push_back ("L"); + std::sort (ll.begin (), ll.end ()); - std::vector ll = libnames_before; - ll.push_back ("L"); - std::sort (ll.begin (), ll.end ()); + EXPECT_EQ (tl::join (libnames_withl, ","), tl::join (ll, ",")); - EXPECT_EQ (tl::join (libnames_withl, ","), tl::join (ll, ",")); + std::pair lbn; + lbn = db::LibraryManager::instance ().lib_by_name ("X"); + EXPECT_EQ (lbn.first, false); + lbn = db::LibraryManager::instance ().lib_by_name ("L"); + EXPECT_EQ (lbn.first, true); + EXPECT_EQ (lbn.second, lib_id); - std::pair lbn; - lbn = db::LibraryManager::instance ().lib_by_name ("X"); - EXPECT_EQ (lbn.first, false); - lbn = db::LibraryManager::instance ().lib_by_name ("L"); - EXPECT_EQ (lbn.first, true); - EXPECT_EQ (lbn.second, lib_id); + db::Library *lib = db::LibraryManager::instance ().lib (lib_id); + EXPECT_EQ (lib == l.get (), true); + EXPECT_EQ (lib->get_id (), lib_id); + EXPECT_EQ (lib->get_name (), "L"); + EXPECT_EQ (lib->get_description (), "A test library."); - db::Library *lib = db::LibraryManager::instance ().lib (lib_id); - EXPECT_EQ (lib == l, true); - EXPECT_EQ (lib->get_id (), lib_id); - EXPECT_EQ (lib->get_name (), "L"); - EXPECT_EQ (lib->get_description (), "A test library."); + EXPECT_EQ (lib->layout ().get_properties(0).to_string (), "23/0"); + EXPECT_EQ (lib->layout ().get_properties(1).to_string (), "16/0"); + EXPECT_EQ (lib->layout ().get_properties(2).to_string (), "24/0"); - EXPECT_EQ (lib->layout ().get_properties(0).to_string (), "23/0"); - EXPECT_EQ (lib->layout ().get_properties(1).to_string (), "16/0"); - EXPECT_EQ (lib->layout ().get_properties(2).to_string (), "24/0"); + db::Manager m (true); + db::Layout layout(&m); + layout.dbu (0.001); - db::Manager m (true); - db::Layout layout(&m); - layout.dbu (0.001); + db::Cell &top = layout.cell (layout.add_cell ("TOP")); - db::Cell &top = layout.cell (layout.add_cell ("TOP")); + EXPECT_EQ (lib->layout ().cell_by_name ("TOP").first, true); + db::cell_index_type lib_top = lib->layout ().cell_by_name ("TOP").second; + db::cell_index_type lp1 = layout.get_lib_proxy (lib, lib_top); - EXPECT_EQ (lib->layout ().cell_by_name ("TOP").first, true); - db::cell_index_type lib_top = lib->layout ().cell_by_name ("TOP").second; - db::cell_index_type lp1 = layout.get_lib_proxy (lib, lib_top); + EXPECT_EQ (std::string (layout.cell_name (lp1)), "TOP$1"); + EXPECT_EQ (layout.basic_name (lp1), "TOP"); + EXPECT_EQ (layout.display_name (lp1), "L.TOP"); - EXPECT_EQ (std::string (layout.cell_name (lp1)), "TOP$1"); - EXPECT_EQ (layout.basic_name (lp1), "TOP"); - EXPECT_EQ (layout.display_name (lp1), "L.TOP"); + EXPECT_EQ (layout.get_properties(0).to_string (), "23/0"); + EXPECT_EQ (layout.get_properties(1).to_string (), "16/0"); + EXPECT_EQ (layout.get_properties(2).to_string (), "24/0"); - EXPECT_EQ (layout.get_properties(0).to_string (), "23/0"); - EXPECT_EQ (layout.get_properties(1).to_string (), "16/0"); - EXPECT_EQ (layout.get_properties(2).to_string (), "24/0"); + db::Instance i1 = top.insert (db::CellInstArray (db::CellInst (lp1), db::Trans (db::Vector (0, 0)))); - db::Instance i1 = top.insert (db::CellInstArray (db::CellInst (lp1), db::Trans (db::Vector (0, 0)))); + std::vector parameters; + parameters.push_back (tl::Variant ()); + parameters.push_back (tl::Variant ()); + parameters.push_back (tl::Variant ()); + tl::Variant &width = parameters[0]; + tl::Variant &height = parameters[1]; + tl::Variant &orientation = parameters[2]; + width = 2.0; + height = 10.0; + orientation = (long)3; - std::vector parameters; - parameters.push_back (tl::Variant ()); - parameters.push_back (tl::Variant ()); - parameters.push_back (tl::Variant ()); - tl::Variant &width = parameters[0]; - tl::Variant &height = parameters[1]; - tl::Variant &orientation = parameters[2]; - width = 2.0; - height = 10.0; - orientation = (long)3; + EXPECT_EQ (lib->layout ().pcell_by_name ("PD").first, true); + db::pcell_id_type pd = lib->layout ().pcell_by_name ("PD").second; + db::cell_index_type lib_pd1 = lib->layout ().get_pcell_variant (pd, parameters); + db::cell_index_type lp2 = layout.get_lib_proxy (lib, lib_pd1); + EXPECT_EQ (std::string (layout.cell_name (lp2)), "PD$2"); + EXPECT_EQ (layout.basic_name (lp2), "PD"); + EXPECT_EQ (layout.display_name (lp2), "L.PD*"); - EXPECT_EQ (lib->layout ().pcell_by_name ("PD").first, true); - db::pcell_id_type pd = lib->layout ().pcell_by_name ("PD").second; - db::cell_index_type lib_pd1 = lib->layout ().get_pcell_variant (pd, parameters); - db::cell_index_type lp2 = layout.get_lib_proxy (lib, lib_pd1); - EXPECT_EQ (std::string (layout.cell_name (lp2)), "PD$2"); - EXPECT_EQ (layout.basic_name (lp2), "PD"); - EXPECT_EQ (layout.display_name (lp2), "L.PD*"); + const db::Cell *lp2_cell = &layout.cell (lp2); + EXPECT_EQ (dynamic_cast (lp2_cell) != 0, true); + EXPECT_EQ (lp2_cell->is_proxy (), true); + EXPECT_EQ (layout.is_pcell_instance (lp2).first, true); + EXPECT_EQ (layout.is_pcell_instance (lp2).second, pd); + EXPECT_EQ (layout.get_pcell_parameters (lp2)[0].to_string(), std::string ("2")); + EXPECT_EQ (layout.get_pcell_parameters (lp2)[1].to_string(), std::string ("10")); - const db::Cell *lp2_cell = &layout.cell (lp2); - EXPECT_EQ (dynamic_cast (lp2_cell) != 0, true); - EXPECT_EQ (lp2_cell->is_proxy (), true); - EXPECT_EQ (layout.is_pcell_instance (lp2).first, true); - EXPECT_EQ (layout.is_pcell_instance (lp2).second, pd); - EXPECT_EQ (layout.get_pcell_parameters (lp2)[0].to_string(), std::string ("2")); - EXPECT_EQ (layout.get_pcell_parameters (lp2)[1].to_string(), std::string ("10")); + db::Instance i2 = top.insert (db::CellInstArray (db::CellInst (lp2), db::Trans (db::Vector (10000, 0)))); - db::Instance i2 = top.insert (db::CellInstArray (db::CellInst (lp2), db::Trans (db::Vector (10000, 0)))); + db::Writer writer = db::Writer (db::SaveLayoutOptions ()); + + CHECKPOINT (); + db::compare_layouts (this, layout, tl::testdata () + "/gds/lib_test.gds", db::NormalizationMode (db::WriteGDS2 + db::NoContext)); + + // if not in editable mode, we could have lost the reference to the second instance + if (db::default_editable_mode ()) { + + m.transaction ("x"); + + height = 5.0; + db::cell_index_type i2_cid = i2.cell_index (); + i2 = top.change_pcell_parameters (i2, parameters); + EXPECT_NE (i2.cell_index (), i2_cid); + + EXPECT_EQ (std::string (layout.cell_name (i2.cell_index ())), "PD$3"); + EXPECT_EQ (layout.basic_name (i2.cell_index ()), "PD"); + EXPECT_EQ (layout.display_name (i2.cell_index ()), "L.PD*"); - db::Writer writer = db::Writer (db::SaveLayoutOptions ()); /* produce golden: - tl::OutputStream stream ("lib_test.gds"); - writer.write (layout, stream); + tl::OutputStream stream2 ("lib_test2.gds"); + writer.write (layout, stream2); */ - equal = compare_vs_au (this, layout, "lib_test.gds"); - EXPECT_EQ (equal, true); + CHECKPOINT (); + db::compare_layouts (this, layout, tl::testdata () + "/gds/lib_test2.gds", db::NormalizationMode (db::WriteGDS2 + db::NoContext)); - // if not in editable mode, we could have lost the reference to the second instance - if (db::default_editable_mode ()) { + m.commit (); - m.transaction ("x"); + m.transaction ("y"); - height = 5.0; - db::cell_index_type i2_cid = i2.cell_index (); - i2 = top.change_pcell_parameters (i2, parameters); - EXPECT_NE (i2.cell_index (), i2_cid); + width = 0.5; + height = 1.0; + orientation = long (0); - EXPECT_EQ (std::string (layout.cell_name (i2.cell_index ())), "PD$3"); - EXPECT_EQ (layout.basic_name (i2.cell_index ()), "PD"); - EXPECT_EQ (layout.display_name (i2.cell_index ()), "L.PD*"); - - /* produce golden: - tl::OutputStream stream2 ("lib_test2.gds"); - writer.write (layout, stream2); - */ + i2 = top.change_pcell_parameters (i2, parameters); - equal = compare_vs_au (this, layout, "lib_test2.gds"); - EXPECT_EQ (equal, true); + /* produce golden: + tl::OutputStream stream3 ("lib_test3.gds"); + writer.write (layout, stream3); + */ - m.commit (); + EXPECT_EQ (std::string (layout.cell_name (i2.cell_index ())), "PD"); + EXPECT_EQ (layout.basic_name (i2.cell_index ()), "PD"); + EXPECT_EQ (layout.display_name (i2.cell_index ()), "L.PD*"); - m.transaction ("y"); + CHECKPOINT (); + db::compare_layouts (this, layout, tl::testdata () + "/gds/lib_test3.gds", db::NormalizationMode (db::WriteGDS2 + db::NoContext)); - width = 0.5; - height = 1.0; - orientation = long (0); + m.commit (); - i2 = top.change_pcell_parameters (i2, parameters); + m.undo (); - /* produce golden: - tl::OutputStream stream3 ("lib_test3.gds"); - writer.write (layout, stream3); - */ + CHECKPOINT (); + db::compare_layouts (this, layout, tl::testdata () + "/gds/lib_test2.gds", db::NormalizationMode (db::WriteGDS2 + db::NoContext)); - EXPECT_EQ (std::string (layout.cell_name (i2.cell_index ())), "PD"); - EXPECT_EQ (layout.basic_name (i2.cell_index ()), "PD"); - EXPECT_EQ (layout.display_name (i2.cell_index ()), "L.PD*"); - - equal = compare_vs_au (this, layout, "lib_test3.gds"); - EXPECT_EQ (equal, true); + m.undo (); - m.commit (); + CHECKPOINT (); + db::compare_layouts (this, layout, tl::testdata () + "/gds/lib_test.gds", db::NormalizationMode (db::WriteGDS2 + db::NoContext)); - m.undo (); - - equal = compare_vs_au (this, layout, "lib_test2.gds"); - EXPECT_EQ (equal, true); - - m.undo (); - - equal = compare_vs_au (this, layout, "lib_test.gds"); - EXPECT_EQ (equal, true); - - m.redo (); - - equal = compare_vs_au (this, layout, "lib_test2.gds"); - EXPECT_EQ (equal, true); - } - - // because we switch to editable mode in between we have to clear the repository explicitly. Otherwise it's being cleared - // on next entry of TEST which will cause a segmentation fault if editable mode is different then. - db::LibraryManager::instance ().delete_lib (l); - - } catch (...) { - - // because we switch to editable mode in between we have to clear the repository explicitly. Otherwise it's being cleared - // on next entry of TEST which will cause a segmentation fault if editable mode is different then. - db::LibraryManager::instance ().delete_lib (l); - throw; + m.redo (); + CHECKPOINT (); + db::compare_layouts (this, layout, tl::testdata () + "/gds/lib_test2.gds", db::NormalizationMode (db::WriteGDS2 + db::NoContext)); } + db::LibraryManager::instance ().delete_lib (l.release ()); + std::vector libnames_after; for (db::LibraryManager::iterator il = db::LibraryManager::instance ().begin (); il != db::LibraryManager::instance ().end (); ++il) { libnames_after.push_back (il->first); @@ -452,252 +404,217 @@ TEST(1) TEST(2) { - LIBT_L *lib = new LIBT_L (_this); - db::LibraryManager::instance ().register_lib (lib); + std::unique_ptr lib (new LIBT_L (_this)); + db::LibraryManager::instance ().register_lib (lib.get ()); - try { + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("L").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("L").second, lib->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib (lib->get_id ()) == lib.get (), true); - bool equal; - db::Writer writer = db::Writer (db::SaveLayoutOptions ()); + db::Writer writer = db::Writer (db::SaveLayoutOptions ()); - db::Manager m (true); - db::Layout layout(&m); - layout.dbu (0.001); + db::Manager m (true); + db::Layout layout(&m); + layout.dbu (0.001); - db::Cell &top = layout.cell (layout.add_cell ("TOP")); + db::Cell &top = layout.cell (layout.add_cell ("TOP")); - db::cell_index_type lib_top = lib->layout ().cell_by_name ("TOP").second; - db::cell_index_type lp1 = layout.get_lib_proxy (lib, lib_top); - db::Instance i1 = top.insert (db::CellInstArray (db::CellInst (lp1), db::Trans (db::Vector (0, 0)))); + db::cell_index_type lib_top = lib->layout ().cell_by_name ("TOP").second; + db::cell_index_type lp1 = layout.get_lib_proxy (lib.get (), lib_top); + db::Instance i1 = top.insert (db::CellInstArray (db::CellInst (lp1), db::Trans (db::Vector (0, 0)))); - std::vector parameters; - parameters.push_back (tl::Variant ()); - parameters.push_back (tl::Variant ()); - parameters.push_back (tl::Variant ()); - tl::Variant &width = parameters[0]; - tl::Variant &height = parameters[1]; - tl::Variant &orientation = parameters[2]; - width = 2.0; - height = 10.0; - orientation = (long)3; + std::vector parameters; + parameters.push_back (tl::Variant ()); + parameters.push_back (tl::Variant ()); + parameters.push_back (tl::Variant ()); + tl::Variant &width = parameters[0]; + tl::Variant &height = parameters[1]; + tl::Variant &orientation = parameters[2]; + width = 2.0; + height = 10.0; + orientation = (long)3; - db::pcell_id_type pd = lib->layout ().pcell_by_name ("PD").second; - db::cell_index_type lib_pd1 = lib->layout ().get_pcell_variant (pd, parameters); - db::cell_index_type lp2 = layout.get_lib_proxy (lib, lib_pd1); - db::Instance i2 = top.insert (db::CellInstArray (db::CellInst (lp2), db::Trans (db::Vector (10000, 0)))); + db::pcell_id_type pd = lib->layout ().pcell_by_name ("PD").second; + db::cell_index_type lib_pd1 = lib->layout ().get_pcell_variant (pd, parameters); + db::cell_index_type lp2 = layout.get_lib_proxy (lib.get (), lib_pd1); + db::Instance i2 = top.insert (db::CellInstArray (db::CellInst (lp2), db::Trans (db::Vector (10000, 0)))); - EXPECT_EQ (std::string (layout.cell_name (lp2)), "PD$2"); - EXPECT_EQ (layout.basic_name (lp2), "PD"); - EXPECT_EQ (layout.display_name (lp2), "L.PD*"); + EXPECT_EQ (std::string (layout.cell_name (lp2)), "PD$2"); + EXPECT_EQ (layout.basic_name (lp2), "PD"); + EXPECT_EQ (layout.display_name (lp2), "L.PD*"); - std::string tmp_file = tl::TestBase::tmp_file (tl::sprintf ("tmp_dbLibraries2.gds")); + std::string tmp_file = tl::TestBase::tmp_file (tl::sprintf ("tmp_dbLibraries2.gds")); - { - tl::OutputStream stream (tmp_file); - writer.write (layout, stream); - } + { + tl::OutputStream stream (tmp_file); + writer.write (layout, stream); + } - db::Layout tmp; - { - tl::InputStream tmp_stream (tmp_file); - db::Reader reader_tmp (tmp_stream); - reader_tmp.read (tmp); - } - - std::pair tmp_pd2 = tmp.cell_by_name ("PD$2"); - EXPECT_EQ (tmp_pd2.first, true); - EXPECT_EQ (tmp.basic_name (tmp_pd2.second), "PD"); - EXPECT_EQ (tmp.display_name (tmp_pd2.second), "L.PD*"); + db::Layout tmp; + { + tl::InputStream tmp_stream (tmp_file); + db::Reader reader_tmp (tmp_stream); + reader_tmp.read (tmp); + } - db::Instance tmp_i2 = tmp.cell (tmp_pd2.second).begin_parent_insts ()->child_inst (); - EXPECT_EQ (tmp_i2.cell_index (), tmp_pd2.second); - std::vector new_param = tmp.get_pcell_parameters (tmp_pd2.second); + std::pair tmp_pd2 = tmp.cell_by_name ("PD$2"); + EXPECT_EQ (tmp_pd2.first, true); + EXPECT_EQ (tmp.basic_name (tmp_pd2.second), "PD"); + EXPECT_EQ (tmp.display_name (tmp_pd2.second), "L.PD*"); - EXPECT_EQ (new_param.size (), size_t (3)); - EXPECT_EQ (new_param[0].to_string (), std::string ("2")); - EXPECT_EQ (new_param[1].to_string (), std::string ("10")); - EXPECT_EQ (new_param[2].to_string (), std::string ("3")); + db::Instance tmp_i2 = tmp.cell (tmp_pd2.second).begin_parent_insts ()->child_inst (); + EXPECT_EQ (tmp_i2.cell_index (), tmp_pd2.second); + std::vector new_param = tmp.get_pcell_parameters (tmp_pd2.second); - std::pair tt = tmp.cell_by_name ("TOP"); - EXPECT_EQ (tt.first, true); - db::Cell &tmp_top = tmp.cell (tt.second); - - if (db::default_editable_mode ()) { + EXPECT_EQ (new_param.size (), size_t (3)); + EXPECT_EQ (new_param[0].to_string (), std::string ("2")); + EXPECT_EQ (new_param[1].to_string (), std::string ("10")); + EXPECT_EQ (new_param[2].to_string (), std::string ("3")); - new_param[1] = 5.0; - db::cell_index_type tmp_i2_cid = tmp_i2.cell_index (); - tmp_i2 = tmp_top.change_pcell_parameters (tmp_i2, new_param); + std::pair tt = tmp.cell_by_name ("TOP"); + EXPECT_EQ (tt.first, true); + db::Cell &tmp_top = tmp.cell (tt.second); - EXPECT_NE (tmp_i2.cell_index (), tmp_i2_cid); + if (db::default_editable_mode ()) { - EXPECT_EQ (std::string (tmp.cell_name (tmp_i2.cell_index ())), "PD$3"); - EXPECT_EQ (tmp.basic_name (tmp_i2.cell_index ()), "PD"); - EXPECT_EQ (tmp.display_name (tmp_i2.cell_index ()), "L.PD*"); - - /* produce golden: - tl::OutputStream stream3 ("lib_test2.gds"); - writer.write (tmp, stream3); - */ - - equal = compare_vs_au (this, tmp, "lib_test2.gds"); - EXPECT_EQ (equal, true); + new_param[1] = 5.0; + db::cell_index_type tmp_i2_cid = tmp_i2.cell_index (); + tmp_i2 = tmp_top.change_pcell_parameters (tmp_i2, new_param); - } + EXPECT_NE (tmp_i2.cell_index (), tmp_i2_cid); - // because we switch to editable mode in between we have to clear the repository explicitly. Otherwise it's being cleared - // on next entry of TEST which will cause a segmentation fault if editable mode is different then. - db::LibraryManager::instance ().delete_lib (lib); + EXPECT_EQ (std::string (tmp.cell_name (tmp_i2.cell_index ())), "PD$3"); + EXPECT_EQ (tmp.basic_name (tmp_i2.cell_index ()), "PD"); + EXPECT_EQ (tmp.display_name (tmp_i2.cell_index ()), "L.PD*"); - } catch (...) { - - // because we switch to editable mode in between we have to clear the repository explicitly. Otherwise it's being cleared - // on next entry of TEST which will cause a segmentation fault if editable mode is different then. - db::LibraryManager::instance ().delete_lib (lib); - throw; + CHECKPOINT (); + db::compare_layouts (this, tmp, tl::testdata () + "/gds/lib_test2.gds", db::NormalizationMode (db::WriteGDS2 + db::NoContext)); } + + // unregister the library through the destructor + lib.reset (0); + + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("L").first, false); } TEST(3) { - LIBT_A *lib_a = new LIBT_A (); - db::LibraryManager::instance ().register_lib (lib_a); + std::unique_ptr lib_a (new LIBT_A ()); + db::LibraryManager::instance ().register_lib (lib_a.get ()); - LIBT_B *lib_b = new LIBT_B (); - db::LibraryManager::instance ().register_lib (lib_b); + std::unique_ptr lib_b (new LIBT_B ()); + db::LibraryManager::instance ().register_lib (lib_b.get ()); - try { + // This test tests the ability to reference libraries out of other libraries ("B" references "A"), + // the ability to persist that and whether this survives a write/read cycle. - // This test tests the ability to reference libraries out of other libraries ("B" references "A"), - // the ability to persist that and whether this survives a write/read cycle. - - db::Manager m (true); - db::Layout layout(&m); - layout.dbu (0.001); + db::Manager m (true); + db::Layout layout(&m); + layout.dbu (0.001); - db::Cell &top = layout.cell (layout.add_cell ("TOP")); + db::Cell &top = layout.cell (layout.add_cell ("TOP")); - db::cell_index_type lib_bb = lib_b->layout ().cell_by_name ("B").second; - db::cell_index_type lp = layout.get_lib_proxy (lib_b, lib_bb); - db::Instance i1 = top.insert (db::CellInstArray (db::CellInst (lp), db::Trans (db::Vector (0, 0)))); + db::cell_index_type lib_bb = lib_b->layout ().cell_by_name ("B").second; + db::cell_index_type lp = layout.get_lib_proxy (lib_b.get (), lib_bb); + db::Instance i1 = top.insert (db::CellInstArray (db::CellInst (lp), db::Trans (db::Vector (0, 0)))); - std::string tmp_file = tl::TestBase::tmp_file (tl::sprintf ("tmp_dbLibraries3.gds")); - - { - db::Writer writer = db::Writer (db::SaveLayoutOptions ()); - tl::OutputStream stream (tmp_file); - writer.write (layout, stream); - } - - layout.clear (); - - db::Layout tmp; - { - tl::InputStream tmp_stream (tmp_file); - db::Reader reader_tmp (tmp_stream); - reader_tmp.read (tmp); - } - - bool equal = compare_vs_au (this, tmp, "lib_test4.gds"); - EXPECT_EQ (equal, true); - - // because we switch to editable mode in between we have to clear the repository explicitly. Otherwise it's being cleared - // on next entry of TEST which will cause a segmentation fault if editable mode is different then. - db::LibraryManager::instance ().delete_lib (lib_a); - db::LibraryManager::instance ().delete_lib (lib_b); - - } catch (...) { - - // because we switch to editable mode in between we have to clear the repository explicitly. Otherwise it's being cleared - // on next entry of TEST which will cause a segmentation fault if editable mode is different then. - db::LibraryManager::instance ().delete_lib (lib_a); - db::LibraryManager::instance ().delete_lib (lib_b); - throw; + std::string tmp_file = tl::TestBase::tmp_file (tl::sprintf ("tmp_dbLibraries3.gds")); + { + db::Writer writer = db::Writer (db::SaveLayoutOptions ()); + tl::OutputStream stream (tmp_file); + writer.write (layout, stream); } + + layout.clear (); + + db::Layout tmp; + { + tl::InputStream tmp_stream (tmp_file); + db::Reader reader_tmp (tmp_stream); + reader_tmp.read (tmp); + } + + CHECKPOINT (); + db::compare_layouts (this, tmp, tl::testdata () + "/gds/lib_test4.gds", db::NormalizationMode (db::WriteGDS2 + db::NoContext)); } TEST(4) { - tl::weak_ptr lib_a1 (new LIBT_A ()); + std::unique_ptr lib_a1_inst (new LIBT_A ()); + tl::weak_ptr lib_a1 (lib_a1_inst.get ()); lib_a1->add_technology ("X"); - tl::weak_ptr lib_a2 (new LIBT_A ()); + std::unique_ptr lib_a2_inst (new LIBT_A ()); + tl::weak_ptr lib_a2 (lib_a2_inst.get ()); lib_a2->add_technology ("Y"); - tl::weak_ptr lib_a3 (new LIBT_A ()); + std::unique_ptr lib_a3_inst (new LIBT_A ()); + tl::weak_ptr lib_a3 (lib_a3_inst.get ()); lib_a3->add_technology ("X"); - tl::weak_ptr lib_a4 (new LIBT_A ()); + std::unique_ptr lib_a4_inst (new LIBT_A ()); + tl::weak_ptr lib_a4 (lib_a4_inst.get ()); - try { + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, false); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, false); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, false); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, false); + db::LibraryManager::instance ().register_lib (lib_a1.get ()); - db::LibraryManager::instance ().register_lib (lib_a1.get ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a1->get_id ()); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, false); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, false); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a1->get_id ()); + db::LibraryManager::instance ().register_lib (lib_a2.get ()); - db::LibraryManager::instance ().register_lib (lib_a2.get ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a1->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").second, lib_a2->get_id ()); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, false); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, false); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a1->get_id ()); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").first, true); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").second, lib_a2->get_id ()); + db::LibraryManager::instance ().register_lib (lib_a3.get ()); + // lib_a3 replaces lib_a1 + EXPECT_EQ (lib_a1.get () == 0, true); + lib_a1_inst.release (); - db::LibraryManager::instance ().register_lib (lib_a3.get ()); - // lib_a3 replaces lib_a1 - EXPECT_EQ (lib_a1.get () == 0, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a3->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").second, lib_a2->get_id ()); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, false); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, false); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a3->get_id ()); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").first, true); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").second, lib_a2->get_id ()); + db::LibraryManager::instance ().register_lib (lib_a4.get ()); - db::LibraryManager::instance ().register_lib (lib_a4.get ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a4->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").second, lib_a4->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").second, lib_a4->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a3->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").second, lib_a2->get_id ()); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a4->get_id ()); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, true); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").second, lib_a4->get_id ()); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, true); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").second, lib_a4->get_id ()); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a3->get_id ()); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").first, true); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").second, lib_a2->get_id ()); + lib_a1_inst.reset (0); + lib_a2_inst.reset (0); + lib_a3_inst.reset (0); + lib_a4_inst.reset (0); - // because we switch to editable mode in between we have to clear the repository explicitly. Otherwise it's being cleared - // on next entry of TEST which will cause a segmentation fault if editable mode is different then. - if (lib_a1.get ()) { db::LibraryManager::instance ().delete_lib (lib_a1.get ()); } - if (lib_a2.get ()) { db::LibraryManager::instance ().delete_lib (lib_a2.get ()); } - if (lib_a3.get ()) { db::LibraryManager::instance ().delete_lib (lib_a3.get ()); } - if (lib_a4.get ()) { db::LibraryManager::instance ().delete_lib (lib_a4.get ()); } - - } catch (...) { - - // because we switch to editable mode in between we have to clear the repository explicitly. Otherwise it's being cleared - // on next entry of TEST which will cause a segmentation fault if editable mode is different then. - if (lib_a1.get ()) { db::LibraryManager::instance ().delete_lib (lib_a1.get ()); } - if (lib_a2.get ()) { db::LibraryManager::instance ().delete_lib (lib_a2.get ()); } - if (lib_a3.get ()) { db::LibraryManager::instance ().delete_lib (lib_a3.get ()); } - if (lib_a4.get ()) { db::LibraryManager::instance ().delete_lib (lib_a4.get ()); } - throw; - - } + EXPECT_EQ (lib_a1.get () == 0, true); + EXPECT_EQ (lib_a2.get () == 0, true); + EXPECT_EQ (lib_a3.get () == 0, true); + EXPECT_EQ (lib_a4.get () == 0, true); } namespace { @@ -734,8 +651,7 @@ class PCell2Declaration : // self-referencing libraries TEST(5_issue905) { - std::unique_ptr lib; - lib.reset (new db::Library ()); + std::unique_ptr lib (new db::Library ()); lib->set_name ("__PCellLibrary"); lib->layout ().register_pcell ("PCell1", new PCell1Declaration ()); lib->layout ().register_pcell ("PCell2", new PCell2Declaration ()); @@ -751,3 +667,34 @@ TEST(5_issue905) db::LibraryManager::instance ().delete_lib (lib.release ()); EXPECT (true); } + +// refresh function +TEST(6_issue996) +{ + std::unique_ptr lib (new LIBT_A ()); + db::LibraryManager::instance ().register_lib (lib.get ()); + + db::cell_index_type ci_a = lib->layout ().cell_by_name ("A").second; + + db::Layout ly; + + db::cell_index_type lib_cell = ly.get_lib_proxy (lib.get (), ci_a); + db::Cell &top_cell = ly.cell (ly.add_cell ("TOP")); + + top_cell.insert (db::CellInstArray (lib_cell, db::Trans ())); + + CHECKPOINT (); + db::compare_layouts (this, ly, tl::testdata () + "/gds/lib_test6a.gds", db::NormalizationMode (db::WriteGDS2 + db::NoContext)); + + lib->modify (); + + // not updated yet + CHECKPOINT (); + db::compare_layouts (this, ly, tl::testdata () + "/gds/lib_test6a.gds", db::NormalizationMode (db::WriteGDS2 + db::NoContext)); + + lib->refresh (); + + // updated now + CHECKPOINT (); + db::compare_layouts (this, ly, tl::testdata () + "/gds/lib_test6b.gds", db::NormalizationMode (db::WriteGDS2 + db::NoContext)); +} diff --git a/testdata/gds/lib_test2.gds b/testdata/gds/lib_test2.gds index 5620fbaafbfff83ceec9d988022ae79ee391e43b..c246782ac0dfd05cd0025fb303226249de68a150 100644 GIT binary patch delta 239 zcmdnN{e~@yfsKKQDS|^7sp}dWFO{QoN^DCGjYm&VM)d*m%xJC%sf^v0ND^H9RL6T literal 1464 zcmbW1&n`nj6vn^%r>E7FTqTHfA<+cUph~c)q*@ZuXct|G4H6Aaq!MZ371&wX*w}dk z@dRS&0W2&nEj)lTGk5e}?d3AbWML!j1!!qyms|EY7AH zO`9+f&ror_T+SCD)(~sXoG$}*KX>+wC8=6UXFGgtBr;T$&ef9iwlKt&$O-{_LF+^NN+4Ck8Uh{3eNTY6d_6GG>PLQ z$p&#O26HG)a{ndCbthSLNu*M3MdpJ!;z_Dis(d*eB!;*hc{%)njN74S6hGDyk*F9u z#@TyK41@YaePm<>F%opY=DD|P`@E_k*WdB^vx{!l8_%8qJ!(6TvI2jhjFGC&c8$}h z!M=%9WNp`trRs$ljf{_JB#>#0zrA86cXZ>3Aq*2M$5q-UQu+Ce98>zcngr)(O^gqv zi5NXCOn#+F&O`8}Nzr*#!6cJ)5A^JZV;Z;sqR)UH|Hu?4U8$}v-`=r2m-A^(8QfPr;rKGxHa-FCXOa&9 diff --git a/testdata/gds/lib_test4.gds b/testdata/gds/lib_test4.gds index f125a963a64fa82321ce6ef8825a12310af20de0..46583bfdbf571aae776b282e904f55a9e1e18bd6 100644 GIT binary patch delta 155 zcmX@a+QAaVz{bGD6u}_F$i)7Pfr)_|2n`sRk=YC!Ol&@$P7Dkp%&c~fo#x)hmVdBx h*`dE+c2o$13@c83lSLT&#c`N9c^BhxoN_amv;d}r84Lgb literal 706 zcma)3K}y3=5Pg~aOhbrbB`9j>Dht6vp_}4DX<923L*pWg;>PoM0YTlk^9ntIcnh~K zdj#kI^v9&M>cC{?{p7v>W&#G$9I->KPXy@T5FxnU!za$BBOr3U%k*Jz^ZvFxzgqNO zU+xOT-ge#rbCM+Ed{#{6#r<@4oeP8t0N&>m2=`pr;4=at=<;}yWfv(lb~Kio1sV*C z#fxf7mP&%wl?>A;jW#n|_|-YH_NRQgcSrl+T@s^RQVfWA`@J diff --git a/testdata/gds/lib_test6a.gds b/testdata/gds/lib_test6a.gds new file mode 100644 index 0000000000000000000000000000000000000000..c4355a33e9f729d83250bce6bfae73b31dca7a4f GIT binary patch literal 298 zcmZQzV_;&6V31*CVt>ZK#J~-N{0yqdYz7V{HXlzX1_lvkRy)T|bMIrzKUli#&|fe+ zDuh9X6}LV%Ha15F1{Mwm1~y(M21W)pJ|+eR1|0!rAZdhzrvcf>7$L_Zh|tf3q93RQ x2AE#}Stl46U^Gk|NQ3pWGvIY42OC?6e*jP|7tozTAQ$t1T?jD-W&#Tf0|1+`8gT#s literal 0 HcmV?d00001 diff --git a/testdata/gds/lib_test6b.gds b/testdata/gds/lib_test6b.gds new file mode 100644 index 0000000000000000000000000000000000000000..708b1c4d9174286b6bd221185577311cddb75505 GIT binary patch literal 298 zcmZQzV_;&6V31*CVt>ZK#J~-N!VHYaYz7V{HXlzX1_lvkRy)T|bMIrzKUli#&|fe+ zDuh9X6}LV%Ha15F1{Mwm1~y(M21W)pJ|+eR1|0!rAZdey7XaDF7$L_Zh|tf3q93RQ x2AE#}Stl46U^Gk|NQ3pWGvIY42OC?6e*jP|7tozTAQ$t1T?jD-W&#Tf0{~S88WjKl literal 0 HcmV?d00001 diff --git a/testdata/ruby/dbLibrary.rb b/testdata/ruby/dbLibrary.rb index 70fd0cd92..d24a7c579 100644 --- a/testdata/ruby/dbLibrary.rb +++ b/testdata/ruby/dbLibrary.rb @@ -30,13 +30,13 @@ class DBLibrary_TestClass < TestBase lib = RBA::Library::new assert_equal(lib.name, "") - assert_equal(lib.id, 0) + noid = lib.id; lib.register("RBA-unit-test") assert_equal(lib.name, "RBA-unit-test") lib_id = lib.id - assert_equal(lib_id != 0, true) + assert_equal(lib_id != noid, true) # the layout inside the library knows the library assert_equal(lib.layout.library.id == lib.id, true)