From 0a03a2809a9ccdc30aaf731c9e066c47f5025cb6 Mon Sep 17 00:00:00 2001 From: Ethan Mahintorabi Date: Mon, 12 Dec 2022 19:03:59 +0000 Subject: [PATCH 01/17] Fixes segfault on some linux systems The static order initialization seems to be more present throughout Klayout and might cause additional issues, but this fix stopped the segfault on my machine. When compiling with asan there are a number or other issues that could be addressed, but it's not clear if they're real problems. dbLayout change occured when using the python API to read a DEF layout. When the layout is updated the code uses a const iterator which implicitly wraps the non-const iterator. In the loop the end() is implicitly wrapped, which tries to dereference a nullptr. My fix checks to ensure that the non-const iterator is not null before trying blindly dereference it. --- src/db/db/dbLayout.h | 9 +++++++-- src/tl/tl/tlClassRegistry.cc | 29 +++++++++++++++-------------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h index 450f8ba80..222860458 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -192,8 +192,13 @@ public: * @brief Default constructor */ cell_list_const_iterator (cell_list_iterator iter) - : mp_cell (& (*iter)) - { } + { + if (iter == cell_list_iterator()) { + mp_cell = nullptr; + } else { + mp_cell = &(*iter); + } + } /** * @brief Equality diff --git a/src/tl/tl/tlClassRegistry.cc b/src/tl/tl/tlClassRegistry.cc index b208dc5b2..a02311d5b 100644 --- a/src/tl/tl/tlClassRegistry.cc +++ b/src/tl/tl/tlClassRegistry.cc @@ -23,35 +23,36 @@ #include "tlClassRegistry.h" -#include +#include +#include +#include namespace tl { -struct ti_compare_f -{ - bool operator() (const std::type_info *a, const std::type_info *b) const - { - return a->before (*b); - } -}; +typedef std::map inst_map_type; -typedef std::map inst_map_type; -static inst_map_type s_inst_map; +// Used to fix https://en.cppreference.com/w/cpp/language/siof segfault +// on some systems. +inst_map_type& s_inst_map() { + static inst_map_type s_inst_map; + return s_inst_map; +} TL_PUBLIC void set_registrar_instance_by_type (const std::type_info &ti, RegistrarBase *rb) { if (rb) { - s_inst_map[&ti] = rb; + s_inst_map()[std::type_index(ti)] = rb; } else { - s_inst_map.erase (&ti); + s_inst_map().erase (std::type_index(ti)); } } TL_PUBLIC RegistrarBase *registrar_instance_by_type (const std::type_info &ti) { - inst_map_type::const_iterator im = s_inst_map.find (&ti); - if (im != s_inst_map.end ()) { + inst_map_type map = s_inst_map(); + inst_map_type::const_iterator im = map.find (std::type_index(ti)); + if (im != map.end ()) { return im->second; } else { return 0; From a2164ec88b94e0267464746eaee0c66a1fa4a2c9 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 13 Dec 2022 21:14:39 +0100 Subject: [PATCH 02/17] Added comment about NetTracerTechnology to change log (#1223) --- Changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog b/Changelog index 10ebaa80e..b9389c6d6 100644 --- a/Changelog +++ b/Changelog @@ -87,6 +87,7 @@ Changes (list may not be complete): - Box/DBox square and rectangle convenience constructor - Box#enlarge convenience isotropic variant - Region#in_and_out, Edges#in_and_out + - New class NetTracerConnectivity introduced for multi-stack support in NetTracerTechnology, substitutes connectivity part NetTracerTechnology 0.27.13 (2022-11-30): * Bugfixes: From f49fa646fc117cf4faf0a4270cdbc93341208729 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 13 Dec 2022 21:54:00 +0100 Subject: [PATCH 03/17] Patched PR with leaner solution --- src/db/db/dbLayout.h | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h index 222860458..79337f3b0 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -192,13 +192,8 @@ public: * @brief Default constructor */ cell_list_const_iterator (cell_list_iterator iter) - { - if (iter == cell_list_iterator()) { - mp_cell = nullptr; - } else { - mp_cell = &(*iter); - } - } + : mp_cell (iter.operator-> ()) + { } /** * @brief Equality From 435e9232e7299bf10a9283de7bc99919138b7514 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 13 Dec 2022 22:05:42 +0100 Subject: [PATCH 04/17] Update pypa/cibuildwheel to 2.11.3 version for Python 3.11 support --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d9598516d..09215828c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,7 +40,7 @@ jobs: HOST_CCACHE_DIR="$(ccache -k cache_dir)" mkdir -p $HOST_CCACHE_DIR - name: Build wheels # check https://cibuildwheel.readthedocs.io/en/stable/setup/#github-actions - uses: pypa/cibuildwheel@v2.5.0 + uses: pypa/cibuildwheel@v2.11.3 # to supply options, put them in 'env', like: # env: # CIBW_SOME_OPTION: value From fd5ae12951d1a5f08246a5a444e28a563b32524f Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 13 Dec 2022 22:15:36 +0100 Subject: [PATCH 05/17] Dropping klayout Python module from RPM and DEB packages as this creates clashes with the PyPI python module. As substitute install klayout module from PyPI. --- scripts/makedeb.sh | 13 ------------- scripts/rpm-data/klayout.spec | 18 ------------------ 2 files changed, 31 deletions(-) diff --git a/scripts/makedeb.sh b/scripts/makedeb.sh index 760fe0e19..81fc8291d 100755 --- a/scripts/makedeb.sh +++ b/scripts/makedeb.sh @@ -55,10 +55,6 @@ sharedir="usr/share" bindir="usr/bin" libdir="usr/lib/klayout" -# TODO: is there a better way to produce this path? -distpackdir="usr/lib/python3/dist-packages" -pylibdir="$distpackdir/klayout" - # clean bin directory rm -rf $bininstdir @@ -97,7 +93,6 @@ mkdir -p makedeb-tmp/${sharedir}/applications mkdir -p makedeb-tmp/${sharedir}/pixmaps mkdir -p makedeb-tmp/${libdir}/db_plugins mkdir -p makedeb-tmp/${libdir}/lay_plugins -mkdir -p makedeb-tmp/${pylibdir} mkdir -p makedeb-tmp/${bindir} cp etc/klayout.desktop makedeb-tmp/${sharedir}/applications @@ -111,13 +106,6 @@ cp -pd $bininstdir/klayout makedeb-tmp/${bindir} cp -pd $bininstdir/lib*so* makedeb-tmp/${libdir} cp -pd $bininstdir/db_plugins/lib*so* makedeb-tmp/${libdir}/db_plugins cp -pd $bininstdir/lay_plugins/lib*so* makedeb-tmp/${libdir}/lay_plugins -cp -pd $bininstdir/pymod/klayout/*so makedeb-tmp/${pylibdir} -cp -pd $bininstdir/pymod/klayout/*py makedeb-tmp/${pylibdir} -for d in db tl rdb lib; do - mkdir -p makedeb-tmp/${pylibdir}/$d - cp -pd $bininstdir/pymod/klayout/$d/*py makedeb-tmp/${pylibdir}/$d -done -sed "s/%VERSION%/$version/g" makedeb-tmp/${distpackdir}/klayout.egg-info cd makedeb-tmp @@ -141,7 +129,6 @@ grep -q $version ${sharedir}/doc/klayout/changelog.Debian || ( echo "Modifying control file .." strip ${bindir}/* -strip ${pylibdir}/*.so strip ${libdir}/db_plugins/*.so* strip ${libdir}/lay_plugins/*.so* diff --git a/scripts/rpm-data/klayout.spec b/scripts/rpm-data/klayout.spec index 71f29855b..c7024b50c 100644 --- a/scripts/rpm-data/klayout.spec +++ b/scripts/rpm-data/klayout.spec @@ -45,7 +45,6 @@ Requires: qt5-qttools >= 5.11.1 Requires: qt5-qttools-devel >= 5.11.1 %define buildopt -j2 -%define pylib %{python_sitearch} %define __python /usr/bin/python3 %endif @@ -55,7 +54,6 @@ Requires: ruby >= 2.0.0 Requires: python3 >= 3.6.0 Requires: qt-x11 >= 4.8.5 %define buildopt -j2 -%define pylib %{python3_sitearch} %endif %if "%{target_system}" == "centos6" @@ -65,7 +63,6 @@ Requires: ruby >= 1.8.7 Requires: python >= 2.6.6 Requires: qt-x11 >= 4.6.2 %define buildopt -libcurl -j2 -%define pylib %{python_sitearch} %endif %if "%{target_system}" == "opensuse42_2" @@ -74,7 +71,6 @@ Requires: ruby2.3 >= 2.3.1 Requires: python3 >= 3.4.6 Requires: libqt4-x11 >= 4.8.6 %define buildopt -j2 -%define pylib %{python3_sitearch} %endif %if "%{target_system}" == "opensuse42_3" @@ -83,7 +79,6 @@ Requires: ruby2.3 >= 2.3.1 Requires: python3 >= 3.4.6 Requires: libqt4-x11 >= 4.8.6 %define buildopt -j2 -%define pylib %{python3_sitearch} %endif %if "%{target_system}" == "opensuse15" @@ -92,7 +87,6 @@ Requires: ruby >= 2.5 Requires: python3 >= 3.6 Requires: libqt4-x11 >= 4.8.7 %define buildopt -j2 -%define pylib %{python3_sitearch} %endif %if "%{target_system}" == "opensuse15" @@ -148,17 +142,6 @@ strip %{_builddir}/bin.$TARGET/strm* TARGET="linux-release" -# create and populate pylib -mkdir -p %{buildroot}%{pylib}/klayout -cp -pd %{_builddir}/bin.$TARGET/pymod/klayout/*.so %{buildroot}%{pylib}/klayout -cp -pd %{_builddir}/bin.$TARGET/pymod/klayout/*.py %{buildroot}%{pylib}/klayout -chmod 644 %{buildroot}%{pylib}/klayout/* -for d in tl db rdb lib; do - mkdir -p %{buildroot}%{pylib}/klayout/$d - cp -pd %{_builddir}/bin.$TARGET/pymod/klayout/$d/*.py %{buildroot}%{pylib}/klayout/$d - chmod 644 %{buildroot}%{pylib}/klayout/$d/* -done - # create and populate libdir mkdir -p %{buildroot}%{_libdir}/klayout mkdir -p %{buildroot}%{_libdir}/klayout/db_plugins @@ -191,7 +174,6 @@ install -Dm644 %{_sourcedir}/etc/logo.png %{buildroot}%{_datadir}/pixmaps/%{name %doc CONTRIB %{_bindir}/klayout %{_bindir}/strm* -%{pylib}/klayout/* %{_libdir}/klayout/* %{_datadir}/applications/%{name}.desktop %{_datadir}/pixmaps/%{name}.png From 199dea536ab6708cdffbeaf84565cd2da379667f Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 13 Dec 2022 22:49:49 +0100 Subject: [PATCH 06/17] Fixed a small bug: d25 material list view background was reset to black with Auto background color --- src/plugins/tools/view_25d/lay_plugin/layD25View.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc index ba1b49639..c525c28ec 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc @@ -125,6 +125,10 @@ bool D25View::configure(const std::string &name, const std::string &value) tl::Color bg; lc.from_string (value, bg); + if (! bg.is_valid ()) { + bg = view () ? view ()->background_color () : Qt::white; + } + QPalette palette = mp_ui->material_list->palette (); palette.setColor (QPalette::Base, bg.to_qc ()); palette.setColor (QPalette::Text, bg.to_mono () ? Qt::black : Qt::white); From ad27c9a51d02f2e1462a58937d4af34b76bbfd8e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 13 Dec 2022 23:35:11 +0100 Subject: [PATCH 07/17] WIP: trying to enhance layout layer lookup performance. --- src/db/db/db.pro | 300 +++++++++--------- src/db/db/dbLayout.cc | 266 ++-------------- src/db/db/dbLayout.h | 103 ++----- src/db/db/dbLayoutLayers.cc | 318 ++++++++++++++++++++ src/db/db/dbLayoutLayers.h | 282 +++++++++++++++++ src/laybasic/laybasic/layLayerProperties.cc | 6 +- 6 files changed, 802 insertions(+), 473 deletions(-) create mode 100644 src/db/db/dbLayoutLayers.cc create mode 100644 src/db/db/dbLayoutLayers.h diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 16f2caffb..dc634cd78 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -39,6 +39,7 @@ SOURCES = \ dbLayerMapping.cc \ dbLayerProperties.cc \ dbLayout.cc \ + dbLayoutLayers.cc \ dbLayoutContextHandler.cc \ dbLayoutDiff.cc \ dbLayoutQuery.cc \ @@ -138,85 +139,85 @@ SOURCES = \ gsiDeclDbVector.cc \ gsiDeclDbLayoutDiff.cc \ gsiDeclDbGlyphs.cc \ - dbConverters.cc \ - dbAsIfFlatRegion.cc \ - dbEmptyRegion.cc \ - dbFlatRegion.cc \ - dbOriginalLayerRegion.cc \ - dbRegionDelegate.cc \ - dbEdgesDelegate.cc \ - dbEmptyEdges.cc \ - dbAsIfFlatEdges.cc \ - dbFlatEdges.cc \ - dbEdgeBoolean.cc \ - dbOriginalLayerEdges.cc \ - dbAsIfFlatEdgePairs.cc \ - dbEmptyEdgePairs.cc \ - dbFlatEdgePairs.cc \ - dbOriginalLayerEdgePairs.cc \ - dbEdgePairsDelegate.cc \ - dbDeepShapeStore.cc \ - dbHierarchyBuilder.cc \ - dbLocalOperation.cc \ - dbHierProcessor.cc \ - dbDeepRegion.cc \ - dbHierNetworkProcessor.cc \ - dbNetlist.cc \ - gsiDeclDbNetlist.cc \ - dbNetlistDeviceClasses.cc \ - dbNetlistDeviceExtractor.cc \ - dbNetlistExtractor.cc \ - gsiDeclDbNetlistDeviceClasses.cc \ - gsiDeclDbNetlistDeviceExtractor.cc \ - gsiDeclDbHierNetworkProcessor.cc \ - dbNetlistDeviceExtractorClasses.cc \ - dbLayoutToNetlist.cc \ - gsiDeclDbLayoutToNetlist.cc \ - dbCircuit.cc \ - dbDevice.cc \ - dbDeviceClass.cc \ - dbNet.cc \ - dbSubCircuit.cc \ - dbPin.cc \ - dbLayoutToNetlistReader.cc \ - dbLayoutToNetlistWriter.cc \ - dbLayoutToNetlistFormatDefs.cc \ - dbDeviceAbstract.cc \ - dbLocalOperationUtils.cc \ - gsiDeclDbDeepShapeStore.cc \ - dbNetlistSpiceWriter.cc \ - dbNetlistWriter.cc \ - dbCellVariants.cc \ - dbDeepEdges.cc \ - dbDeepEdgePairs.cc \ - dbRegionUtils.cc \ - dbEdgesUtils.cc \ - dbRegionProcessors.cc \ - dbNetlistCompare.cc \ - dbNetlistReader.cc \ - dbNetlistSpiceReader.cc \ - gsiDeclDbNetlistCompare.cc \ - dbNetlistCrossReference.cc \ - dbLayoutVsSchematicWriter.cc \ - dbLayoutVsSchematicReader.cc \ - dbLayoutVsSchematicFormatDefs.cc \ - dbLayoutVsSchematic.cc \ - gsiDeclDbNetlistCrossReference.cc \ - gsiDeclDbLayoutVsSchematic.cc \ - dbNetlistObject.cc \ - gsiDeclDbTexts.cc \ - dbTexts.cc \ - dbDeepTexts.cc \ - dbAsIfFlatTexts.cc \ - dbTextsDelegate.cc \ - dbEmptyTexts.cc \ - dbFlatTexts.cc \ - dbTextsUtils.cc \ - dbOriginalLayerTexts.cc \ - dbNetShape.cc \ - dbShapeCollection.cc \ - gsiDeclDbShapeCollection.cc \ - dbShapeCollectionUtils.cc + dbConverters.cc \ + dbAsIfFlatRegion.cc \ + dbEmptyRegion.cc \ + dbFlatRegion.cc \ + dbOriginalLayerRegion.cc \ + dbRegionDelegate.cc \ + dbEdgesDelegate.cc \ + dbEmptyEdges.cc \ + dbAsIfFlatEdges.cc \ + dbFlatEdges.cc \ + dbEdgeBoolean.cc \ + dbOriginalLayerEdges.cc \ + dbAsIfFlatEdgePairs.cc \ + dbEmptyEdgePairs.cc \ + dbFlatEdgePairs.cc \ + dbOriginalLayerEdgePairs.cc \ + dbEdgePairsDelegate.cc \ + dbDeepShapeStore.cc \ + dbHierarchyBuilder.cc \ + dbLocalOperation.cc \ + dbHierProcessor.cc \ + dbDeepRegion.cc \ + dbHierNetworkProcessor.cc \ + dbNetlist.cc \ + gsiDeclDbNetlist.cc \ + dbNetlistDeviceClasses.cc \ + dbNetlistDeviceExtractor.cc \ + dbNetlistExtractor.cc \ + gsiDeclDbNetlistDeviceClasses.cc \ + gsiDeclDbNetlistDeviceExtractor.cc \ + gsiDeclDbHierNetworkProcessor.cc \ + dbNetlistDeviceExtractorClasses.cc \ + dbLayoutToNetlist.cc \ + gsiDeclDbLayoutToNetlist.cc \ + dbCircuit.cc \ + dbDevice.cc \ + dbDeviceClass.cc \ + dbNet.cc \ + dbSubCircuit.cc \ + dbPin.cc \ + dbLayoutToNetlistReader.cc \ + dbLayoutToNetlistWriter.cc \ + dbLayoutToNetlistFormatDefs.cc \ + dbDeviceAbstract.cc \ + dbLocalOperationUtils.cc \ + gsiDeclDbDeepShapeStore.cc \ + dbNetlistSpiceWriter.cc \ + dbNetlistWriter.cc \ + dbCellVariants.cc \ + dbDeepEdges.cc \ + dbDeepEdgePairs.cc \ + dbRegionUtils.cc \ + dbEdgesUtils.cc \ + dbRegionProcessors.cc \ + dbNetlistCompare.cc \ + dbNetlistReader.cc \ + dbNetlistSpiceReader.cc \ + gsiDeclDbNetlistCompare.cc \ + dbNetlistCrossReference.cc \ + dbLayoutVsSchematicWriter.cc \ + dbLayoutVsSchematicReader.cc \ + dbLayoutVsSchematicFormatDefs.cc \ + dbLayoutVsSchematic.cc \ + gsiDeclDbNetlistCrossReference.cc \ + gsiDeclDbLayoutVsSchematic.cc \ + dbNetlistObject.cc \ + gsiDeclDbTexts.cc \ + dbTexts.cc \ + dbDeepTexts.cc \ + dbAsIfFlatTexts.cc \ + dbTextsDelegate.cc \ + dbEmptyTexts.cc \ + dbFlatTexts.cc \ + dbTextsUtils.cc \ + dbOriginalLayerTexts.cc \ + dbNetShape.cc \ + dbShapeCollection.cc \ + gsiDeclDbShapeCollection.cc \ + dbShapeCollectionUtils.cc HEADERS = \ dbArray.h \ @@ -256,6 +257,7 @@ HEADERS = \ dbLayerProperties.h \ dbLayoutDiff.h \ dbLayout.h \ + dbLayoutLayers.h \ dbLayoutQuery.h \ dbLayoutStateModel.h \ dbLayoutUtils.h \ @@ -321,76 +323,76 @@ HEADERS = \ dbForceLink.h \ dbPlugin.h \ dbInit.h \ - dbConverters.h \ - dbAsIfFlatRegion.h \ - dbEmptyRegion.h \ - dbFlatRegion.h \ - dbOriginalLayerRegion.h \ - dbRegionDelegate.h \ - dbEdgesDelegate.h \ - dbEmptyEdges.h \ - dbAsIfFlatEdges.h \ - dbFlatEdges.h \ - dbEdgeBoolean.h \ - dbOriginalLayerEdges.h \ - dbAsIfFlatEdgePairs.h \ - dbEmptyEdgePairs.h \ - dbFlatEdgePairs.h \ - dbOriginalLayerEdgePairs.h \ - dbEdgePairsDelegate.h \ - dbDeepShapeStore.h \ - dbHierarchyBuilder.h \ - dbLocalOperation.h \ - dbHierProcessor.h \ - dbNetlist.h \ - dbNetlistDeviceClasses.h \ - dbNetlistDeviceExtractor.h \ - dbNetlistExtractor.h \ - dbNetlistDeviceExtractorClasses.h \ - dbLayoutToNetlist.h \ - dbHierNetworkProcessor.h \ - dbNetlistUtils.h \ - dbNet.h \ - dbCircuit.h \ - dbDevice.h \ - dbDeviceClass.h \ - dbPin.h \ - dbSubCircuit.h \ - dbLayoutToNetlistReader.h \ - dbLayoutToNetlistWriter.h \ - dbLayoutToNetlistFormatDefs.h \ - dbDeviceAbstract.h \ - dbLocalOperationUtils.h \ - dbDeepRegion.h \ - dbNetlistSpiceWriter.h \ - dbNetlistWriter.h \ - dbCellVariants.h \ - dbDeepEdges.h \ - dbDeepEdgePairs.h \ - dbRegionUtils.h \ - dbEdgesUtils.h \ - dbRegionProcessors.h \ - gsiDeclDbHelpers.h \ - dbNetlistCompare.h \ - dbNetlistReader.h \ - dbNetlistSpiceReader.h \ - dbNetlistCrossReference.h \ - dbLayoutVsSchematicWriter.h \ - dbLayoutVsSchematicReader.h \ - dbLayoutVsSchematicFormatDefs.h \ - dbLayoutVsSchematic.h \ - dbNetlistObject.h \ - dbTexts.h \ - dbDeepTexts.h \ - dbAsIfFlatTexts.h \ - dbTextsDelegate.h \ - dbEmptyTexts.h \ - dbFlatTexts.h \ - dbTextsUtils.h \ - dbOriginalLayerTexts.h \ - dbNetShape.h \ - dbShapeCollection.h \ - dbShapeCollectionUtils.h + dbConverters.h \ + dbAsIfFlatRegion.h \ + dbEmptyRegion.h \ + dbFlatRegion.h \ + dbOriginalLayerRegion.h \ + dbRegionDelegate.h \ + dbEdgesDelegate.h \ + dbEmptyEdges.h \ + dbAsIfFlatEdges.h \ + dbFlatEdges.h \ + dbEdgeBoolean.h \ + dbOriginalLayerEdges.h \ + dbAsIfFlatEdgePairs.h \ + dbEmptyEdgePairs.h \ + dbFlatEdgePairs.h \ + dbOriginalLayerEdgePairs.h \ + dbEdgePairsDelegate.h \ + dbDeepShapeStore.h \ + dbHierarchyBuilder.h \ + dbLocalOperation.h \ + dbHierProcessor.h \ + dbNetlist.h \ + dbNetlistDeviceClasses.h \ + dbNetlistDeviceExtractor.h \ + dbNetlistExtractor.h \ + dbNetlistDeviceExtractorClasses.h \ + dbLayoutToNetlist.h \ + dbHierNetworkProcessor.h \ + dbNetlistUtils.h \ + dbNet.h \ + dbCircuit.h \ + dbDevice.h \ + dbDeviceClass.h \ + dbPin.h \ + dbSubCircuit.h \ + dbLayoutToNetlistReader.h \ + dbLayoutToNetlistWriter.h \ + dbLayoutToNetlistFormatDefs.h \ + dbDeviceAbstract.h \ + dbLocalOperationUtils.h \ + dbDeepRegion.h \ + dbNetlistSpiceWriter.h \ + dbNetlistWriter.h \ + dbCellVariants.h \ + dbDeepEdges.h \ + dbDeepEdgePairs.h \ + dbRegionUtils.h \ + dbEdgesUtils.h \ + dbRegionProcessors.h \ + gsiDeclDbHelpers.h \ + dbNetlistCompare.h \ + dbNetlistReader.h \ + dbNetlistSpiceReader.h \ + dbNetlistCrossReference.h \ + dbLayoutVsSchematicWriter.h \ + dbLayoutVsSchematicReader.h \ + dbLayoutVsSchematicFormatDefs.h \ + dbLayoutVsSchematic.h \ + dbNetlistObject.h \ + dbTexts.h \ + dbDeepTexts.h \ + dbAsIfFlatTexts.h \ + dbTextsDelegate.h \ + dbEmptyTexts.h \ + dbFlatTexts.h \ + dbTextsUtils.h \ + dbOriginalLayerTexts.h \ + dbNetShape.h \ + dbShapeCollection.h \ + dbShapeCollectionUtils.h !equals(HAVE_QT, "0") || !equals(HAVE_PYTHON, "0") { diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index 51f249d58..458f2eda9 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -255,92 +255,6 @@ private: bool m_insert; }; -// ----------------------------------------------------------------- -// Implementation of the LayerIterator class - -LayerIterator::LayerIterator (unsigned int layer_index, const db::Layout &layout) - : m_layer_index (layer_index), m_layout (layout) -{ - while (m_layer_index < m_layout.layers () && ! m_layout.is_valid_layer (m_layer_index)) { - ++m_layer_index; - } -} - -LayerIterator & -LayerIterator::operator++() -{ - do { - ++m_layer_index; - } while (m_layer_index < m_layout.layers () && ! m_layout.is_valid_layer (m_layer_index)); - - return *this; -} - -std::pair -LayerIterator::operator*() const -{ - return std::pair (m_layer_index, &m_layout.get_properties (m_layer_index)); -} - -// ----------------------------------------------------------------- -// Implementation of the ProxyContextInfo class - -ProxyContextInfo -ProxyContextInfo::deserialize (std::vector::const_iterator from, std::vector::const_iterator to) -{ - ProxyContextInfo info; - - for (std::vector::const_iterator i = from; i != to; ++i) { - - tl::Extractor ex (i->c_str ()); - - if (ex.test ("LIB=")) { - - info.lib_name = ex.skip (); - - } else if (ex.test ("P(")) { - - std::pair vv; - - ex.read_word_or_quoted (vv.first); - ex.test (")"); - ex.test ("="); - ex.read (vv.second); - - info.pcell_parameters.insert (vv); - - } else if (ex.test ("PCELL=")) { - - info.pcell_name = ex.skip (); - - } else if (ex.test ("CELL=")) { - - info.cell_name = ex.skip (); - - } - - } - - return info; -} - -void -ProxyContextInfo::serialize (std::vector &strings) -{ - if (! lib_name.empty ()) { - strings.push_back ("LIB=" + lib_name); - } - for (std::map ::const_iterator p = pcell_parameters.begin (); p != pcell_parameters.end (); ++p) { - strings.push_back ("P(" + tl::to_word_or_quoted_string (p->first) + ")=" + p->second.to_parsable_string ()); - } - if (! pcell_name.empty ()) { - strings.push_back ("PCELL=" + pcell_name); - } - if (! cell_name.empty ()) { - strings.push_back ("CELL=" + cell_name); - } -} - // ----------------------------------------------------------------- // Implementation of the Layout class @@ -353,9 +267,6 @@ Layout::Layout (db::Manager *manager) m_dbu (0.001), m_prop_id (0), m_properties_repository (this), - m_guiding_shape_layer (-1), - m_waste_layer (-1), - m_error_layer (-1), m_do_cleanup (false), m_editable (db::default_editable_mode ()) { @@ -371,9 +282,6 @@ Layout::Layout (bool editable, db::Manager *manager) m_dbu (0.001), m_prop_id (0), m_properties_repository (this), - m_guiding_shape_layer (-1), - m_waste_layer (-1), - m_error_layer (-1), m_do_cleanup (false), m_editable (editable) { @@ -393,9 +301,6 @@ Layout::Layout (const db::Layout &layout) m_dbu (0.001), m_prop_id (0), m_properties_repository (this), - m_guiding_shape_layer (-1), - m_waste_layer (-1), - m_error_layer (-1), m_do_cleanup (false), m_editable (layout.m_editable) { @@ -437,8 +342,7 @@ Layout::clear () m_top_down_list.clear (); - m_free_indices.clear (); - m_layer_states.clear (); + m_layers.clear (); for (std::vector::const_iterator p = m_cell_names.begin (); p != m_cell_names.end (); ++p) { if (*p) { @@ -459,10 +363,6 @@ Layout::clear () m_pcells.clear (); m_pcell_ids.clear (); - m_guiding_shape_layer = -1; - m_waste_layer = -1; - m_error_layer = -1; - m_lib_proxy_map.clear (); m_meta_info.clear (); } @@ -476,9 +376,8 @@ Layout::operator= (const Layout &d) clear (); - m_guiding_shape_layer = d.m_guiding_shape_layer; - m_waste_layer = d.m_waste_layer; - m_error_layer = d.m_error_layer; + m_layers = d.m_layers; + m_editable = d.m_editable; m_pcell_ids = d.m_pcell_ids; @@ -504,9 +403,6 @@ Layout::operator= (const Layout &d) } m_properties_repository = d.m_properties_repository; // because the cell assign operator does not map property ID's .. - m_free_indices = d.m_free_indices; - m_layer_states = d.m_layer_states; - m_layer_props = d.m_layer_props; m_top_down_list = d.m_top_down_list; m_top_cells = d.m_top_cells; @@ -720,14 +616,13 @@ Layout::mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat stat->add (typeid (*this), (void *) this, sizeof (*this), sizeof (*this), parent, purpose, cat); } + m_layers.mem_stat (stat, purpose, cat, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_cell_ptrs, true, (void *) this); db::mem_stat (stat, purpose, cat, m_free_cell_indices, true, (void *) this); db::mem_stat (stat, purpose, cat, m_top_down_list, true, (void *) this); - db::mem_stat (stat, purpose, cat, m_free_indices, true, (void *) this); - db::mem_stat (stat, purpose, cat, m_layer_states, true, (void *) this); db::mem_stat (stat, purpose, cat, m_cell_names, true, (void *) this); db::mem_stat (stat, purpose, cat, m_cell_map, true, (void *) this); - db::mem_stat (stat, purpose, cat, m_layer_props, true, (void *) this); db::mem_stat (stat, purpose, cat, m_pcells, true, (void *) this); db::mem_stat (stat, purpose, cat, m_pcell_ids, true, (void *) this); db::mem_stat (stat, purpose, cat, m_lib_proxy_map, true, (void *) this); @@ -1839,8 +1734,8 @@ Layout::meta_info_value (const std::string &name) const void Layout::swap_layers (unsigned int a, unsigned int b) { - tl_assert (a < layers () && m_layer_states [a] != Free); - tl_assert (b < layers () && m_layer_states [b] != Free); + tl_assert (m_layers.layer_state (a) != LayoutLayers::Free); + tl_assert (m_layers.layer_state (b) != LayoutLayers::Free); // clear the shapes for (iterator c = begin (); c != end (); ++c) { @@ -1851,8 +1746,8 @@ Layout::swap_layers (unsigned int a, unsigned int b) void Layout::move_layer (unsigned int src, unsigned int dest) { - tl_assert (src < layers () && m_layer_states [src] != Free); - tl_assert (dest < layers () && m_layer_states [dest] != Free); + tl_assert (m_layers.layer_state (src) != LayoutLayers::Free); + tl_assert (m_layers.layer_state (dest) != LayoutLayers::Free); // move the shapes for (iterator c = begin (); c != end (); ++c) { @@ -1863,8 +1758,8 @@ Layout::move_layer (unsigned int src, unsigned int dest) void Layout::copy_layer (unsigned int src, unsigned int dest) { - tl_assert (src < layers () && m_layer_states [src] != Free); - tl_assert (dest < layers () && m_layer_states [dest] != Free); + tl_assert (m_layers.layer_state (src) != LayoutLayers::Free); + tl_assert (m_layers.layer_state (dest) != LayoutLayers::Free); // copy the shapes for (iterator c = begin (); c != end (); ++c) { @@ -1875,7 +1770,7 @@ Layout::copy_layer (unsigned int src, unsigned int dest) void Layout::clear_layer (unsigned int n) { - tl_assert (n < layers () && m_layer_states [n] != Free); + tl_assert (m_layers.layer_state (n) != LayoutLayers::Free); // clear the shapes for (iterator c = begin (); c != end (); ++c) { @@ -1886,14 +1781,13 @@ Layout::clear_layer (unsigned int n) void Layout::delete_layer (unsigned int n) { - tl_assert (n < layers () && m_layer_states [n] != Free); + tl_assert (m_layers.layer_state (n) != LayoutLayers::Free); if (manager () && manager ()->transacting ()) { - manager ()->queue (this, new InsertRemoveLayerOp (n, m_layer_props [n], false /*delete*/)); + manager ()->queue (this, new InsertRemoveLayerOp (n, m_layers.get_properties (n), false /*delete*/)); } - m_free_indices.push_back (n); - m_layer_states [n] = Free; + m_layers.delete_layer (n); // clear the shapes for (iterator c = begin (); c != end (); ++c) { @@ -1906,11 +1800,7 @@ Layout::delete_layer (unsigned int n) unsigned int Layout::insert_layer (const LayerProperties &props) { - unsigned int i = do_insert_layer (); - while (m_layer_props.size () <= i) { - m_layer_props.push_back (LayerProperties ()); - } - m_layer_props [i] = props; + unsigned int i = m_layers.insert_layer (props); if (manager () && manager ()->transacting ()) { manager ()->queue (this, new InsertRemoveLayerOp (i, props, true/*insert*/)); @@ -1924,11 +1814,7 @@ Layout::insert_layer (const LayerProperties &props) void Layout::insert_layer (unsigned int index, const LayerProperties &props) { - do_insert_layer (index); - while (m_layer_props.size () <= index) { - m_layer_props.push_back (LayerProperties ()); - } - m_layer_props [index] = props; + m_layers.insert_layer (index, props); if (manager () && manager ()->transacting ()) { manager ()->queue (this, new InsertRemoveLayerOp (index, props, true/*insert*/)); @@ -1940,68 +1826,13 @@ Layout::insert_layer (unsigned int index, const LayerProperties &props) unsigned int Layout::get_layer (const db::LayerProperties &lp) { - if (lp.is_null ()) { - // for a null layer info always create a layer - return insert_layer (); - } else { - // if we have a layer with the requested properties already, return this. - for (db::Layout::layer_iterator li = begin_layers (); li != end_layers (); ++li) { - if ((*li).second->log_equal (lp)) { - return (*li).first; - } - } - // otherwise create a new layer - return insert_layer (lp); - } -} - -unsigned int -Layout::error_layer () const -{ - if (m_error_layer < 0) { - // create the waste layer (since that layer is cached we can do - // this in a "const" fashion. - db::Layout *self = const_cast (this); - self->m_error_layer = (int) self->insert_special_layer (db::LayerProperties ("WASTE")); - } - - return (unsigned int) m_error_layer; -} - -unsigned int -Layout::waste_layer () const -{ - if (m_waste_layer < 0) { - // create the waste layer (since that layer is cached we can do - // this in a "const" fashion. - db::Layout *self = const_cast (this); - self->m_waste_layer = (int) self->insert_special_layer (db::LayerProperties ("WASTE")); - } - - return (unsigned int) m_waste_layer; -} - -unsigned int -Layout::guiding_shape_layer () const -{ - if (m_guiding_shape_layer < 0) { - // create the guiding shape layer (since that layer is cached we can do - // this in a "const" fashion. - db::Layout *self = const_cast (this); - self->m_guiding_shape_layer = (int) self->insert_special_layer (db::LayerProperties ("GUIDING_SHAPES")); - } - - return (unsigned int) m_guiding_shape_layer; + return m_layers.get_layer (lp); } unsigned int Layout::insert_special_layer (const LayerProperties &props) { - unsigned int i = do_insert_layer (true /*special*/); - while (m_layer_props.size () <= i) { - m_layer_props.push_back (LayerProperties ()); - } - m_layer_props [i] = props; + unsigned int i = m_layers.insert_special_layer (props); if (manager () && manager ()->transacting ()) { manager ()->queue (this, new InsertRemoveLayerOp (i, props, true/*insert*/)); @@ -2013,13 +1844,13 @@ Layout::insert_special_layer (const LayerProperties &props) void Layout::set_properties (unsigned int i, const LayerProperties &props) { - if (m_layer_props [i] != props) { + if (m_layers.get_properties (i) != props) { if (manager () && manager ()->transacting ()) { - manager ()->queue (this, new SetLayerPropertiesOp (i, props, m_layer_props [i])); + manager ()->queue (this, new SetLayerPropertiesOp (i, props, m_layers.get_properties (i))); } - m_layer_props [i] = props; + m_layers.set_properties (i, props); layer_properties_changed (); @@ -2029,60 +1860,13 @@ Layout::set_properties (unsigned int i, const LayerProperties &props) void Layout::insert_special_layer (unsigned int index, const LayerProperties &props) { - do_insert_layer (index, true /*special*/); - while (m_layer_props.size () <= index) { - m_layer_props.push_back (LayerProperties ()); - } - m_layer_props [index] = props; + m_layers.insert_special_layer (index, props); if (manager () && manager ()->transacting ()) { manager ()->queue (this, new InsertRemoveLayerOp (index, props, true/*insert*/)); } } -unsigned int -Layout::do_insert_layer (bool special) -{ - if (m_free_indices.size () > 0) { - unsigned int i = m_free_indices.back (); - m_free_indices.pop_back (); - m_layer_states [i] = special ? Special : Normal; - return i; - } else { - m_layer_states.push_back (special ? Special : Normal); - unsigned int i = layers () - 1; - return i; - } -} - -void -Layout::do_insert_layer (unsigned int index, bool special) -{ - if (index >= layers ()) { - - // add layer to the end of the list. - // add as may freelist entries as required. - while (index > layers ()) { - m_free_indices.push_back (layers ()); - m_layer_states.push_back (Free); - } - m_layer_states.push_back (special ? Special : Normal); - - } else { - - tl_assert (m_layer_states [index] == Free); - m_layer_states [index] = special ? Special : Normal; - - } - -} - -void -Layout::reserve_layers (unsigned int n) -{ - m_layer_states.reserve (n); -} - static const std::vector &gauge_parameters (const std::vector &p, const db::PCellDeclaration *pcell_decl, std::vector &buffer) { const std::vector &pcp = pcell_decl->parameter_declarations (); @@ -2354,8 +2138,8 @@ Layout::convert_cell_to_static (db::cell_index_type ci) new_cell.set_cell_index (ret_ci); // remove guiding shapes. - if (m_guiding_shape_layer >= 0) { - new_cell.shapes (m_guiding_shape_layer).clear (); + if (m_layers.guiding_shape_layer_maybe () >= 0) { + new_cell.shapes (m_layers.guiding_shape_layer_maybe ()).clear (); } } diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h index 79337f3b0..99ab11d5e 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -32,6 +32,7 @@ #include "dbText.h" #include "dbCell.h" #include "dbLayoutStateModel.h" +#include "dbLayoutLayers.h" #include "dbLayerProperties.h" #include "dbMetaInfo.h" #include "dbCellInst.h" @@ -393,50 +394,6 @@ private: cell_type *mp_first, *mp_last; }; -/** - * @brief A layer iterator (for valid layers) - * - * The layer iterator delivers layer indices and layer properties of layer layers. - */ -class DB_PUBLIC LayerIterator -{ -public: - /** - * @brief Constructor - */ - LayerIterator (unsigned int layer_index, const db::Layout &layout); - - /** - * @brief Increment operator - */ - LayerIterator &operator++(); - - /** - * @brief Equality - */ - bool operator== (const LayerIterator &i) - { - return i.m_layer_index == m_layer_index; - } - - /** - * @brief Inequality - */ - bool operator!= (const LayerIterator &i) - { - return i.m_layer_index != m_layer_index; - } - - /** - * @brief Access operator - */ - std::pair operator*() const; - -private: - unsigned int m_layer_index; - const db::Layout &m_layout; -}; - /** * @brief An interface that is used to map layer between libraries and PCells and the layout */ @@ -1426,7 +1383,7 @@ public: */ bool is_valid_layer (unsigned int n) const { - return (n < layers () && m_layer_states [n] == Normal); + return m_layers.layer_state (n) == db::LayoutLayers::Normal; } /** @@ -1434,7 +1391,7 @@ public: */ bool is_free_layer (unsigned int n) const { - return (n >= layers () || m_layer_states [n] == Free); + return m_layers.layer_state (n) == db::LayoutLayers::Free; } /** @@ -1442,7 +1399,7 @@ public: */ bool is_special_layer (unsigned int n) const { - return (n < layers () && m_layer_states [n] == Special); + return m_layers.layer_state (n) == db::LayoutLayers::Special; } /** @@ -1454,7 +1411,7 @@ public: */ unsigned int layers () const { - return (cell_index_type) m_layer_states.size (); + return m_layers.layers (); } /** @@ -1462,7 +1419,7 @@ public: */ layer_iterator begin_layers () const { - return layer_iterator (0, *this); + return m_layers.begin_layers (); } /** @@ -1470,13 +1427,16 @@ public: */ layer_iterator end_layers () const { - return layer_iterator (layers (), *this); + return m_layers.end_layers (); } /** * @brief Reserve space for n layers */ - void reserve_layers (unsigned int n); + void reserve_layers (unsigned int n) + { + m_layers.reserve_layers (n); + } /** * @brief begin iterator of the unsorted cell list @@ -1705,21 +1665,30 @@ public: * * The guiding shape layer is used to store the guiding shapes of PCells */ - unsigned int guiding_shape_layer () const; + unsigned int guiding_shape_layer () const + { + return m_layers.guiding_shape_layer (); + } /** * @brief Gets the waste layer * * The waste layer is used to store shapes that should not be visible and can be cleared at any time. */ - unsigned int waste_layer () const; + unsigned int waste_layer () const + { + return m_layers.waste_layer (); + } /** * @brief Gets the error layer * * The error layer is used to display error messages. */ - unsigned int error_layer () const; + unsigned int error_layer () const + { + return m_layers.error_layer (); + } /** * @brief Set the properties for a specified layer @@ -1731,7 +1700,7 @@ public: */ const LayerProperties &get_properties (unsigned int i) const { - return m_layer_props [i]; + return m_layers.get_properties (i); } /** @@ -1877,8 +1846,6 @@ protected: virtual void do_update (); private: - enum LayerState { Normal, Free, Special }; - db::Library *mp_library; cell_list m_cells; size_t m_cells_size; @@ -1887,11 +1854,9 @@ private: mutable unsigned int m_invalid; cell_index_vector m_top_down_list; size_t m_top_cells; - std::vector m_free_indices; - std::vector m_layer_states; + LayoutLayers m_layers; std::vector m_cell_names; cell_map_type m_cell_map; - std::vector m_layer_props; double m_dbu; db::properties_id_type m_prop_id; StringRepository m_string_repository; @@ -1901,9 +1866,6 @@ private: std::vector m_pcells; pcell_name_map m_pcell_ids; lib_proxy_map m_lib_proxy_map; - int m_guiding_shape_layer; - int m_waste_layer; - int m_error_layer; bool m_do_cleanup; bool m_editable; meta_info m_meta_info; @@ -1937,21 +1899,6 @@ private: */ cell_index_type allocate_new_cell (); - /** - * @brief Insert a new layer - * - * This creates a new index number, either from the free list - * of by creating a new one. - */ - unsigned int do_insert_layer (bool special = false); - - /** - * @brief Insert a new layer at the given index - * - * If the index is unused, create a new layer there. - */ - void do_insert_layer (unsigned int index, bool special = false); - /** * @brief Implementation of prune_cell and prune_subcells */ diff --git a/src/db/db/dbLayoutLayers.cc b/src/db/db/dbLayoutLayers.cc new file mode 100644 index 000000000..e6f8eb251 --- /dev/null +++ b/src/db/db/dbLayoutLayers.cc @@ -0,0 +1,318 @@ + +/* + + KLayoutLayers LayoutLayers Viewer + Copyright (C) 2006-2022 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#include "dbLayoutLayers.h" + +namespace db +{ + +// ----------------------------------------------------------------- +// Implementation of the LayerIterator class + +LayerIterator::LayerIterator (unsigned int layer_index, const db::LayoutLayers &layout) + : m_layer_index (layer_index), m_layout (layout) +{ + while (m_layer_index < m_layout.layers () && m_layout.layer_state (m_layer_index) != db::LayoutLayers::Normal) { + ++m_layer_index; + } +} + +LayerIterator & +LayerIterator::operator++() +{ + do { + ++m_layer_index; + } while (m_layer_index < m_layout.layers () && m_layout.layer_state (m_layer_index) != db::LayoutLayers::Normal); + + return *this; +} + +std::pair +LayerIterator::operator*() const +{ + return std::pair (m_layer_index, &m_layout.get_properties (m_layer_index)); +} + +// ----------------------------------------------------------------- +// Implementation of the LayoutLayers class + +LayoutLayers::LayoutLayers () + : m_guiding_shape_layer (-1), + m_waste_layer (-1), + m_error_layer (-1) +{ + // .. nothing yet .. +} + +LayoutLayers::LayoutLayers (const db::LayoutLayers &layout) + : m_guiding_shape_layer (-1), + m_waste_layer (-1), + m_error_layer (-1) +{ + *this = layout; +} + +LayoutLayers::~LayoutLayers () +{ + // .. nothing yet .. +} + +void +LayoutLayers::clear () +{ + m_free_indices.clear (); + m_layer_states.clear (); + m_layer_props.clear (); + m_layers_by_props.clear (); + + m_guiding_shape_layer = -1; + m_waste_layer = -1; + m_error_layer = -1; +} + +LayoutLayers & +LayoutLayers::operator= (const LayoutLayers &d) +{ + if (&d != this) { + + m_guiding_shape_layer = d.m_guiding_shape_layer; + m_waste_layer = d.m_waste_layer; + m_error_layer = d.m_error_layer; + + m_free_indices = d.m_free_indices; + m_layer_states = d.m_layer_states; + m_layer_props = d.m_layer_props; + m_layers_by_props = d.m_layers_by_props; + + } + return *this; +} + +void +LayoutLayers::mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const +{ + if (!no_self) { + stat->add (typeid (*this), (void *) this, sizeof (*this), sizeof (*this), parent, purpose, cat); + } + + db::mem_stat (stat, purpose, cat, m_free_indices, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_layer_states, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_layer_props, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_layers_by_props, true, (void *) this); +} + +void +LayoutLayers::delete_layer (unsigned int n) +{ + const db::LayerProperties &lp = m_layer_props [n]; + if (! lp.is_null ()) { + for (auto i = m_layers_by_props.find (lp); i != m_layers_by_props.end () && i->first.log_equal (lp); ++i) { + if (i->second == n) { + m_layers_by_props.erase (i); + break; + } + } + } + + m_free_indices.push_back (n); + m_layer_props [n] = db::LayerProperties (); + m_layer_states [n] = Free; +} + +unsigned int +LayoutLayers::insert_layer (const LayerProperties &props) +{ + unsigned int i = do_insert_layer (); + set_properties (i, props); + return i; +} + +void +LayoutLayers::insert_layer (unsigned int index, const LayerProperties &props) +{ + if (layer_state (index) == Normal) { + delete_layer (index); + } + do_insert_layer (index); + set_properties (index, props); +} + +unsigned int +LayoutLayers::get_layer (const db::LayerProperties &lp) +{ + if (lp.is_null ()) { + // for a null layer info always create a layer + return insert_layer (); + } else { + auto i = m_layers_by_props.find (lp); + if (i != m_layers_by_props.end () && i->first.log_equal (lp)) { + return i->second; + } else { + // otherwise create a new layer + return insert_layer (lp); + } + } +} + +int +LayoutLayers::get_layer_maybe (const db::LayerProperties &lp) +{ + if (lp.is_null ()) { + return -1; + } else { + auto i = m_layers_by_props.find (lp); + if (i != m_layers_by_props.end () && i->first.log_equal (lp)) { + return int (i->second); + } else { + return -1; + } + } +} + +unsigned int +LayoutLayers::error_layer () const +{ + if (m_error_layer < 0) { + // create the waste layer (since that layer is cached we can do + // this in a "const" fashion. + db::LayoutLayers *self = const_cast (this); + self->m_error_layer = (int) self->insert_special_layer (db::LayerProperties ("WASTE")); + } + + return (unsigned int) m_error_layer; +} + +unsigned int +LayoutLayers::waste_layer () const +{ + if (m_waste_layer < 0) { + // create the waste layer (since that layer is cached we can do + // this in a "const" fashion. + db::LayoutLayers *self = const_cast (this); + self->m_waste_layer = (int) self->insert_special_layer (db::LayerProperties ("WASTE")); + } + + return (unsigned int) m_waste_layer; +} + +unsigned int +LayoutLayers::guiding_shape_layer () const +{ + if (m_guiding_shape_layer < 0) { + // create the guiding shape layer (since that layer is cached we can do + // this in a "const" fashion. + db::LayoutLayers *self = const_cast (this); + self->m_guiding_shape_layer = (int) self->insert_special_layer (db::LayerProperties ("GUIDING_SHAPES")); + } + + return (unsigned int) m_guiding_shape_layer; +} + +unsigned int +LayoutLayers::insert_special_layer (const LayerProperties &props) +{ + unsigned int i = do_insert_layer (true /*special*/); + set_properties (i, props); + return i; +} + +void +LayoutLayers::insert_special_layer (unsigned int index, const LayerProperties &props) +{ + if (layer_state (index) == Normal) { + delete_layer (index); + } + + do_insert_layer (index, true /*special*/); + set_properties (index, props); +} + +unsigned int +LayoutLayers::do_insert_layer (bool special) +{ + if (m_free_indices.size () > 0) { + unsigned int i = m_free_indices.back (); + m_free_indices.pop_back (); + m_layer_states [i] = special ? Special : Normal; + return i; + } else { + m_layer_states.push_back (special ? Special : Normal); + unsigned int i = layers () - 1; + return i; + } +} + +void +LayoutLayers::do_insert_layer (unsigned int index, bool special) +{ + if (index >= layers ()) { + + // add layer to the end of the list. + // add as may freelist entries as required. + while (index > layers ()) { + m_free_indices.push_back (layers ()); + m_layer_states.push_back (Free); + } + m_layer_states.push_back (special ? Special : Normal); + + } else { + + tl_assert (m_layer_states [index] == Free); + m_layer_states [index] = special ? Special : Normal; + + } + +} + +void +LayoutLayers::reserve_layers (unsigned int n) +{ + m_layer_states.reserve (n); +} + +void +LayoutLayers::set_properties (unsigned int n, const LayerProperties &props) +{ + while (m_layer_props.size () <= n) { + m_layer_props.push_back (LayerProperties ()); + } + + const db::LayerProperties &lp = m_layer_props [n]; + if (! lp.is_null ()) { + for (auto i = m_layers_by_props.find (lp); i != m_layers_by_props.end () && i->first.log_equal (lp); ++i) { + if (i->second == n) { + m_layers_by_props.erase (i); + break; + } + } + } + + m_layer_props [n] = props; + + if (! props.is_null ()) { + m_layers_by_props.insert (std::make_pair (props, n)); + } +} + +} + diff --git a/src/db/db/dbLayoutLayers.h b/src/db/db/dbLayoutLayers.h new file mode 100644 index 000000000..fb0046144 --- /dev/null +++ b/src/db/db/dbLayoutLayers.h @@ -0,0 +1,282 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2022 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#ifndef HDR_dbLayoutLayers +#define HDR_dbLayoutLayers + +#include "dbCommon.h" + +#include "dbLayerProperties.h" +#include "dbMemStatistics.h" + +#include +#include + +namespace db +{ + +class MemStatistics; +class LayoutLayers; + +/** + * @brief A layer iterator (for valid layers) + * + * The layer iterator delivers layer indices and layer properties of layer layers. + */ +class DB_PUBLIC LayerIterator +{ +public: + /** + * @brief Constructor + */ + LayerIterator (unsigned int layer_index, const db::LayoutLayers &layout); + + /** + * @brief Increment operator + */ + LayerIterator &operator++(); + + /** + * @brief Equality + */ + bool operator== (const LayerIterator &i) + { + return i.m_layer_index == m_layer_index; + } + + /** + * @brief Inequality + */ + bool operator!= (const LayerIterator &i) + { + return i.m_layer_index != m_layer_index; + } + + /** + * @brief Access operator + */ + std::pair operator*() const; + +private: + unsigned int m_layer_index; + const db::LayoutLayers &m_layout; +}; + +/** + * @brief The layoutLayers object + * + * This object wraps the layer list and manages layer properties, + * layer states and the free layer list. + */ + +class DB_PUBLIC LayoutLayers +{ +public: + typedef LayerIterator layer_iterator; + enum LayerState { Normal, Free, Special }; + + /** + * @brief Standard constructor + */ + LayoutLayers (); + + /** + * @brief The copy ctor + */ + LayoutLayers (const LayoutLayers &d); + + /** + * @brief Destructor + */ + ~LayoutLayers (); + + /** + * @brief Assignment operator + */ + LayoutLayers &operator= (const LayoutLayers &d); + + /** + * @brief Clears the layout layers + */ + void clear (); + + /** + * @brief Deletes a layer + */ + void delete_layer (unsigned int n); + + /** + * @brief Gets the layer's state + */ + LayerState layer_state (unsigned int l) const + { + return l < (unsigned int) m_layer_states.size () ? m_layer_states [l] : Free; + } + + /** + * @brief Gets the number of layers defined so far + * + * TODO: the list of 0 to nlayers-1 also contains the free layers - + * we should get a vector containing the layers that are actually + * allocated. + */ + unsigned int layers () const + { + return (unsigned int) m_layer_states.size (); + } + + /** + * @brief The iterator of valid layers: begin + */ + layer_iterator begin_layers () const + { + return layer_iterator (0, *this); + } + + /** + * @brief The iterator of valid layers: end + */ + layer_iterator end_layers () const + { + return layer_iterator (layers (), *this); + } + + /** + * @brief Reserve space for n layers + */ + void reserve_layers (unsigned int n); + + /** + * @brief Inserts a new layer with the given properties + */ + unsigned int insert_layer (const LayerProperties &props = LayerProperties ()); + + /** + * @brief Inserts a new layer with the given properties at the given index + */ + void insert_layer (unsigned int index, const LayerProperties &props = LayerProperties ()); + + /** + * @brief Gets or creates a layer with the given properties + * + * If there already is a layer matching the given properties, it's index will be + * returned. Otherwise a new layer with these properties is created. + */ + unsigned int get_layer (const db::LayerProperties &props); + + /** + * @brief Gets or creates a layer with the given properties or -1 if such a layer does not exist. + */ + int get_layer_maybe (const db::LayerProperties &props); + + /** + * @brief Insert a new special layer with the given properties + * + * A special layers is used for example to represent rulers. + */ + unsigned int insert_special_layer (const LayerProperties &props = LayerProperties ()); + + /** + * @brief Insert a new layer with the given properties at the given index + * + * A special layers is used for example to represent rulers. + */ + void insert_special_layer (unsigned int index, const LayerProperties &props = LayerProperties ()); + + /** + * @brief Gets the guiding shape layer or -1 if none is set yet. + */ + int guiding_shape_layer_maybe () const + { + return m_guiding_shape_layer; + } + + /** + * @brief Gets the guiding shape layer + * + * The guiding shape layer is used to store the guiding shapes of PCells + */ + unsigned int guiding_shape_layer () const; + + /** + * @brief Gets the waste layer + * + * The waste layer is used to store shapes that should not be visible and can be cleared at any time. + */ + unsigned int waste_layer () const; + + /** + * @brief Gets the error layer + * + * The error layer is used to display error messages. + */ + unsigned int error_layer () const; + + /** + * @brief Sets the properties for a specified layer + */ + void set_properties (unsigned int i, const LayerProperties &props); + + /** + * @brief Gets the properties for a specified layer + */ + const LayerProperties &get_properties (unsigned int i) const + { + return m_layer_props [i]; + } + + /** + * @brief Collects memory statistics + */ + void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self = false, void *parent = 0) const; + +private: + std::vector m_free_indices; + std::vector m_layer_states; + std::vector m_layer_props; + std::multimap m_layers_by_props; + int m_guiding_shape_layer; + int m_waste_layer; + int m_error_layer; + + /** + * @brief Insert a new layer + * + * This creates a new index number, either from the free list + * of by creating a new one. + */ + unsigned int do_insert_layer (bool special = false); + + /** + * @brief Insert a new layer at the given index + * + * If the index is unused, create a new layer there. + */ + void do_insert_layer (unsigned int index, bool special = false); +}; + +} + +#endif + + diff --git a/src/laybasic/laybasic/layLayerProperties.cc b/src/laybasic/laybasic/layLayerProperties.cc index 7ee412e6c..61dc43359 100644 --- a/src/laybasic/laybasic/layLayerProperties.cc +++ b/src/laybasic/laybasic/layLayerProperties.cc @@ -629,11 +629,7 @@ LayerProperties::do_realize (const LayoutViewBase *view) const // lookup the layer with the given name/layer/datatype if (m_layer_index < 0 && ! m_source_real.is_wildcard_layer ()) { - for (unsigned int i = 0; i < cv->layout ().layers () && m_layer_index < 0; ++i) { - if (cv->layout ().is_valid_layer (i) && m_source_real.match (cv->layout ().get_properties (i))) { - m_layer_index = int (i); - } - } + m_layer_index = cv->layout ().get_layer_maybe (m_source_real.layer_props ()); } } From b1e78efcaadc9edec14007ca2fc60482e4f8c9a5 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 13 Dec 2022 23:58:56 +0100 Subject: [PATCH 08/17] WIP: trying to enhance layout layer lookup performance. --- src/db/db/dbLayout.cc | 65 ++++++++++++++++++++++++++++++++++---- src/db/db/dbLayout.h | 13 +++++++- src/db/db/dbLayoutLayers.h | 2 +- 3 files changed, 72 insertions(+), 8 deletions(-) diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index 458f2eda9..b181bd2e0 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -255,6 +255,65 @@ private: bool m_insert; }; +// ----------------------------------------------------------------- +// Implementation of the ProxyContextInfo class + +ProxyContextInfo +ProxyContextInfo::deserialize (std::vector::const_iterator from, std::vector::const_iterator to) +{ + ProxyContextInfo info; + + for (std::vector::const_iterator i = from; i != to; ++i) { + + tl::Extractor ex (i->c_str ()); + + if (ex.test ("LIB=")) { + + info.lib_name = ex.skip (); + + } else if (ex.test ("P(")) { + + std::pair vv; + + ex.read_word_or_quoted (vv.first); + ex.test (")"); + ex.test ("="); + ex.read (vv.second); + + info.pcell_parameters.insert (vv); + + } else if (ex.test ("PCELL=")) { + + info.pcell_name = ex.skip (); + + } else if (ex.test ("CELL=")) { + + info.cell_name = ex.skip (); + + } + + } + + return info; +} + +void +ProxyContextInfo::serialize (std::vector &strings) +{ + if (! lib_name.empty ()) { + strings.push_back ("LIB=" + lib_name); + } + for (std::map ::const_iterator p = pcell_parameters.begin (); p != pcell_parameters.end (); ++p) { + strings.push_back ("P(" + tl::to_word_or_quoted_string (p->first) + ")=" + p->second.to_parsable_string ()); + } + if (! pcell_name.empty ()) { + strings.push_back ("PCELL=" + pcell_name); + } + if (! cell_name.empty ()) { + strings.push_back ("CELL=" + cell_name); + } +} + // ----------------------------------------------------------------- // Implementation of the Layout class @@ -1823,12 +1882,6 @@ Layout::insert_layer (unsigned int index, const LayerProperties &props) layer_properties_changed (); } -unsigned int -Layout::get_layer (const db::LayerProperties &lp) -{ - return m_layers.get_layer (lp); -} - unsigned int Layout::insert_special_layer (const LayerProperties &props) { diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h index 99ab11d5e..7b7cc1278 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -1644,7 +1644,18 @@ public: * If there already is a layer matching the given properties, it's index will be * returned. Otherwise a new layer with these properties is created. */ - unsigned int get_layer (const db::LayerProperties &props); + unsigned int get_layer (const db::LayerProperties &props) + { + return m_layers.get_layer (props); + } + + /** + * @brief Gets the layer with the given properties or -1 if such a layer does not exist + */ + int get_layer_maybe (const db::LayerProperties &props) + { + return m_layers.get_layer_maybe (props); + } /** * @brief Insert a new special layer with the given properties diff --git a/src/db/db/dbLayoutLayers.h b/src/db/db/dbLayoutLayers.h index fb0046144..fbe0988bf 100644 --- a/src/db/db/dbLayoutLayers.h +++ b/src/db/db/dbLayoutLayers.h @@ -185,7 +185,7 @@ public: unsigned int get_layer (const db::LayerProperties &props); /** - * @brief Gets or creates a layer with the given properties or -1 if such a layer does not exist. + * @brief Gets the layer with the given properties or -1 if such a layer does not exist. */ int get_layer_maybe (const db::LayerProperties &props); From 884203149ad17a2f443eacb521219544c4d1ba32 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 17 Dec 2022 20:33:50 +0100 Subject: [PATCH 09/17] Added tests for recent changes --- src/db/unit_tests/dbLayoutTests.cc | 67 ++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/src/db/unit_tests/dbLayoutTests.cc b/src/db/unit_tests/dbLayoutTests.cc index f36e3125a..1d4829e23 100644 --- a/src/db/unit_tests/dbLayoutTests.cc +++ b/src/db/unit_tests/dbLayoutTests.cc @@ -664,3 +664,70 @@ TEST(6) EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {CIRCLE}\nboundary 1 0 {-2071 -5000} {-5000 -2071} {-5000 2071} {-2071 5000} {2071 5000} {5000 2071} {5000 -2071} {2071 -5000} {-2071 -5000}\nend_cell\nend_lib\n"); } } + +TEST(7_LayerProperties) +{ + db::Manager m; + db::Layout l (&m); + + EXPECT_EQ (l.is_valid_layer (0), false); + EXPECT_EQ (l.guiding_shape_layer (), 0); + EXPECT_EQ (l.is_special_layer (0), true); + EXPECT_EQ (int (l.layers ()), 1); + + EXPECT_EQ (l.get_layer_maybe (db::LayerProperties (1, 0)), -1); + unsigned int l1 = l.get_layer (db::LayerProperties (1, 0)); + EXPECT_EQ (1, int (l1)); + EXPECT_EQ (l.get_layer_maybe (db::LayerProperties (1, 0)), int (l1)); + EXPECT_EQ (l.get_layer_maybe (db::LayerProperties (2, 0)), -1); + EXPECT_EQ (int (l.layers ()), 2); + + unsigned int l2 = l.get_layer (db::LayerProperties (2, 0)); + EXPECT_EQ (2, int (l2)); + EXPECT_EQ (l.get_layer_maybe (db::LayerProperties (1, 0)), int (l1)); + EXPECT_EQ (l.get_layer_maybe (db::LayerProperties (2, 0)), int (l2)); + EXPECT_EQ (l.get_layer_maybe (db::LayerProperties (3, 0)), -1); + EXPECT_EQ (int (l.layers ()), 3); + + l.insert_layer (l2, db::LayerProperties (3, 0)); + EXPECT_EQ (int (l.layers ()), 3); + EXPECT_EQ (l.get_layer_maybe (db::LayerProperties (1, 0)), int (l1)); + EXPECT_EQ (l.get_layer_maybe (db::LayerProperties (2, 0)), -1); + EXPECT_EQ (l.get_layer_maybe (db::LayerProperties (3, 0)), int (l2)); + EXPECT_EQ (l.get_properties (l2).to_string (), "3/0"); + + l.transaction (std::string ()); + l.delete_layer (l2); + l.commit (); + + EXPECT_EQ (l.get_layer_maybe (db::LayerProperties (1, 0)), int (l1)); + EXPECT_EQ (l.get_layer_maybe (db::LayerProperties (2, 0)), -1); + EXPECT_EQ (l.get_layer_maybe (db::LayerProperties (3, 0)), -1); + + m.undo (); + EXPECT_EQ (int (l.layers ()), 3); + EXPECT_EQ (l.get_layer_maybe (db::LayerProperties (1, 0)), int (l1)); + EXPECT_EQ (l.get_layer_maybe (db::LayerProperties (2, 0)), -1); + EXPECT_EQ (l.get_layer_maybe (db::LayerProperties (3, 0)), int (l2)); + + auto li = l.begin_layers (); + EXPECT_EQ (li != l.end_layers (), true); + EXPECT_EQ ((*li).second->to_string (), "1/0"); + ++li; + EXPECT_EQ (li != l.end_layers (), true); + EXPECT_EQ ((*li).second->to_string (), "3/0"); + ++li; + EXPECT_EQ (li == l.end_layers (), true); + + l.set_properties (l2, db::LayerProperties (10, 0)); + EXPECT_EQ (int (l.layers ()), 3); + EXPECT_EQ (l.get_layer_maybe (db::LayerProperties (1, 0)), int (l1)); + EXPECT_EQ (l.get_layer_maybe (db::LayerProperties (2, 0)), -1); + EXPECT_EQ (l.get_layer_maybe (db::LayerProperties (3, 0)), -1); + EXPECT_EQ (l.get_layer_maybe (db::LayerProperties (10, 0)), int (l2)); + + l.clear (); + EXPECT_EQ (int (l.layers ()), 0); + EXPECT_EQ (l.get_layer_maybe (db::LayerProperties (1, 0)), -1); + EXPECT_EQ (l.get_layer_maybe (db::LayerProperties (2, 0)), -1); +} From 24b8526361fedeb1ab1d2b0959b779d10d34e535 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 17 Dec 2022 20:34:22 +0100 Subject: [PATCH 10/17] Attempting to speed up layer list for many layers --- src/laybasic/laybasic/layLayoutViewBase.cc | 32 ++++++++++++++-------- src/laybasic/laybasic/layLayoutViewBase.h | 3 ++ src/layui/layui/layLayerControlPanel.cc | 3 +- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/laybasic/laybasic/layLayoutViewBase.cc b/src/laybasic/laybasic/layLayoutViewBase.cc index b2e3a805d..a879417d7 100644 --- a/src/laybasic/laybasic/layLayoutViewBase.cc +++ b/src/laybasic/laybasic/layLayoutViewBase.cc @@ -239,6 +239,7 @@ const double animation_interval = 0.5; LayoutViewBase::LayoutViewBase (db::Manager *manager, bool editable, lay::Plugin *plugin_parent, unsigned int options) : lay::Dispatcher (plugin_parent, false /*not standalone*/), mp_ui (0), + dm_redraw (this, &LayoutViewBase::redraw), m_editable (editable), m_options (options), m_annotation_shapes (manager) @@ -252,6 +253,7 @@ LayoutViewBase::LayoutViewBase (db::Manager *manager, bool editable, lay::Plugin LayoutViewBase::LayoutViewBase (lay::LayoutView *ui, db::Manager *manager, bool editable, lay::Plugin *plugin_parent, unsigned int options) : lay::Dispatcher (plugin_parent, false /*not standalone*/), mp_ui (ui), + dm_redraw (this, &LayoutViewBase::redraw), m_editable (editable), m_options (options), m_annotation_shapes (manager) @@ -265,6 +267,7 @@ LayoutViewBase::LayoutViewBase (lay::LayoutView *ui, db::Manager *manager, bool LayoutViewBase::LayoutViewBase (lay::LayoutView *ui, lay::LayoutViewBase *source, db::Manager *manager, bool editable, lay::Plugin *plugin_parent, unsigned int options) : lay::Dispatcher (plugin_parent, false /*not standalone*/), mp_ui (ui), + dm_redraw (this, &LayoutViewBase::redraw), m_editable (editable), m_options (options), m_annotation_shapes (manager) @@ -769,7 +772,7 @@ LayoutViewBase::configure (const std::string &name, const std::string &value) // keep a shadow state to correctly issue the redraw call m_default_font_size = df; lay::FixedFont::set_default_font_size (df); - redraw (); + redraw_later (); } // do not take - let others have the event for the redraw call return false; @@ -1814,7 +1817,7 @@ LayoutViewBase::set_properties (unsigned int index, const LayerPropertiesList &p if (index == current_layer_list ()) { end_layer_updates (); layer_list_changed_event (3); - redraw (); + redraw_later (); m_prop_changed = true; } } @@ -1875,7 +1878,7 @@ LayoutViewBase::replace_layer_node (unsigned int index, const LayerPropertiesCon end_layer_updates (); layer_list_changed_event (2); // TODO: check, if redraw is actually necessary (this is complex!) - redraw (); + redraw_later (); m_prop_changed = true; } } @@ -1909,7 +1912,7 @@ LayoutViewBase::set_properties (unsigned int index, const LayerPropertiesConstIt layer_list_changed_event (1); if (need_redraw) { - redraw (); + redraw_later (); } if (visible_changed) { @@ -1945,7 +1948,7 @@ LayoutViewBase::insert_layer (unsigned int index, const LayerPropertiesConstIter if (index == current_layer_list ()) { end_layer_updates (); layer_list_changed_event (2); - redraw (); + redraw_later (); m_prop_changed = true; } @@ -1978,7 +1981,7 @@ LayoutViewBase::delete_layer (unsigned int index, LayerPropertiesConstIterator & if (index == current_layer_list ()) { end_layer_updates (); layer_list_changed_event (2); - redraw (); + redraw_later (); m_prop_changed = true; } @@ -2174,7 +2177,7 @@ void LayoutViewBase::signal_hier_changed () { // schedule a redraw request for all layers - redraw (); + redraw_later (); // forward this event to our observers hier_changed_event (); } @@ -2206,7 +2209,7 @@ void LayoutViewBase::signal_bboxes_changed () { // schedule a redraw request for all layers - redraw (); + redraw_later (); // forward this event to our observers geom_changed_event (); @@ -2216,7 +2219,7 @@ void LayoutViewBase::signal_cell_name_changed () { cell_visibility_changed_event (); // HINT: that is not what actually is intended, but it serves the function ... - redraw (); // needs redraw + redraw_later (); // needs redraw } void @@ -2229,7 +2232,7 @@ LayoutViewBase::signal_layer_properties_changed () } // schedule a redraw request - since the layer views might not have changed, this is necessary - redraw (); + redraw_later (); } void @@ -2271,7 +2274,7 @@ LayoutViewBase::finish_cellviews_changed () cellviews_changed_event (); - redraw (); + redraw_later (); } std::list::iterator @@ -3896,6 +3899,12 @@ LayoutViewBase::redraw_deco_layer () do_redraw (lay::draw_custom_queue_entry); } +void +LayoutViewBase::redraw_later () +{ + dm_redraw (); +} + void LayoutViewBase::redraw () { @@ -5463,6 +5472,7 @@ LayoutViewBase::current_pos (double /*x*/, double /*y*/) void LayoutViewBase::stop_redraw () { + dm_redraw.cancel (); mp_canvas->stop_redraw (); } diff --git a/src/laybasic/laybasic/layLayoutViewBase.h b/src/laybasic/laybasic/layLayoutViewBase.h index a45056f80..3419f76c9 100644 --- a/src/laybasic/laybasic/layLayoutViewBase.h +++ b/src/laybasic/laybasic/layLayoutViewBase.h @@ -51,6 +51,7 @@ #include "tlException.h" #include "tlEvents.h" #include "tlTimer.h" +#include "tlDeferredExecution.h" #include "dbInstElement.h" namespace rdb { @@ -2650,6 +2651,7 @@ public: // called by children and owner void redraw (); + void redraw_later (); void redraw_layer (unsigned int index); void redraw_deco_layer (); void redraw_cell_boxes (); @@ -2700,6 +2702,7 @@ private: private: lay::LayoutView *mp_ui; + tl::DeferredMethod dm_redraw; bool m_editable; int m_disabled_edits; unsigned int m_options; diff --git a/src/layui/layui/layLayerControlPanel.cc b/src/layui/layui/layLayerControlPanel.cc index 1ff0370c8..66fece100 100644 --- a/src/layui/layui/layLayerControlPanel.cc +++ b/src/layui/layui/layLayerControlPanel.cc @@ -70,6 +70,7 @@ LCPTreeWidget::LCPTreeWidget (QWidget *parent, lay::LayerTreeModel *model, const { setObjectName (QString::fromUtf8 (name)); setModel (model); + setUniformRowHeights (true); #if QT_VERSION >= 0x040200 setAllColumnsShowFocus (true); #endif @@ -1702,7 +1703,7 @@ LayerControlPanel::cancel_updates () void LayerControlPanel::end_updates () { - do_update_content (); + m_do_update_content_dm (); } void From 5731c36a35e0e2db016bf4485399a7013327de55 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 17 Dec 2022 20:34:41 +0100 Subject: [PATCH 11/17] Trying Jenkins setup for MSVC --- Jenkinsfile-msvc2017 | 65 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 Jenkinsfile-msvc2017 diff --git a/Jenkinsfile-msvc2017 b/Jenkinsfile-msvc2017 new file mode 100644 index 000000000..e3033ad39 --- /dev/null +++ b/Jenkinsfile-msvc2017 @@ -0,0 +1,65 @@ + +@Library("osconfig") _ + +properties([disableConcurrentBuilds()]) + +// from shared library +target = osconfig() + +currentBuild.description = "Pipelined " + target + +node("master") { + + artefacts = pwd() + "/artefacts" + target_dir = artefacts + "/" + target + + stage("Checkout sources") { + + checkout scm + checkout_private() + + } + + stage("Building target ${target}") { + + withDockerContainer(image: "jenkins-${target}") { + // from shared library + build(target, target_dir) + } + + } + + stage("Publish and test") { + + parallel( + "Publish": { + + // from shared library - only publish for normal branch, not for PR + if (! BRANCH_NAME.startsWith('PR')) { + publish(BRANCH_NAME, target, target_dir) + } + + }, + "Unit testing": { + + ut_result = "no-result" + withDockerContainer(image: "jenkins-${target}") { + ut_result = run_ut(target) + } + + junit(testResults: ut_result) + + }, + "Installtest": { + + withDockerContainer(image: "jenkins-${target}-basic") { + // from shared library + installtest(target, target_dir) + } + + }) + + } + +} + From 43c07e9de386c7040e4982e2e991ae14f17afd59 Mon Sep 17 00:00:00 2001 From: klayoutmatthias Date: Sat, 17 Dec 2022 23:59:19 +0100 Subject: [PATCH 12/17] Updating Jenkinsfile-msvc2017 --- Jenkinsfile-msvc2017 | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/Jenkinsfile-msvc2017 b/Jenkinsfile-msvc2017 index e3033ad39..89a2735f8 100644 --- a/Jenkinsfile-msvc2017 +++ b/Jenkinsfile-msvc2017 @@ -22,10 +22,8 @@ node("master") { stage("Building target ${target}") { - withDockerContainer(image: "jenkins-${target}") { - // from shared library - build(target, target_dir) - } + // from shared library + build(target, target_dir) } @@ -43,19 +41,15 @@ node("master") { "Unit testing": { ut_result = "no-result" - withDockerContainer(image: "jenkins-${target}") { - ut_result = run_ut(target) - } + ut_result = run_ut(target) junit(testResults: ut_result) }, "Installtest": { - withDockerContainer(image: "jenkins-${target}-basic") { - // from shared library - installtest(target, target_dir) - } + // from shared library + installtest(target, target_dir) }) From 781e9a7e263596badc0242f66620ee164cfd61d8 Mon Sep 17 00:00:00 2001 From: klayoutmatthias Date: Sun, 18 Dec 2022 01:13:08 +0100 Subject: [PATCH 13/17] Turning off Python module test --- Jenkinsfile-msvc2017 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile-msvc2017 b/Jenkinsfile-msvc2017 index 89a2735f8..036f6bc2a 100644 --- a/Jenkinsfile-msvc2017 +++ b/Jenkinsfile-msvc2017 @@ -49,7 +49,7 @@ node("master") { "Installtest": { // from shared library - installtest(target, target_dir) + installtest_nopython(target, target_dir) }) From b7b26b7ecd1859773361004d3aba52ba87d4be58 Mon Sep 17 00:00:00 2001 From: klayoutmatthias Date: Sun, 18 Dec 2022 01:16:46 +0100 Subject: [PATCH 14/17] Turning off Python module test --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index e3033ad39..03bf27089 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -54,7 +54,7 @@ node("master") { withDockerContainer(image: "jenkins-${target}-basic") { // from shared library - installtest(target, target_dir) + installtest_nopython(target, target_dir) } }) From de784de7eac7a9cff3d92fce0ed10d35c019b54d Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 18 Dec 2022 14:31:46 +0100 Subject: [PATCH 15/17] Wider data types for Windows (long is 32 bit) and for CBLOCK byte counts in OASIS reader --- .../oasis/db_plugin/dbOASISReader.cc | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc index 3480e0530..a8c5f0dcc 100644 --- a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc +++ b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc @@ -559,41 +559,42 @@ OASISReader::mark_start_table () void OASISReader::read_offset_table () { - unsigned long of = 0; + unsigned int of = 0; of = get_uint (); - m_table_cellname = get_ulong (); + get (m_table_cellname); if (m_table_cellname != 0 && m_expect_strict_mode >= 0 && ((of == 0) != (m_expect_strict_mode == 0))) { warn (tl::to_string (tr ("CELLNAME offset table has unexpected strict mode"))); } of = get_uint (); - m_table_textstring = get_ulong (); + get (m_table_textstring); if (m_table_textstring != 0 && m_expect_strict_mode >= 0 && ((of == 0) != (m_expect_strict_mode == 0))) { warn (tl::to_string (tr ("TEXTSTRING offset table has unexpected strict mode"))); } of = get_uint (); - m_table_propname = get_ulong (); + get (m_table_propname); if (m_table_propname != 0 && m_expect_strict_mode >= 0 && ((of == 0) != (m_expect_strict_mode == 0))) { warn (tl::to_string (tr ("PROPNAME offset table has unexpected strict mode"))); } of = get_uint (); - m_table_propstring = get_ulong (); + get (m_table_propstring); if (m_table_propstring != 0 && m_expect_strict_mode >= 0 && ((of == 0) != (m_expect_strict_mode == 0))) { warn (tl::to_string (tr ("PROPSTRING offset table has unexpected strict mode"))); } of = get_uint (); - m_table_layername = get_ulong (); + get (m_table_layername); if (m_table_layername != 0 && m_expect_strict_mode >= 0 && ((of == 0) != (m_expect_strict_mode == 0))) { warn (tl::to_string (tr ("LAYERNAME offset table has unexpected strict mode"))); } // XNAME table ignored currently get_uint (); - get_ulong (); + size_t dummy = 0; + get (dummy); } static const char magic_bytes[] = { "%SEMI-OASIS\015\012" }; @@ -1084,8 +1085,9 @@ OASISReader::do_read (db::Layout &layout) error (tl::sprintf (tl::to_string (tr ("Invalid CBLOCK compression type %d")), type)); } - get_uint (); // uncomp-byte-count - not needed - get_uint (); // comp-byte-count - not needed + size_t dummy = 0; + get (dummy); // uncomp-byte-count - not needed + get (dummy); // comp-byte-count - not needed // put the stream into deflating mode m_stream.inflate (); @@ -1282,8 +1284,9 @@ OASISReader::read_element_properties (db::PropertiesRepository &rep, bool ignore error (tl::sprintf (tl::to_string (tr ("Invalid CBLOCK compression type %d")), type)); } - get_uint (); // uncomp-byte-count - not needed - get_uint (); // comp-byte-count - not needed + size_t dummy = 0; + get (dummy); // uncomp-byte-count - not needed + get (dummy); // comp-byte-count - not needed // put the stream into deflating mode m_stream.inflate (); @@ -1520,7 +1523,7 @@ OASISReader::read_pointlist (modal_variable > &pointlis bool OASISReader::read_repetition () { - unsigned char type = get_uint (); + unsigned int type = get_uint (); if (type == 0) { // reuse modal variable @@ -3308,8 +3311,9 @@ OASISReader::do_read_cell (db::cell_index_type cell_index, db::Layout &layout) error (tl::sprintf (tl::to_string (tr ("Invalid CBLOCK compression type %d")), type)); } - get_uint (); // uncomp-byte-count - not needed - get_uint (); // comp-byte-count - not needed + size_t dummy = 0; + get (dummy); // uncomp-byte-count - not needed + get (dummy); // comp-byte-count - not needed // put the stream into deflating mode m_stream.inflate (); From 9440985aed667a293472d831d3869603dc6fbc77 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 18 Dec 2022 17:43:48 +0100 Subject: [PATCH 16/17] Trying to fix a segfault observed on MacOS --- .../tools/net_tracer/db_plugin/dbNetTracerPlugin.cc | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/plugins/tools/net_tracer/db_plugin/dbNetTracerPlugin.cc b/src/plugins/tools/net_tracer/db_plugin/dbNetTracerPlugin.cc index 67cc68b9d..953e47119 100644 --- a/src/plugins/tools/net_tracer/db_plugin/dbNetTracerPlugin.cc +++ b/src/plugins/tools/net_tracer/db_plugin/dbNetTracerPlugin.cc @@ -80,7 +80,8 @@ get_default (const db::NetTracerTechnologyComponent &tc) if (tc.begin () != tc.end ()) { return tc.begin ().operator-> (); } else { - return 0; + static db::NetTracerConnectivity s_empty; + return &s_empty; } } @@ -135,13 +136,8 @@ struct FallbackXMLReadAdaptor void start (const db::NetTracerTechnologyComponent &parent) { const db::NetTracerConnectivity *tn = get_default (parent); - if (! tn) { - m_iter = Iter (); - m_end = Iter (); - } else { - m_iter = (tn->*mp_begin) (); - m_end = (tn->*mp_end) (); - } + m_iter = (tn->*mp_begin) (); + m_end = (tn->*mp_end) (); } void next () From 7a762024113341329fe5b5c4476a7333dcc6a9e7 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 20 Dec 2022 20:43:04 +0100 Subject: [PATCH 17/17] Added a unit test to check the integrity of all XML doc pages --- src/lay/lay/layHelpSource.h | 2 +- src/lay/unit_tests/layHelpIndexTest.cc | 33 ++++++++++++++++++++++++++ src/lay/unit_tests/unit_tests.pro | 3 ++- src/unit_tests/unit_test_main.cc | 4 ++++ src/unit_tests/unit_tests.pro | 7 ++++++ 5 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 src/lay/unit_tests/layHelpIndexTest.cc diff --git a/src/lay/lay/layHelpSource.h b/src/lay/lay/layHelpSource.h index 222a85cd5..62ca4ca8e 100644 --- a/src/lay/lay/layHelpSource.h +++ b/src/lay/lay/layHelpSource.h @@ -70,7 +70,7 @@ std::string escape_xml (const std::string &s); /** * @brief A specialization of BrowserSource for delivering the generated documentation */ -class HelpSource +class LAY_PUBLIC HelpSource : public BrowserSource { public: diff --git a/src/lay/unit_tests/layHelpIndexTest.cc b/src/lay/unit_tests/layHelpIndexTest.cc new file mode 100644 index 000000000..ddd243fe0 --- /dev/null +++ b/src/lay/unit_tests/layHelpIndexTest.cc @@ -0,0 +1,33 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2022 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#include "layHelpSource.h" +#include "tlUnitTest.h" + +TEST (1) +{ + // tests whether the index can be built - i.e. all XML files + // are valid. + lay::HelpSource help_source (false /*don't load index file*/); + help_source.scan (); +} diff --git a/src/lay/unit_tests/unit_tests.pro b/src/lay/unit_tests/unit_tests.pro index 2452b866f..bd437bdbb 100644 --- a/src/lay/unit_tests/unit_tests.pro +++ b/src/lay/unit_tests/unit_tests.pro @@ -8,7 +8,8 @@ include($$PWD/../../lib_ut.pri) SOURCES = \ laySalt.cc \ - laySessionTests.cc + layHelpIndexTest.cc \ + laySessionTests.cc INCLUDEPATH += $$LAY_INC $$TL_INC $$LAYBASIC_INC $$LAYUI_INC $$LAYVIEW_INC $$DB_INC $$GSI_INC $$ANT_INC $$IMG_INC $$RDB_INC DEPENDPATH += $$LAY_INC $$TL_INC $$LAYBASIC_INC $$LAYUI_INC $$LAYVIEW_INC $$DB_INC $$GSI_INC $$ANT_INC $$IMG_INC $$RDB_INC diff --git a/src/unit_tests/unit_test_main.cc b/src/unit_tests/unit_test_main.cc index 32640b046..fce23b5a5 100644 --- a/src/unit_tests/unit_test_main.cc +++ b/src/unit_tests/unit_test_main.cc @@ -41,6 +41,10 @@ // This hard-links the GSI test classes #include "../gsi_test/gsiTestForceLink.h" +// For testing the document structure +#include "docForceLink.h" +#include "iconsForceLink.h" + #include "version.h" #if defined(HAVE_QT) diff --git a/src/unit_tests/unit_tests.pro b/src/unit_tests/unit_tests.pro index 0e01149cb..230b1bd8b 100644 --- a/src/unit_tests/unit_tests.pro +++ b/src/unit_tests/unit_tests.pro @@ -4,6 +4,13 @@ DESTDIR = $$OUT_PWD/.. include($$PWD/../klayout.pri) include($$PWD/../with_all_libs.pri) +# NOTE: doc is needed for testing help sources + +INCLUDEPATH += $$DOC_INC $$ICONS_INC +DEPENDPATH += $$DOC_INC $$ICONS_INC + +LIBS += -lklayout_doc -lklayout_icons + TEMPLATE = app # Don't build the ut_runner app as ordinary command line tool on MacOS