mirror of https://github.com/KLayout/klayout.git
issue-996 Providing a "refresh" function for triggering a refresh from inside t… (#998)
* 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.
This commit is contained in:
parent
ffbdb90ad8
commit
4226ab0078
|
|
@ -25,25 +25,31 @@
|
|||
#include "dbLibraryProxy.h"
|
||||
#include "dbPCellDeclaration.h"
|
||||
#include "dbPCellVariant.h"
|
||||
#include "dbLibraryManager.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
Library::Library()
|
||||
: m_id (0), m_layout (true)
|
||||
: m_id (std::numeric_limits<lib_id_type>::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<lib_id_type>::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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "tlAssert.h"
|
||||
#include "tlStaticObjects.h"
|
||||
#include "tlClassRegistry.h"
|
||||
#include "tlThreads.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
|
@ -69,13 +70,15 @@ LibraryManager::~LibraryManager ()
|
|||
std::pair<bool, lib_id_type>
|
||||
LibraryManager::lib_by_name (const std::string &name, const std::set<std::string> &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<std::string>::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::set<std::string
|
|||
// fallback: technology-unspecific libs
|
||||
l = m_lib_by_name.find (name);
|
||||
while (l != m_lib_by_name.end () && l->first == 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::set<std::string
|
|||
}
|
||||
|
||||
void
|
||||
LibraryManager::delete_lib (Library *library)
|
||||
LibraryManager::unregister_lib (Library *library)
|
||||
{
|
||||
if (!library) {
|
||||
if (! library) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_lib_by_name.erase (library->get_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<lib_id_type>::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<size_t>::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<lib_id_type>::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<Library *> 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<Library *>::iterator l = libs.begin (); l != libs.end (); ++l) {
|
||||
if (*l) {
|
||||
(*l)->remap_to (0);
|
||||
(*l)->set_id (std::numeric_limits<lib_id_type>::max ());
|
||||
delete *l;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "dbTypes.h"
|
||||
#include "tlClassRegistry.h"
|
||||
#include "tlEvents.h"
|
||||
#include "tlThreads.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
|
@ -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<Library *> m_libs;
|
||||
lib_name_map m_lib_by_name;
|
||||
mutable tl::Mutex m_lock;
|
||||
|
||||
LibraryManager ();
|
||||
Library *lib_internal (lib_id_type id) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<db::Layout &> (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*/);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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<db::Layout &> (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<std::string> 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<LIBT_L> l (new LIBT_L (_this));
|
||||
db::lib_id_type lib_id = db::LibraryManager::instance ().register_lib (l.get ());
|
||||
|
||||
try {
|
||||
std::vector<std::string> 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<std::string> 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<std::string> ll = libnames_before;
|
||||
ll.push_back ("L");
|
||||
std::sort (ll.begin (), ll.end ());
|
||||
|
||||
std::vector<std::string> 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<bool, db::lib_id_type> 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<bool, db::lib_id_type> 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<tl::Variant> 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<tl::Variant> 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<const db::LibraryProxy *> (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<const db::LibraryProxy *> (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<std::string> 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<LIBT_L> 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<tl::Variant> 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<tl::Variant> 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<bool, db::cell_index_type> 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<tl::Variant> new_param = tmp.get_pcell_parameters (tmp_pd2.second);
|
||||
std::pair<bool, db::cell_index_type> 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<tl::Variant> new_param = tmp.get_pcell_parameters (tmp_pd2.second);
|
||||
|
||||
std::pair<bool, db::cell_index_type> 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<bool, db::cell_index_type> 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<LIBT_A> 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<LIBT_B> 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<LIBT_A> lib_a1 (new LIBT_A ());
|
||||
std::unique_ptr<LIBT_A> lib_a1_inst (new LIBT_A ());
|
||||
tl::weak_ptr<LIBT_A> lib_a1 (lib_a1_inst.get ());
|
||||
lib_a1->add_technology ("X");
|
||||
|
||||
tl::weak_ptr<LIBT_A> lib_a2 (new LIBT_A ());
|
||||
std::unique_ptr<LIBT_A> lib_a2_inst (new LIBT_A ());
|
||||
tl::weak_ptr<LIBT_A> lib_a2 (lib_a2_inst.get ());
|
||||
lib_a2->add_technology ("Y");
|
||||
|
||||
tl::weak_ptr<LIBT_A> lib_a3 (new LIBT_A ());
|
||||
std::unique_ptr<LIBT_A> lib_a3_inst (new LIBT_A ());
|
||||
tl::weak_ptr<LIBT_A> lib_a3 (lib_a3_inst.get ());
|
||||
lib_a3->add_technology ("X");
|
||||
|
||||
tl::weak_ptr<LIBT_A> lib_a4 (new LIBT_A ());
|
||||
std::unique_ptr<LIBT_A> lib_a4_inst (new LIBT_A ());
|
||||
tl::weak_ptr<LIBT_A> 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<db::Library> lib;
|
||||
lib.reset (new db::Library ());
|
||||
std::unique_ptr<db::Library> 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<LIBT_A> 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));
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue