WIP (also for other issue #2172)

- New virtual method "reload" for Library
- Implementing that for file-based libraries
- Integrating that into "refresh"
- GSI binding for Library#rename, Library#unregister
- Trigger changed event on Library#unregister
- Library#_destroy will unregister the library
- Typos fixed
This commit is contained in:
Matthias Koefferlein 2025-10-11 16:21:53 +02:00
parent ec5de0ffe8
commit b3ec482eb8
6 changed files with 155 additions and 28 deletions

View File

@ -145,9 +145,25 @@ 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::rename (const std::string &name)
{
if (name != get_name () && db::LibraryManager::initialized ()) {
// if the name changed, reregister the library under the new name
db::LibraryManager::instance ().unregister_lib (this);
set_name (name);
db::LibraryManager::instance ().register_lib (this);
}
}
void
Library::refresh ()
{
std::string name = reload ();
rename (name);
layout ().refresh ();
remap_to (this);
}

View File

@ -65,6 +65,20 @@ public:
*/
virtual ~Library ();
/**
* @brief Called to reload the library
*
* If the library is a file-based one, this method can be reimplemented to reload
* the file. This method must not change the name of the library, but return a new
* name in case it has changed.
*
* @return The new name of the library
*/
virtual std::string reload ()
{
return get_name ();
}
/**
* @brief The layout object
*
@ -211,6 +225,14 @@ public:
*/
void refresh ();
/**
* @brief Renames the library
*
* Unlike "set_name", this method will take care of properly re-registering the library
* under the new name.
*/
void rename (const std::string &name);
/**
* @brief Remap the library proxies to a different library
*

View File

@ -126,6 +126,9 @@ LibraryManager::unregister_lib (Library *library)
library->remap_to (0);
library->set_id (std::numeric_limits<lib_id_type>::max ());
// issue the change notification
changed_event ();
}
void

View File

@ -79,6 +79,11 @@ static void register_lib (db::Library *lib, const std::string &name)
db::LibraryManager::instance ().register_lib (lib);
}
static void unregister_lib (db::Library *lib)
{
db::LibraryManager::instance ().unregister_lib (lib);
}
static void delete_lib (db::Library *lib)
{
db::LibraryManager::instance ().delete_lib (lib);
@ -97,7 +102,7 @@ static std::string get_technology (db::Library *lib)
static void destroy_lib (db::Library *lib)
{
if (db::LibraryManager::instance ().lib_ptr_by_name (lib->get_name ()) == lib) {
// Library is registered -> do not delete
delete_lib (lib);
} else {
delete lib;
}
@ -105,31 +110,51 @@ static void destroy_lib (db::Library *lib)
namespace {
template <class Base>
class LibraryClass
: public Class<db::Library>
: public gsi::Class<Base>
{
public:
LibraryClass (const char *module, const char *name, const gsi::Methods &methods, const char *description)
: Class<db::Library> (module, name, methods, description)
: gsi::Class<Base> (module, name, methods, description)
{ }
template <class B>
LibraryClass (const gsi::Class<B> &base, const char *module, const char *name, const gsi::Methods &methods, const char *description)
: gsi::Class<Base> (base, module, name, methods, description)
{ }
virtual void destroy (void *p) const
{
db::Library *lib = reinterpret_cast<db::Library *> (p);
Base *lib = reinterpret_cast<Base *> (p);
destroy_lib (lib);
}
};
class LibraryImpl
: public db::Library
{
public:
LibraryImpl () : db::Library () { }
virtual std::string reload ()
{
if (cb_reload.can_issue ()) {
return cb_reload.issue<db::Library, std::string> (&db::Library::reload);
} else {
return db::Library::reload ();
}
}
gsi::Callback cb_reload;
};
}
LibraryClass decl_Library ("db", "Library",
gsi::constructor ("new", &new_lib,
"@brief Creates a new, empty library"
) +
LibraryClass<db::Library> decl_Library ("db", "LibraryBase",
gsi::method ("library_by_name", &library_by_name, gsi::arg ("name"), gsi::arg ("for_technology", std::string (), "unspecific"),
"@brief Gets a library by name\n"
"Returns the library object for the given name. If the name is not a valid\n"
"library name, nil is returned.\n"
"Returns the library object for the given name. If the name is not a valid library name, nil is returned.\n"
"\n"
"Different libraries can be registered under the same names for different technologies. When a technology name is given in 'for_technologies', "
"the first library matching this technology is returned. If no technology is given, the first library is returned.\n"
@ -166,6 +191,22 @@ LibraryClass decl_Library ("db", "Library",
"\n"
"The technology specific behaviour has been introduced in version 0.27."
) +
gsi::method_ext ("unregister", &unregister_lib,
"@brief Unregisters the library\n"
"\n"
"Unregisters the library from the system. This will break all references of cells "
"using this library and make them 'defunct'.\n"
"\n"
"This method has been introduced in version 0.30.5."
) +
gsi::method ("rename", &db::Library::rename, gsi::arg ("name"),
"@brief Renames the library\n"
"\n"
"Re-registers the library under a new name. Note that this will not change library references - "
"i.e. references to the old name will become invalid after calling this method.\n"
"\n"
"This method has been introduced in version 0.30.5."
) +
gsi::method_ext ("delete", &delete_lib,
"@brief Deletes the library\n"
"\n"
@ -176,7 +217,7 @@ LibraryClass decl_Library ("db", "Library",
) +
gsi::method ("name", &db::Library::get_name,
"@brief Returns the libraries' name\n"
"The name is set when the library is registered and cannot be changed\n"
"The name is set when the library is registered. To change it use \\rename.\n"
) +
gsi::method ("id", &db::Library::get_id,
"@brief Returns the library's ID\n"
@ -240,9 +281,27 @@ LibraryClass decl_Library ("db", "Library",
"@brief Updates all layouts using this library.\n"
"This method will retire cells or update layouts in the attached clients.\n"
"It will also recompute the PCells inside the library. "
"Starting with version 0.30.5, this method will also call 'reload' on all libraries to "
"refresh cells located in external files.\n"
"\n"
"This method has been introduced in version 0.27.8."
),
"@hide"
);
LibraryClass<LibraryImpl> decl_LibraryImpl (decl_Library, "db", "Library",
gsi::constructor ("new", &new_lib,
"@brief Creates a new, empty library"
) +
gsi::callback ("reload", &LibraryImpl::reload, &LibraryImpl::cb_reload,
"@brief Reloads resources for the library.\n"
"Reimplement this method if you like to reload resources the library was created from - "
"for example layout files.\n"
"\n"
"@return The new name of the library or the original name if it did not change.\n"
"\n"
"This method is called on \\refresh. It was introduced in version 0.30.5.\n"
),
"@brief A Library \n"
"\n"
"A library is basically a wrapper around a layout object. The layout object\n"

View File

@ -1034,7 +1034,7 @@ Class<db::EqualDeviceParameters> decl_dbEqualDeviceParameters ("db", "EqualDevic
Class<GenericDeviceParameterCompare> decl_GenericDeviceParameterCompare (decl_dbEqualDeviceParameters, "db", "GenericDeviceParameterCompare",
gsi::callback ("less", &GenericDeviceParameterCompare::less, &GenericDeviceParameterCompare::cb_less, gsi::arg ("device_a"), gsi::arg ("device_b"),
"@brief Compares the parameters of two devices for a begin less than b. "
"@brief Compares the parameters of two devices for a begin less than b.\n"
"Returns true, if the parameters of device a are considered less than those of device b."
"The 'less' implementation needs to ensure strict weak ordering. Specifically, less(a,b) == false and less(b,a) implies that a is equal to b and "
"less(a,b) == true implies that less(b,a) is false and vice versa. If not, an internal error "

View File

@ -32,12 +32,53 @@
#include "dbReader.h"
#include "tlLog.h"
#include "tlStream.h"
#include "tlFileUtils.h"
#include <QDir>
namespace lay
{
// -------------------------------------------------------------------------------------------
class FileBasedLibrary
: public db::Library
{
public:
FileBasedLibrary (const std::string &path)
: db::Library (), m_path (path)
{
set_description (tl::filename (path));
}
virtual std::string reload ()
{
std::string name = tl::basename (m_path);
layout ().clear ();
tl::InputStream stream (m_path);
db::Reader reader (stream);
reader.read (layout ());
// Use the libname if there is one
db::Layout::meta_info_name_id_type libname_name_id = layout ().meta_info_name_id ("libname");
for (db::Layout::meta_info_iterator m = layout ().begin_meta (); m != layout ().end_meta (); ++m) {
if (m->first == libname_name_id && ! m->second.value.is_nil ()) {
name = m->second.value.to_string ();
break;
}
}
return name;
}
private:
std::string m_path;
};
// -------------------------------------------------------------------------------------------
LibraryController::LibraryController ()
: m_file_watcher (0),
dm_sync_files (this, &LibraryController::sync_files)
@ -166,7 +207,6 @@ LibraryController::sync_files ()
QStringList libs = lp.entryList (name_filters, QDir::Files);
for (QStringList::const_iterator im = libs.begin (); im != libs.end (); ++im) {
std::string filename = tl::to_string (*im);
std::string lib_path = tl::to_string (lp.absoluteFilePath (*im));
try {
@ -187,26 +227,13 @@ LibraryController::sync_files ()
if (needs_load) {
std::unique_ptr<db::Library> lib (new db::Library ());
lib->set_description (filename);
std::unique_ptr<db::Library> lib (new FileBasedLibrary (lib_path));
if (! p->second.empty ()) {
lib->set_technology (p->second);
}
lib->set_name (tl::to_string (QFileInfo (*im).baseName ()));
tl::log << "Reading library '" << lib_path << "'";
tl::InputStream stream (lib_path);
db::Reader reader (stream);
reader.read (lib->layout ());
// Use the libname if there is one
db::Layout::meta_info_name_id_type libname_name_id = lib->layout ().meta_info_name_id ("libname");
for (db::Layout::meta_info_iterator m = lib->layout ().begin_meta (); m != lib->layout ().end_meta (); ++m) {
if (m->first == libname_name_id && ! m->second.value.is_nil ()) {
lib->set_name (m->second.value.to_string ());
break;
}
}
lib->set_name (lib->reload ());
if (! p->second.empty ()) {
tl::log << "Registering as '" << lib->get_name () << "' for tech '" << p->second << "'";