diff --git a/src/db/db/dbLibrary.cc b/src/db/db/dbLibrary.cc index fec55c29b..6c0ca490c 100644 --- a/src/db/db/dbLibrary.cc +++ b/src/db/db/dbLibrary.cc @@ -46,6 +46,39 @@ Library::~Library () // .. nothing yet .. } +bool +Library::is_for_technology (const std::string &name) const +{ + return m_technologies.find (name) != m_technologies.end (); +} + +bool +Library::for_technologies () const +{ + return ! m_technologies.empty (); +} + +void +Library::set_technology (const std::string &t) +{ + m_technologies.clear (); + if (! t.empty ()) { + m_technologies.insert (t); + } +} + +void +Library::clear_technologies () +{ + m_technologies.clear (); +} + +void +Library::add_technology (const std::string &tech) +{ + m_technologies.insert (tech); +} + void Library::register_proxy (db::LibraryProxy *lib_proxy, db::Layout *ly) { diff --git a/src/db/db/dbLibrary.h b/src/db/db/dbLibrary.h index 422eec281..21cd70061 100644 --- a/src/db/db/dbLibrary.h +++ b/src/db/db/dbLibrary.h @@ -31,6 +31,7 @@ #include "tlObject.h" #include +#include namespace db { @@ -108,18 +109,38 @@ public: * If this attribute is non-empty, the library is selected only when the given technology is * used for the layout. */ - const std::string &get_technology () const + const std::set &get_technologies () const { - return m_technology; + return m_technologies; } /** - * @brief Sets the technology name this library is associated with + * @brief Gets a value indicating whether this library is associated with the given technology */ - void set_technology (const std::string &t) - { - m_technology = t; - } + bool is_for_technology (const std::string &name) const; + + /** + * @brief Gets a value indicating whether the library is associated with any technology + */ + bool for_technologies () const; + + /** + * @brief Sets the technology name this library is associated with + * + * This will reset the list of technologies to this one. + * If the given technology string is empty, the list of technologies will be cleared. + */ + void set_technology (const std::string &t); + + /** + * @brief Clears the list of technologies this library is associated with + */ + void clear_technologies (); + + /** + * @brief Additionally associate the library with the given technology + */ + void add_technology (const std::string &tech); /** * @brief Getter for the description property @@ -198,7 +219,7 @@ public: private: std::string m_name; std::string m_description; - std::string m_technology; + std::set m_technologies; lib_id_type m_id; db::Layout m_layout; std::map m_referrers; diff --git a/src/db/db/gsiDeclDbLibrary.cc b/src/db/db/gsiDeclDbLibrary.cc index ff4f406a1..cfd1f5f2f 100644 --- a/src/db/db/gsiDeclDbLibrary.cc +++ b/src/db/db/gsiDeclDbLibrary.cc @@ -68,6 +68,16 @@ static void delete_lib (db::Library *lib) db::LibraryManager::instance ().delete_lib (lib); } +static std::string get_technology (db::Library *lib) +{ + const std::set &techs = lib->get_technologies (); + if (techs.empty ()) { + return std::string (); + } else { + return *techs.begin (); + } +} + Class decl_Library ("db", "Library", gsi::constructor ("new", &new_lib, "@brief Creates a new, empty library" @@ -114,19 +124,48 @@ Class decl_Library ("db", "Library", "@brief Sets the libraries' description text\n" "@args description\n" ) + - gsi::method ("technology", &db::Library::get_technology, + gsi::method_ext ("#technology", &get_technology, "@brief Returns name of the technology the library is associated with\n" "If this attribute is a non-empty string, this library is only offered for " "selection if the current layout uses this technology.\n" "\n" - "This attribute has been introduced in version 0.25." + "This attribute has been introduced in version 0.25. In version 0.27 this attribute is deprecated as " + "a library can now be associated with multiple technologies." ) + gsi::method ("technology=", &db::Library::set_technology, "@brief sets the name of the technology the library is associated with\n" "@args technology\n" "\n" "See \\technology for details. " - "This attribute has been introduced in version 0.25." + "This attribute has been introduced in version 0.25. In version 0.27, a library can be associated with " + "multiple technologies and this method will revert the selection to a single one. Passing an empty string " + "is equivalent to \\clear_technologies." + ) + + gsi::method ("clear_technologies", &db::Library::clear_technologies, + "@brief Clears the list of technologies the library is associated with.\n" + "See also \\add_technology.\n" + "\n" + "This method has been introduced in version 0.27" + ) + + gsi::method ("add_technology", &db::Library::add_technology, gsi::arg ("tech"), + "@brief Additionally associates the library with the given technology.\n" + "See also \\clear_technologies.\n" + "\n" + "This method has been introduced in version 0.27" + ) + + gsi::method ("is_for_technology", &db::Library::is_for_technology, gsi::arg ("tech"), + "@brief Returns a value indicating whether the library is associated with the given technology.\n" + "This method has been introduced in version 0.27" + ) + + gsi::method ("for_technologies", &db::Library::for_technologies, + "@brief Returns a value indicating whether the library is associated with any technology.\n" + "The method is equivalent to checking whether the \\technologies list is empty.\n" + "\n" + "This method has been introduced in version 0.27" + ) + + gsi::method ("technologies", &db::Library::get_technologies, + "@brief Gets the list of technologies this library is associated with.\n" + "This method has been introduced in version 0.27" ) + gsi::method ("layout_const", (const db::Layout &(db::Library::*)() const) &db::Library::layout, "@brief The layout object where the cells reside that this library defines (const version)\n" diff --git a/src/lay/lay/layLibraryController.cc b/src/lay/lay/layLibraryController.cc index 2636a4ede..36556b05a 100644 --- a/src/lay/lay/layLibraryController.cc +++ b/src/lay/lay/layLibraryController.cc @@ -205,7 +205,7 @@ LibraryController::sync_files () } } - tl::log << "Registering as '" << lib->get_name () << "' for tech '" << lib->get_technology () << "'"; + tl::log << "Registering as '" << lib->get_name () << "' for tech '" << p->second << "'"; new_lib_files.insert (std::make_pair (lib_path, std::make_pair (lib->get_name (), fi.lastModified ()))); db::LibraryManager::instance ().register_lib (lib.release ()); diff --git a/src/lay/lay/layTechSetupDialog.cc b/src/lay/lay/layTechSetupDialog.cc index e89396411..266c42cf6 100644 --- a/src/lay/lay/layTechSetupDialog.cc +++ b/src/lay/lay/layTechSetupDialog.cc @@ -135,7 +135,7 @@ TechBaseEditorPage::setup () for (db::LibraryManager::iterator l = db::LibraryManager::instance ().begin (); l != db::LibraryManager::instance ().end (); ++l) { const db::Library *lib = db::LibraryManager::instance ().lib (l->second); - if (lib->get_technology () == tech ()->name ()) { + if (lib->is_for_technology (tech ()->name ())) { std::string text = lib->get_name (); if (! lib->get_description ().empty ()) { text += " - " + lib->get_description (); diff --git a/src/laybasic/laybasic/layLibrariesView.cc b/src/laybasic/laybasic/layLibrariesView.cc index fd9aced34..fa63e5ba0 100644 --- a/src/laybasic/laybasic/layLibrariesView.cc +++ b/src/laybasic/laybasic/layLibrariesView.cc @@ -794,9 +794,10 @@ LibrariesView::display_string (int n) const if (! lib->get_description ().empty ()) { text += " - " + lib->get_description (); } - if (! lib->get_technology ().empty ()) { + if (lib->for_technologies ()) { text += " "; - text += tl::to_string (QObject::tr ("[Technology %1]").arg (tl::to_qstring (lib->get_technology ()))); + std::string tn = tl::join (std::vector (lib->get_technologies ().begin (), lib->get_technologies ().end ()), ","); + text += tl::to_string (QObject::tr ("[Technology %1]").arg (tl::to_qstring (tn))); } return text; } diff --git a/src/laybasic/laybasic/layWidgets.cc b/src/laybasic/laybasic/layWidgets.cc index ca9da9088..bfa616bb0 100644 --- a/src/laybasic/laybasic/layWidgets.cc +++ b/src/laybasic/laybasic/layWidgets.cc @@ -600,15 +600,16 @@ LibrarySelectionComboBox::update_list () for (db::LibraryManager::iterator l = db::LibraryManager::instance ().begin (); l != db::LibraryManager::instance ().end (); ++l) { db::Library *lib = db::LibraryManager::instance ().lib (l->second); - if (! m_tech_set || lib->get_technology ().empty () || m_tech == lib->get_technology ()) { + if (! m_tech_set || !lib->for_technologies ()|| lib->is_for_technology (m_tech)) { std::string item_text = lib->get_name (); if (! lib->get_description ().empty ()) { item_text += " - " + lib->get_description (); } - if (m_tech_set && !lib->get_technology ().empty ()) { + if (m_tech_set && lib->for_technologies ()) { item_text += " "; - item_text += tl::to_string (QObject::tr ("[Technology %1]").arg (tl::to_qstring (lib->get_technology ()))); + std::string tn = tl::join (std::vector (lib->get_technologies ().begin (), lib->get_technologies ().end ()), ","); + item_text += tl::to_string (QObject::tr ("[Technology %1]").arg (tl::to_qstring (tn))); } addItem (tl::to_qstring (item_text), QVariant ((unsigned int) lib->get_id ())); diff --git a/src/rba/unit_tests/rba.cc b/src/rba/unit_tests/rba.cc index c7ac735e6..75f79c5cd 100644 --- a/src/rba/unit_tests/rba.cc +++ b/src/rba/unit_tests/rba.cc @@ -104,6 +104,7 @@ RUBYTEST (dbGlyphs, "dbGlyphs.rb") RUBYTEST (dbInstanceTest, "dbInstanceTest.rb") RUBYTEST (dbInstElementTest, "dbInstElementTest.rb") RUBYTEST (dbLayerMapping, "dbLayerMapping.rb") +RUBYTEST (dbLibrary, "dbLibrary.rb") RUBYTEST (dbLayout, "dbLayout.rb") RUBYTEST (dbLayoutTest, "dbLayoutTest.rb") RUBYTEST (dbLayoutDiff, "dbLayoutDiff.rb") diff --git a/testdata/ruby/dbLibrary.rb b/testdata/ruby/dbLibrary.rb new file mode 100644 index 000000000..cd73007a5 --- /dev/null +++ b/testdata/ruby/dbLibrary.rb @@ -0,0 +1,93 @@ +# encoding: UTF-8 + +# KLayout Layout Viewer +# Copyright (C) 2006-2020 Matthias Koefferlein +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +if !$:.member?(File::dirname($0)) + $:.push(File::dirname($0)) +end + +load("test_prologue.rb") + +class DBLibrary_TestClass < TestBase + + def test_1_registration + + lib = RBA::Library::new + + assert_equal(lib.name, "") + assert_equal(lib.id, 0) + + lib.register("RBA-unit-test") + + assert_equal(lib.name, "RBA-unit-test") + assert_equal(lib.id != 0, true) + + assert_equal(RBA::Library::library_names.member?("RBA-unit-test"), true) + assert_equal(RBA::Library::library_by_name("RBA-unit-test").id, lib.id) + + lib.delete + assert_equal(RBA::Library::library_by_name("RBA-unit-test"), nil) + + end + + def test_2_attributes + + lib = RBA::Library::new + + lib.description = "42 is the answer" + assert_equal(lib.description, "42 is the answer") + + assert_equal(lib.is_for_technology("X"), false) + assert_equal(lib.technologies, []) + assert_equal(lib.for_technologies, false) + + lib.technology = "X" + assert_equal(lib.is_for_technology("X"), true) + assert_equal(lib.technologies, ["X"]) + assert_equal(lib.for_technologies, true) + + lib.technology = "" + assert_equal(lib.is_for_technology("X"), false) + assert_equal(lib.technologies, []) + assert_equal(lib.for_technologies, false) + + lib.add_technology("Y") + assert_equal(lib.is_for_technology("X"), false) + assert_equal(lib.is_for_technology("Y"), true) + assert_equal(lib.technologies, ["Y"]) + assert_equal(lib.for_technologies, true) + + lib.clear_technologies + assert_equal(lib.is_for_technology("Y"), false) + assert_equal(lib.technologies, []) + assert_equal(lib.for_technologies, false) + + end + + def test_3_layout + + lib = RBA::Library::new + lib.layout.create_cell("X") + assert_equal(lib.layout.top_cell.name, "X") + + end + +end + +load("test_epilogue.rb") +