From 78a139494a2c1ed3b6ee358cc7f45527507efcc6 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 2 Dec 2022 17:21:12 +0100 Subject: [PATCH 01/21] Avoid recursion in Application#notify during exception processing - more stable debugging --- src/lay/lay/layApplication.cc | 29 ++++++++++++++++++++++------- src/lay/lay/layApplication.h | 1 + 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/lay/lay/layApplication.cc b/src/lay/lay/layApplication.cc index 13ce2719a..a02791ef8 100644 --- a/src/lay/lay/layApplication.cc +++ b/src/lay/lay/layApplication.cc @@ -1443,7 +1443,8 @@ ApplicationBase::get_config_names () const GuiApplication::GuiApplication (int &argc, char **argv) : QApplication (argc, argv), ApplicationBase (false), mp_mw (0), - mp_recorder (0) + mp_recorder (0), + m_in_notify (0) { // install a special style proxy to overcome the issue of black-on-black tree expanders setStyle (new lay::BackgroundAwareTreeStyle (0)); @@ -1479,14 +1480,28 @@ GuiApplication::initialize () bool GuiApplication::notify (QObject *receiver, QEvent *e) { - // Note: due to a bug in some Qt versions (i.e. 4.8.3) throwing exceptions across - // signals may not be safe. Hence the local BEGIN_PROTECTED .. END_PROTECTED approach - // is still preferred over the global solution through "notify" + bool in_notify = (m_in_notify > 0); bool ret = true; - BEGIN_PROTECTED - ret = QApplication::notify (receiver, e); - END_PROTECTED + ++m_in_notify; + + // Note: due to a bug in some Qt versions (i.e. 4.8.3) throwing exceptions across + // signals may not be safe. Hence the local BEGIN_PROTECTED .. END_PROTECTED approach + // is still preferred over the global solution through "notify". + // Because END_PROTECTED may raise other events (message box) and this may cause other + // exceptions, we use silent mode inside notify to avoid recursion. + + if (in_notify) { + BEGIN_PROTECTED_SILENT + ret = QApplication::notify (receiver, e); + END_PROTECTED_SILENT + } else { + BEGIN_PROTECTED + ret = QApplication::notify (receiver, e); + END_PROTECTED + } + + --m_in_notify; return ret; } diff --git a/src/lay/lay/layApplication.h b/src/lay/lay/layApplication.h index 79cf507fb..31dbb6b07 100644 --- a/src/lay/lay/layApplication.h +++ b/src/lay/lay/layApplication.h @@ -479,6 +479,7 @@ protected: private: MainWindow *mp_mw; gtf::Recorder *mp_recorder; + int m_in_notify; }; /** From 77e9b511cf6fe8709e832ced7334287ae683653c Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 2 Dec 2022 17:32:18 +0100 Subject: [PATCH 02/21] Fixed slow 'show only selected' with many layers (reason: too many updates of recent editor options layer list) --- src/edt/edt/edtRecentConfigurationPage.cc | 10 ++++++++-- src/edt/edt/edtRecentConfigurationPage.h | 5 ++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/edt/edt/edtRecentConfigurationPage.cc b/src/edt/edt/edtRecentConfigurationPage.cc index 84f831c8d..071527444 100644 --- a/src/edt/edt/edtRecentConfigurationPage.cc +++ b/src/edt/edt/edtRecentConfigurationPage.cc @@ -69,7 +69,7 @@ RecentConfigurationPage::init () } mp_tree_widget->setHeaderLabels (column_labels); - update_list (get_stored_values ()); + update_list (); } RecentConfigurationPage::~RecentConfigurationPage () @@ -314,11 +314,17 @@ RecentConfigurationPage::render_to (QTreeWidgetItem *item, int column, const std void RecentConfigurationPage::layers_changed (int) { - update_list (get_stored_values ()); + dm_update_list (); } void RecentConfigurationPage::technology_changed (const std::string &) +{ + dm_update_list (); +} + +void +RecentConfigurationPage::update_list () { update_list (get_stored_values ()); } diff --git a/src/edt/edt/edtRecentConfigurationPage.h b/src/edt/edt/edtRecentConfigurationPage.h index 00997fd0f..ba084dc20 100644 --- a/src/edt/edt/edtRecentConfigurationPage.h +++ b/src/edt/edt/edtRecentConfigurationPage.h @@ -27,6 +27,7 @@ #include "layEditorOptionsPage.h" #include "tlObject.h" +#include "tlDeferredExecution.h" #include #include @@ -79,7 +80,7 @@ public: template RecentConfigurationPage (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher, const std::string &recent_cfg_name, Iter begin_cfg, Iter end_cfg) - : EditorOptionsPage (view, dispatcher), m_recent_cfg_name (recent_cfg_name), m_cfg (begin_cfg, end_cfg) + : EditorOptionsPage (view, dispatcher), m_recent_cfg_name (recent_cfg_name), m_cfg (begin_cfg, end_cfg), dm_update_list (this, &RecentConfigurationPage::update_list) { init (); } @@ -99,9 +100,11 @@ private: std::string m_recent_cfg_name; std::list m_cfg; QTreeWidget *mp_tree_widget; + tl::DeferredMethod dm_update_list; void init (); void update_list (const std::list > &stored_values); + void update_list (); std::list > get_stored_values () const; void set_stored_values (const std::list > &values) const; void render_to (QTreeWidgetItem *item, int column, const std::vector &values, RecentConfigurationPage::ConfigurationRendering rendering); From cca20773a74bf661aa69a11204d6ef57cc90d1af Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 2 Dec 2022 17:53:15 +0100 Subject: [PATCH 03/21] Include performance patch for array-vs-array interactions in deep mode --- src/db/db/dbHierProcessor.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/db/db/dbHierProcessor.cc b/src/db/db/dbHierProcessor.cc index 35582d39b..db7210bd6 100644 --- a/src/db/db/dbHierProcessor.cc +++ b/src/db/db/dbHierProcessor.cc @@ -1097,10 +1097,16 @@ private: const db::Cell &cell1 = mp_subject_layout->cell (inst1->object ().cell_index ()); const db::Cell &cell2 = mp_intruder_layout->cell (inst2->object ().cell_index ()); db::box_convert inst2_bc (*mp_intruder_layout, m_intruder_layer); + db::box_convert inst1_bc (*mp_subject_layout, m_subject_layer); + + db::Box iibox2 = inst2->bbox (inst2_bc).enlarged (db::Vector (m_dist, m_dist)); + if (iibox2.empty ()) { + return; + } std::unordered_map > > interactions_cache; - for (db::CellInstArray::iterator n = inst1->begin (); ! n.at_end (); ++n) { + for (db::CellInstArray::iterator n = inst1->begin_touching (safe_box_enlarged (iibox2, -1, -1), inst1_bc); ! n.at_end (); ++n) { db::ICplxTrans tn1 = inst1->complex_trans (*n); db::ICplxTrans tni1 = tn1.inverted (); From 63ad38e9d90e35a60b93886014cc0340b6a174e3 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 3 Dec 2022 20:59:36 +0100 Subject: [PATCH 04/21] Region#inside/not_inside/covering/not_covering is faster as it skips the merge step now. Fixed deep mode implementation (counting mode detection) with performance effect on outside/interacting too --- src/db/db/dbAsIfFlatRegion.cc | 3 ++- src/db/db/dbDeepRegion.cc | 9 ++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index 842e55eba..be42a4843 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -581,7 +581,8 @@ AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, boo proc.set_report_progress (report_progress ()); std::vector > others; - others.push_back ((mode < 0 || counting) ? other.begin_merged () : other.begin ()); + // NOTE: with counting the other region needs to be merged + others.push_back (counting ? other.begin_merged () : other.begin ()); proc.run_flat (polygons, others, std::vector (), &op, oph.results ()); diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index 0f7ea7fd7..350e10fe2 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -1952,6 +1952,7 @@ DeepRegion::selected_interacting_generic (const Region &other, int mode, bool to } } + min_count = std::max (size_t (1), min_count); bool counting = !(min_count == 1 && max_count == std::numeric_limits::max ()); // with these flag set to true, the resulting polygons are broken again. @@ -1966,9 +1967,8 @@ DeepRegion::selected_interacting_generic (const Region &other, int mode, bool to } const db::DeepLayer &polygons = merged_deep_layer (); - // NOTE: on "inside" or with counting, the other polygons must be merged - bool other_needs_merged = (mode < 0 || counting); - const db::DeepLayer &other_polygons = other_needs_merged ? other_deep->merged_deep_layer () : other_deep->deep_layer (); + // NOTE: with counting, the other polygons must be merged + const db::DeepLayer &other_polygons = counting ? other_deep->merged_deep_layer () : other_deep->deep_layer (); db::InteractingLocalOperation op (mode, touching, output_mode, min_count, max_count, true); @@ -2011,6 +2011,7 @@ DeepRegion::selected_interacting_generic (const Edges &other, InteractingOutputM } } + min_count = std::max (size_t (1), min_count); bool counting = !(min_count == 1 && max_count == std::numeric_limits::max ()); // with these flag set to true, the resulting polygons are broken again. @@ -2181,6 +2182,8 @@ DeepRegion::selected_interacting_generic (const Texts &other, InteractingOutputM } } + min_count = std::max (size_t (1), min_count); + // with these flag set to true, the resulting polygons are broken again. bool split_after = false; From 4d04cf4fe3c9ad4797b5d72c9641377d2df25540 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 4 Dec 2022 10:32:36 +0100 Subject: [PATCH 05/21] WIP: introducing points as valid objects into database - implementation. Includes: edge pair perimeter and area. --- src/db/db/dbBox.h | 2 +- src/db/db/dbEdgePair.h | 25 ++++++++ src/db/db/dbPoint.h | 25 ++++++++ src/db/db/dbShape.cc | 26 ++++++++ src/db/db/dbShape.h | 107 +++++++++++++++++++++++++++++++++ src/db/db/dbShapeIterator.cc | 5 ++ src/db/db/dbShapes.cc | 30 +++++++++ src/db/db/dbShapes.h | 7 ++- src/db/db/dbShapes2.cc | 8 +++ src/db/db/dbShapes3.cc | 13 +++- src/db/db/gsiDeclDbEdgePair.cc | 12 ++++ src/db/db/gsiDeclDbShape.cc | 55 +++++++++++++++++ src/db/db/gsiDeclDbShapes.cc | 38 ++++++++++++ 13 files changed, 349 insertions(+), 4 deletions(-) diff --git a/src/db/db/dbBox.h b/src/db/db/dbBox.h index 8736b8e19..18c2b3b94 100644 --- a/src/db/db/dbBox.h +++ b/src/db/db/dbBox.h @@ -56,7 +56,7 @@ class ArrayRepository; * coordinates box). */ -template +template struct DB_PUBLIC_TEMPLATE box { typedef C coord_type; diff --git a/src/db/db/dbEdgePair.h b/src/db/db/dbEdgePair.h index 93da9a72b..da3e7f8c6 100644 --- a/src/db/db/dbEdgePair.h +++ b/src/db/db/dbEdgePair.h @@ -63,6 +63,7 @@ public: typedef db::coord_traits coord_traits; typedef typename coord_traits::distance_type distance_type; typedef typename coord_traits::area_type area_type; + typedef typename coord_traits::perimeter_type perimeter_type; typedef db::object_tag< edge_pair > tag; /** @@ -379,6 +380,30 @@ public: return box_type (m_first.p1 (), m_first.p2 ()) + box_type (m_second.p1 (), m_second.p2 ()); } + /** + * @brief Gets the perimeter of the edge pair + * + * The perimeter is defined by then sum of the lengths of the edges ("active perimeter") + */ + perimeter_type perimeter () const + { + return m_first.length () + m_second.length (); + } + + /** + * @brief Gets the area of the edge pair + * + * This is the area covered between the edges. + */ + area_type area () const + { + vector_type v12 = m_first.p2 () - m_first.p1 (); + vector_type v13 = m_second.p1 () - m_first.p1 (); + vector_type v14 = m_second.p2 () - m_first.p1 (); + area_type a = (db::vprod (v12, v13) + db::vprod (v13, v14)) / 2; + return a < 0 ? -a : a; + } + /** * @brief Test if the edges are orthogonal (vertical or horizontal) */ diff --git a/src/db/db/dbPoint.h b/src/db/db/dbPoint.h index 0a6b8882e..cdc8d4c09 100644 --- a/src/db/db/dbPoint.h +++ b/src/db/db/dbPoint.h @@ -28,6 +28,7 @@ #include "dbCommon.h" #include "dbTypes.h" +#include "dbObjectTag.h" #include "tlString.h" #include "tlTypeTraits.h" #include "tlVector.h" @@ -37,6 +38,9 @@ namespace db { template class vector; +template struct box; +template class generic_repository; +class ArrayRepository; /** * @brief A point class @@ -51,6 +55,9 @@ public: typedef db::vector vector_type; typedef typename coord_traits::distance_type distance_type; typedef typename coord_traits::area_type area_type; + typedef db::object_tag< point > tag; + typedef db::box box_type; + typedef db::point point_type; /** * @brief Default constructor @@ -321,6 +328,24 @@ public: */ bool less (const point &p) const; + /** + * @brief The (dummy) translation operator + */ + void translate (const point &d, db::generic_repository &, db::ArrayRepository &) + { + *this = d; + } + + /** + * @brief The (dummy) translation operator + */ + template + void translate (const point &d, const T &t, db::generic_repository &, db::ArrayRepository &) + { + *this = d; + transform (t); + } + private: C m_x, m_y; }; diff --git a/src/db/db/dbShape.cc b/src/db/db/dbShape.cc index dd4c126d3..4463c05ed 100644 --- a/src/db/db/dbShape.cc +++ b/src/db/db/dbShape.cc @@ -95,6 +95,8 @@ db::properties_id_type Shape::prop_id () const return (**((pedge_iter_type *) m_generic.iter)).properties_id (); case EdgePair: return (**((pedge_pair_iter_type *) m_generic.iter)).properties_id (); + case Point: + return (**((ppoint_iter_type *) m_generic.iter)).properties_id (); case Path: return (**((ppath_iter_type *) m_generic.iter)).properties_id (); case PathRef: @@ -144,6 +146,8 @@ db::properties_id_type Shape::prop_id () const return m_generic.pedge->properties_id (); case EdgePair: return m_generic.pedge_pair->properties_id (); + case Point: + return m_generic.ppoint->properties_id (); case Path: return m_generic.ppath->properties_id (); case PathRef: @@ -564,6 +568,9 @@ Shape::box_type Shape::box () const return m_trans * basic_ptr (box_array_type::tag ())->object (); } else if (m_type == ShortBoxArrayMember) { return m_trans * basic_ptr (short_box_array_type::tag ())->object (); + } else if (m_type == Point) { + point_type pt = point (); + return m_trans * box_type (pt, pt); } else { raise_no_box (); } @@ -614,6 +621,12 @@ Shape::perimeter_type Shape::perimeter () const const short_box_array_type *arr = basic_ptr (short_box_array_type::tag ()); return arr->size () * arr->object ().perimeter (); } + case Point: + return 0; + case Edge: + return edge ().length (); + case EdgePair: + return edge_pair ().perimeter (); case Box: case ShortBox: case BoxArrayMember: @@ -629,6 +642,9 @@ size_t Shape::array_size () const switch (m_type) { case Null: return 0; + case Point: + case Edge: + case EdgePair: case Polygon: case PolygonRef: case PolygonPtrArrayMember: @@ -681,6 +697,11 @@ Shape::area_type Shape::area () const switch (m_type) { case Null: return area_type (); + case Point: + case Edge: + return 0; + case EdgePair: + return edge_pair ().area (); case Polygon: return polygon ().area (); case PolygonRef: @@ -761,6 +782,8 @@ Shape::box_type Shape::bbox () const return box_type (edge ().p1 (), edge ().p2 ()); case EdgePair: return edge_pair ().bbox (); + case Point: + return box_type (point (), point ()); case Path: return path ().box (); case PathRef: @@ -835,6 +858,9 @@ Shape::to_string () const case EdgePair: r = "edge_pair " + edge_pair ().to_string (); break; + case Point: + r = "point " + point ().to_string (); + break; case Path: case PathRef: case PathPtrArrayMember: diff --git a/src/db/db/dbShape.h b/src/db/db/dbShape.h index 8bad9ade7..3ba323870 100644 --- a/src/db/db/dbShape.h +++ b/src/db/db/dbShape.h @@ -645,6 +645,7 @@ public: typedef tl::reuse_vector >::const_iterator path_ptr_array_iter_type; typedef tl::reuse_vector >::const_iterator edge_iter_type; typedef tl::reuse_vector >::const_iterator edge_pair_iter_type; + typedef tl::reuse_vector >::const_iterator point_iter_type; typedef tl::reuse_vector >::const_iterator text_iter_type; typedef tl::reuse_vector >::const_iterator text_ref_iter_type; typedef tl::reuse_vector >::const_iterator text_ptr_iter_type; @@ -669,6 +670,7 @@ public: typedef tl::reuse_vector > >::const_iterator ppath_ptr_array_iter_type; typedef tl::reuse_vector > >::const_iterator pedge_iter_type; typedef tl::reuse_vector > >::const_iterator pedge_pair_iter_type; + typedef tl::reuse_vector > >::const_iterator ppoint_iter_type; typedef tl::reuse_vector > >::const_iterator ptext_iter_type; typedef tl::reuse_vector > >::const_iterator ptext_ref_iter_type; typedef tl::reuse_vector > >::const_iterator ptext_ptr_iter_type; @@ -709,6 +711,7 @@ public: TextRef, TextPtrArray, TextPtrArrayMember, + Point, UserObject }; @@ -1029,6 +1032,14 @@ public: m_type = EdgePair; } + /** + * @brief Construct a shape proxy as a reference to a point + */ + void init (point_type::tag) + { + m_type = Point; + } + /** * @brief Construct a shape proxy as a reference to a box */ @@ -1373,6 +1384,22 @@ public: } } + /** + * @brief Return the actual object that this shape reference is pointing to + * + * This is a generalization of the polygon (), etc. methods using a tag to identify the + * target object. + */ + const point_type *basic_ptr (point_type::tag) const + { + tl_assert (m_type == Point); + if (m_stable) { + return m_with_props ? &**(((ppoint_iter_type *) m_generic.iter)) : &**(((ppoint_iter_type *) m_generic.iter)); + } else { + return m_with_props ? m_generic.ppoint : m_generic.point; + } + } + /** * @brief Return the actual object that this shape reference is pointing to * @@ -1682,6 +1709,23 @@ public: } } + /** + * @brief Return the actual object that this shape reference is pointing to for objects with properties + * + * This is a generalization of the polygon (), etc. methods using a tag to identify the + * target object. + */ + const db::object_with_properties *basic_ptr (db::object_with_properties::tag) const + { + tl_assert (m_type == Point); + tl_assert (m_with_props); + if (m_stable) { + return &**(((ppoint_iter_type *) m_generic.iter)); + } else { + return m_generic.ppoint; + } + } + /** * @brief Return the actual object that this shape reference is pointing to for objects with properties * @@ -1917,6 +1961,15 @@ public: return *(((edge_pair_iter_type *) m_generic.iter)); } + /** + * @brief Return the iterator (in stable reference mode) by tag + */ + point_iter_type basic_iter (point_type::tag) const + { + tl_assert (m_type == Point && ! m_with_props); + return *(((point_iter_type *) m_generic.iter)); + } + /** * @brief Return the iterator (in stable reference mode) by tag */ @@ -2088,6 +2141,15 @@ public: return *(((pedge_pair_iter_type *) m_generic.iter)); } + /** + * @brief Return the iterator (in stable reference mode) by tag for objects with properties + */ + ppoint_iter_type basic_iter (db::object_with_properties::tag) const + { + tl_assert (m_type == Point && m_with_props); + return *(((ppoint_iter_type *) m_generic.iter)); + } + /** * @brief Return the iterator (in stable reference mode) by tag for objects with properties */ @@ -2395,6 +2457,49 @@ public: return edge_pair (p); } + /** + * @brief Return a reference to the point if one is referenced + */ + const point_type &point () const + { + tl_assert (m_type == Point); + return *basic_ptr (point_type::tag ()); + } + + /** + * @brief Test if the shape proxy points to a point + */ + bool is_point () const + { + return (m_type == Point); + } + + /** + * @brief Instantiate the edge object + * + * If a edge is referenced, this object is instantiated + * by this method. + * Returns true, if the conversion was successful. + */ + bool point (point_type &p) const + { + if (is_point ()) { + p = point (); + return true; + } else { + return false; + } + } + + /** + * @brief Alias for polymorphic expansion + * Returns true, if the conversion was successful. + */ + bool instantiate (point_type &p) const + { + return point (p); + } + /** * @brief Return a reference to the text if one is referenced */ @@ -2675,6 +2780,7 @@ public: const text_ptr_array_type *text_aref; const edge_type *edge; const edge_pair_type *edge_pair; + const point_type *point; const path_type *path; const path_ref_type *path_ref; const path_ptr_array_type *path_aref; @@ -2695,6 +2801,7 @@ public: const db::object_with_properties *ptext_aref; const db::object_with_properties *pedge; const db::object_with_properties *pedge_pair; + const db::object_with_properties *ppoint; const db::object_with_properties *ppath; const db::object_with_properties *ppath_ref; const db::object_with_properties *ppath_aref; diff --git a/src/db/db/dbShapeIterator.cc b/src/db/db/dbShapeIterator.cc index 589f804ad..9500e3d16 100644 --- a/src/db/db/dbShapeIterator.cc +++ b/src/db/db/dbShapeIterator.cc @@ -641,6 +641,9 @@ ShapeIterator::advance_generic (int mode) case EdgePair: if (advance_shape (mode)) return; break; + case Point: + if (advance_shape (mode)) return; + break; case Path: if (advance_shape (mode)) return; break; @@ -767,6 +770,8 @@ ShapeIterator::quad_box_generic () const return (quad_box_by_shape (region_tag)); case EdgePair: return (quad_box_by_shape (region_tag)); + case Point: + return (quad_box_by_shape (region_tag)); case Path: return (quad_box_by_shape (region_tag)); case PathRef: diff --git a/src/db/db/dbShapes.cc b/src/db/db/dbShapes.cc index 962234ee1..4372f82ea 100644 --- a/src/db/db/dbShapes.cc +++ b/src/db/db/dbShapes.cc @@ -375,6 +375,8 @@ Shapes::do_insert (const Shapes::shape_type &shape, const Shapes::unit_trans_typ return (insert_by_tag (shape_type::edge_type::tag (), shape, pm)); case shape_type::EdgePair: return (insert_by_tag (shape_type::edge_pair_type::tag (), shape, pm)); + case shape_type::Point: + return (insert_by_tag (shape_type::point_type::tag (), shape, pm)); case shape_type::Path: return (insert_by_tag (shape_type::path_type::tag (), shape, pm)); case shape_type::PathRef: @@ -531,6 +533,16 @@ Shapes::do_insert (const Shapes::shape_type &shape, const Trans &t, tl::func_del return insert (db::object_with_properties (p, pm (shape.prop_id ()))); } } + case shape_type::Point: + { + shape_type::point_type p (shape.point ()); + p = t.trans (p); + if (! shape.has_prop_id ()) { + return insert (p); + } else { + return insert (db::object_with_properties (p, pm (shape.prop_id ()))); + } + } case shape_type::EdgePair: { shape_type::edge_pair_type p (shape.edge_pair ()); @@ -658,6 +670,8 @@ Shapes::find (const Shapes::shape_type &shape) const return find_shape_by_tag (shape_type::edge_type::tag (), shape); case shape_type::EdgePair: return find_shape_by_tag (shape_type::edge_pair_type::tag (), shape); + case shape_type::Point: + return find_shape_by_tag (shape_type::point_type::tag (), shape); case shape_type::Path: return find_shape_by_tag (shape_type::path_type::tag (), shape); case shape_type::PathRef: @@ -727,6 +741,9 @@ Shapes::replace_prop_id (const Shapes::shape_type &ref, db::properties_id_type p case shape_type::EdgePair: replace_prop_id (ref.basic_ptr (object_with_properties::tag ()), prop_id); break; + case shape_type::Point: + replace_prop_id (ref.basic_ptr (object_with_properties::tag ()), prop_id); + break; case shape_type::Path: replace_prop_id (ref.basic_ptr (object_with_properties::tag ()), prop_id); break; @@ -789,6 +806,8 @@ Shapes::replace_prop_id (const Shapes::shape_type &ref, db::properties_id_type p return replace_prop_id_iter (shape_type::simple_polygon_ptr_array_type::tag (), ref.basic_iter (shape_type::simple_polygon_ptr_array_type::tag ()), prop_id); case shape_type::Edge: return replace_prop_id_iter (shape_type::edge_type::tag (), ref.basic_iter (shape_type::edge_type::tag ()), prop_id); + case shape_type::Point: + return replace_prop_id_iter (shape_type::point_type::tag (), ref.basic_iter (shape_type::point_type::tag ()), prop_id); case shape_type::EdgePair: return replace_prop_id_iter (shape_type::edge_pair_type::tag (), ref.basic_iter (shape_type::edge_pair_type::tag ()), prop_id); case shape_type::Path: @@ -874,6 +893,12 @@ Shapes::transform (const Shapes::shape_type &ref, const Trans &t) p.transform (t); return replace_member_with_props (shape_type::edge_pair_type::tag (), ref, p); } + case shape_type::Point: + { + shape_type::point_type p (ref.point ()); + p = t.trans (p); + return replace_member_with_props (shape_type::point_type::tag (), ref, p); + } case shape_type::Path: { shape_type::path_type p (ref.path ()); @@ -962,6 +987,8 @@ Shapes::replace (const Shapes::shape_type &ref, const Sh &sh) return replace_member_with_props (shape_type::edge_type::tag (), ref, sh); case shape_type::EdgePair: return replace_member_with_props (shape_type::edge_pair_type::tag (), ref, sh); + case shape_type::Point: + return replace_member_with_props (shape_type::point_type::tag (), ref, sh); case shape_type::Path: return replace_member_with_props (shape_type::path_type::tag (), ref, sh); case shape_type::PathRef: @@ -1347,6 +1374,7 @@ template DB_PUBLIC Shape Shapes::replace<>(const Shape &, const SimplePolygon &) template DB_PUBLIC Shape Shapes::replace<>(const Shape &, const Text &); template DB_PUBLIC Shape Shapes::replace<>(const Shape &, const Edge &); template DB_PUBLIC Shape Shapes::replace<>(const Shape &, const EdgePair &); +template DB_PUBLIC Shape Shapes::replace<>(const Shape &, const Point &); template DB_PUBLIC Shape Shapes::transform<> (const Shape &, const ICplxTrans &); template DB_PUBLIC Shape Shapes::transform<> (const Shape &, const Trans &); @@ -1376,6 +1404,8 @@ template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::stable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::stable_layer_tag>; +template class DB_PUBLIC layer_op; +template class DB_PUBLIC layer_op, db::stable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::stable_layer_tag>; template class DB_PUBLIC layer_op; diff --git a/src/db/db/dbShapes.h b/src/db/db/dbShapes.h index f09581580..d950bb141 100644 --- a/src/db/db/dbShapes.h +++ b/src/db/db/dbShapes.h @@ -138,8 +138,9 @@ public: Text = 15, TextRef = 16, TextPtrArray = 17, - UserObject = 18, - Null = 19 // must be last! + Point = 18, + UserObject = 19, + Null = 20 // must be last! }; enum flags_type @@ -154,6 +155,7 @@ public: | (1 << SimplePolygonPtrArray), Edges = (1 << Edge), EdgePairs = (1 << EdgePair), + Points = (1 << Point), Paths = (1 << Path) | (1 << PathRef) | (1 << PathPtrArray), @@ -392,6 +394,7 @@ private: char sz17 [sizeof (per_shape_iter_size )]; char sz18 [sizeof (per_shape_iter_size )]; char sz19 [sizeof (per_shape_iter_size )]; + char sz20 [sizeof (per_shape_iter_size )]; }; // this union is simply there to determine the maximum size required for all diff --git a/src/db/db/dbShapes2.cc b/src/db/db/dbShapes2.cc index 82e1a8cf8..136eca156 100644 --- a/src/db/db/dbShapes2.cc +++ b/src/db/db/dbShapes2.cc @@ -679,6 +679,12 @@ inline unsigned int iterator_type_mask (ShapeIterator::edge_pair_type::tag) return 1 << ShapeIterator::EdgePair; } +/// @brief Internal: ShapeIterator masks per shape type +inline unsigned int iterator_type_mask (ShapeIterator::point_type::tag) +{ + return 1 << ShapeIterator::Point; +} + /// @brief Internal: ShapeIterator masks per shape type inline unsigned int iterator_type_mask (ShapeIterator::path_type::tag) { @@ -917,6 +923,8 @@ template class layer_class template class layer_class, db::stable_layer_tag>; template class layer_class; template class layer_class, db::stable_layer_tag>; +template class layer_class; +template class layer_class, db::stable_layer_tag>; template class layer_class; template class layer_class, db::stable_layer_tag>; template class layer_class; diff --git a/src/db/db/dbShapes3.cc b/src/db/db/dbShapes3.cc index 52c116cf3..ae40f521d 100644 --- a/src/db/db/dbShapes3.cc +++ b/src/db/db/dbShapes3.cc @@ -134,6 +134,8 @@ template DB_PUBLIC layer &Shapes::ge template DB_PUBLIC layer, db::stable_layer_tag> &Shapes::get_layer, db::stable_layer_tag> (); template DB_PUBLIC layer &Shapes::get_layer (); template DB_PUBLIC layer, db::stable_layer_tag> &Shapes::get_layer, db::stable_layer_tag> (); +template DB_PUBLIC layer &Shapes::get_layer (); +template DB_PUBLIC layer, db::stable_layer_tag> &Shapes::get_layer, db::stable_layer_tag> (); template DB_PUBLIC layer &Shapes::get_layer (); template DB_PUBLIC layer, db::stable_layer_tag> &Shapes::get_layer, db::stable_layer_tag> (); template DB_PUBLIC layer &Shapes::get_layer (); @@ -211,6 +213,8 @@ template DB_PUBLIC const layer &Shap template DB_PUBLIC const layer, db::stable_layer_tag> &Shapes::get_layer, db::stable_layer_tag> () const; template DB_PUBLIC const layer &Shapes::get_layer () const; template DB_PUBLIC const layer, db::stable_layer_tag> &Shapes::get_layer, db::stable_layer_tag> () const; +template DB_PUBLIC const layer &Shapes::get_layer () const; +template DB_PUBLIC const layer, db::stable_layer_tag> &Shapes::get_layer, db::stable_layer_tag> () const; template DB_PUBLIC const layer &Shapes::get_layer () const; template DB_PUBLIC const layer, db::stable_layer_tag> &Shapes::get_layer, db::stable_layer_tag> () const; template DB_PUBLIC const layer &Shapes::get_layer () const; @@ -315,6 +319,8 @@ Shapes::is_valid (const Shapes::shape_type &shape) const return is_valid_shape_by_tag (shape_type::edge_type::tag (), shape); case shape_type::EdgePair: return is_valid_shape_by_tag (shape_type::edge_pair_type::tag (), shape); + case shape_type::Point: + return is_valid_shape_by_tag (shape_type::point_type::tag (), shape); case shape_type::Path: return is_valid_shape_by_tag (shape_type::path_type::tag (), shape); case shape_type::PathRef: @@ -478,6 +484,9 @@ Shapes::erase_shape (const Shapes::shape_type &shape) case shape_type::EdgePair: erase_shape_by_tag (shape_type::edge_pair_type::tag (), shape); break; + case shape_type::Point: + erase_shape_by_tag (shape_type::point_type::tag (), shape); + break; case shape_type::Path: erase_shape_by_tag (shape_type::path_type::tag (), shape); break; @@ -570,6 +579,9 @@ Shapes::erase_shapes (const std::vector &shapes) case shape_type::Edge: erase_shapes_by_tag (shape_type::edge_type::tag (), s, snext); break; + case shape_type::Point: + erase_shapes_by_tag (shape_type::point_type::tag (), s, snext); + break; case shape_type::EdgePair: erase_shapes_by_tag (shape_type::edge_pair_type::tag (), s, snext); break; @@ -625,5 +637,4 @@ Shapes::erase_shapes (const std::vector &shapes) } } - } diff --git a/src/db/db/gsiDeclDbEdgePair.cc b/src/db/db/gsiDeclDbEdgePair.cc index 061f8d98f..3f4136c75 100644 --- a/src/db/db/gsiDeclDbEdgePair.cc +++ b/src/db/db/gsiDeclDbEdgePair.cc @@ -169,6 +169,18 @@ struct edge_pair_defs method ("bbox", &C::bbox, "@brief Gets the bounding box of the edge pair\n" ) + + method ("perimeter", &C::perimeter, + "@brief Gets the perimeter of the edge pair\n" + "\n" + "The perimeter is defined as the sum of the lengths of both edges ('active perimeter').\n" + "\n" + "This attribute has been introduced in version 0.28." + ) + + method ("area", &C::area, + "@brief Gets the area between the edges of the edge pair\n" + "\n" + "This attribute has been introduced in version 0.28." + ) + method ("<", &C::less, gsi::arg ("box"), "@brief Less operator\n" "Returns true, if this edge pair is 'less' with respect to first and second edge\n" diff --git a/src/db/db/gsiDeclDbShape.cc b/src/db/db/gsiDeclDbShape.cc index fab8cf946..3a3a85560 100644 --- a/src/db/db/gsiDeclDbShape.cc +++ b/src/db/db/gsiDeclDbShape.cc @@ -709,6 +709,26 @@ static tl::Variant get_dedge_pair (const db::Shape *s) } } +static tl::Variant get_point (const db::Shape *s) +{ + db::Shape::point_type p; + if (s->point (p)) { + return tl::Variant (p); + } else { + return tl::Variant (); + } +} + +static tl::Variant get_dpoint (const db::Shape *s) +{ + db::Shape::point_type p; + if (s->point (p)) { + return tl::Variant (db::CplxTrans (shape_dbu (s)) * p); + } else { + return tl::Variant (); + } +} + static tl::Variant get_text (const db::Shape *s) { db::Shape::text_type p; @@ -1108,6 +1128,7 @@ static int t_simplePolygonPtrArray () { return db::Shape::SimplePolygonPtr static int t_simplePolygonPtrArrayMember () { return db::Shape::SimplePolygonPtrArrayMember; } static int t_edge () { return db::Shape::Edge; } static int t_edge_pair () { return db::Shape::EdgePair; } +static int t_point () { return db::Shape::Point; } static int t_path () { return db::Shape::Path; } static int t_pathRef () { return db::Shape::PathRef; } static int t_pathPtrArray () { return db::Shape::PathPtrArray; } @@ -1250,6 +1271,22 @@ Class decl_Shape ("db", "Shape", "\n" "This method has been introduced in version 0.25." ) + + gsi::method_ext ("point=", &set_shape, gsi::arg("point"), + "@brief Replaces the shape by the given point\n" + "This method replaces the shape by the given point. This method can only be called " + "for editable layouts. It does not change the user properties of the shape.\n" + "Calling this method will invalidate any iterators. It should not be called inside a " + "loop iterating over shapes.\n" + "\n" + "This method has been introduced in version 0.28." + ) + + gsi::method_ext ("point=|dpoint=", &set_dshape, gsi::arg("point"), + "@brief Replaces the shape by the given point (in micrometer units)\n" + "This method replaces the shape by the given point, like \\point= with a \\Point argument does. " + "This version translates the point from micrometer units to database units internally.\n" + "\n" + "This method has been introduced in version 0.28." + ) + gsi::method_ext ("edge_pair=", &set_shape, gsi::arg("edge_pair"), "@brief Replaces the shape by the given edge pair\n" "This method replaces the shape by the given edge pair. This method can only be called " @@ -1760,6 +1797,23 @@ Class decl_Shape ("db", "Shape", "\n" "This method has been added in version 0.26.\n" ) + + gsi::method ("is_point?", &db::Shape::is_point, + "@brief Returns true, if the object is an point\n" + "\n" + "This method has been introduced in version 0.28.\n" + ) + + gsi::method_ext ("point", &get_point, + "@brief Returns the point object\n" + "\n" + "This method has been introduced in version 0.28.\n" + ) + + gsi::method_ext ("dpoint", &get_dpoint, + "@brief Returns the point object as a \\DPoint object in micrometer units\n" + "See \\point for a description of this method. This method returns the point after translation to " + "micrometer units.\n" + "\n" + "This method has been introduced in version 0.28.\n" + ) + gsi::method ("is_text?", &db::Shape::is_text, "@brief Returns true, if the object is a text\n" ) + @@ -2057,6 +2111,7 @@ Class decl_Shape ("db", "Shape", gsi::method ("TSimplePolygonPtrArrayMember|#t_simple_polygon_ptr_array_member", &t_simplePolygonPtrArrayMember) + gsi::method ("TEdge|#t_edge", &t_edge) + gsi::method ("TEdgePair|#t_edge_pair", &t_edge_pair) + + gsi::method ("TPoint|#t_point", &t_point) + gsi::method ("TPath|#t_path", &t_path) + gsi::method ("TPathRef|#t_path_ref", &t_pathRef) + gsi::method ("TPathPtrArray|#t_path_ptr_array", &t_pathPtrArray) + diff --git a/src/db/db/gsiDeclDbShapes.cc b/src/db/db/gsiDeclDbShapes.cc index c8603c736..bf7e055a3 100644 --- a/src/db/db/gsiDeclDbShapes.cc +++ b/src/db/db/gsiDeclDbShapes.cc @@ -454,6 +454,7 @@ static unsigned int s_regions () { return db::ShapeIterator::Regions static unsigned int s_boxes () { return db::ShapeIterator::Boxes; } static unsigned int s_edges () { return db::ShapeIterator::Edges; } static unsigned int s_edge_pairs () { return db::ShapeIterator::EdgePairs; } +static unsigned int s_points () { return db::ShapeIterator::Points; } static unsigned int s_paths () { return db::ShapeIterator::Paths; } static unsigned int s_texts () { return db::ShapeIterator::Texts; } static unsigned int s_user_objects () { return db::ShapeIterator::UserObjects; } @@ -875,6 +876,25 @@ Class decl_Shapes ("db", "Shapes", "\n" "This variant has been introduced in version 0.26.\n" ) + + gsi::method_ext ("replace", &replace, gsi::arg ("shape"), gsi::arg ("point"), + "@brief Replaces the given shape with an point object\n" + "\n" + "This method replaces the given shape with the " + "object specified. It does not change the property Id. To change the property Id, " + "use the \\replace_prop_id method. To replace a shape and discard the property Id, erase the " + "shape and insert a new shape." + "\n" + "This variant has been introduced in version 0.28." + ) + + gsi::method_ext ("replace", &dreplace, gsi::arg ("shape"), gsi::arg ("point"), + "@brief Replaces the given shape with an point given in micrometer units\n" + "@return A reference to the new shape (a \\Shape object)\n" + "\n" + "This method behaves like the \\replace version with an \\Point argument, except that it will " + "internally translate the point from micrometer to database units.\n" + "\n" + "This variant has been introduced in version 0.28." + ) + gsi::method_ext ("replace", &replace, gsi::arg ("shape"), gsi::arg ("text"), "@brief Replaces the given shape with a text object\n" "@return A reference to the new shape (a \\Shape object)\n" @@ -989,6 +1009,19 @@ Class decl_Shapes ("db", "Shapes", "\n" "This variant has been introduced in version 0.26." ) + + gsi::method_ext ("insert|#insert_point", &insert, gsi::arg ("point"), + "@brief Inserts an point into the shapes list\n" + "\n" + "This variant has been introduced in version 0.28.\n" + ) + + gsi::method_ext ("insert", &dinsert, gsi::arg ("point"), + "@brief Inserts a micrometer-unit point into the shapes list\n" + "@return A reference to the new shape (a \\Shape object)\n" + "This method behaves like the \\insert version with a \\Point argument, except that it will " + "internally translate the point from micrometer to database units.\n" + "\n" + "This variant has been introduced in version 0.28.\n" + ) + gsi::method_ext ("insert|#insert_text", &insert, gsi::arg ("text"), "@brief Inserts a text into the shapes list\n" "@return A reference to the new shape (a \\Shape object)\n" @@ -1285,6 +1318,11 @@ Class decl_Shapes ("db", "Shapes", gsi::method ("SEdgePairs|#s_edge_pairs", &s_edge_pairs, "@brief Indicates that edge pairs shall be retrieved" ) + + gsi::method ("SPoints|#s_points", &s_points, + "@brief Indicates that points shall be retrieved" + "\n" + "This constant has been added in version 0.28." + ) + gsi::method ("SPaths|#s_paths", &s_paths, "@brief Indicates that paths shall be retrieved" ) + From 0c89d8fec8ac39ee9d5c4b0982bf0b3890300add Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 4 Dec 2022 19:53:37 +0100 Subject: [PATCH 06/21] WIP: points as db objects - added tests, bug fixes --- src/db/db/dbObjectWithProperties.h | 3 + src/db/db/dbShape.h | 2 +- src/db/db/dbShapes2.cc | 2 + src/db/db/dbShapes3.cc | 6 ++ src/db/unit_tests/dbEdgePairTests.cc | 4 + src/db/unit_tests/dbShapeTests.cc | 133 +++++++++++++++++++++++++++ src/db/unit_tests/dbShapesTests.cc | 54 +++++------ testdata/ruby/dbEdgePairTest.rb | 26 ++++++ testdata/ruby/dbShapesTest.rb | 63 +++++++++++++ 9 files changed, 265 insertions(+), 28 deletions(-) diff --git a/src/db/db/dbObjectWithProperties.h b/src/db/db/dbObjectWithProperties.h index 7595f53ac..e9de85639 100644 --- a/src/db/db/dbObjectWithProperties.h +++ b/src/db/db/dbObjectWithProperties.h @@ -194,6 +194,9 @@ typedef object_with_properties DPathWithProperties; typedef object_with_properties PathRefWithProperties; typedef object_with_properties DPathRefWithProperties; +typedef object_with_properties PointWithProperties; +typedef object_with_properties DPointWithProperties; + typedef object_with_properties EdgeWithProperties; typedef object_with_properties DEdgeWithProperties; diff --git a/src/db/db/dbShape.h b/src/db/db/dbShape.h index 3ba323870..cfcc9f405 100644 --- a/src/db/db/dbShape.h +++ b/src/db/db/dbShape.h @@ -1394,7 +1394,7 @@ public: { tl_assert (m_type == Point); if (m_stable) { - return m_with_props ? &**(((ppoint_iter_type *) m_generic.iter)) : &**(((ppoint_iter_type *) m_generic.iter)); + return m_with_props ? &**(((ppoint_iter_type *) m_generic.iter)) : &**(((point_iter_type *) m_generic.iter)); } else { return m_with_props ? m_generic.ppoint : m_generic.point; } diff --git a/src/db/db/dbShapes2.cc b/src/db/db/dbShapes2.cc index 136eca156..f4138b9fd 100644 --- a/src/db/db/dbShapes2.cc +++ b/src/db/db/dbShapes2.cc @@ -965,6 +965,8 @@ template class layer_class; template class layer_class, db::unstable_layer_tag>; template class layer_class; template class layer_class, db::unstable_layer_tag>; +template class layer_class; +template class layer_class, db::unstable_layer_tag>; template class layer_class; template class layer_class, db::unstable_layer_tag>; template class layer_class; diff --git a/src/db/db/dbShapes3.cc b/src/db/db/dbShapes3.cc index ae40f521d..921be5e3d 100644 --- a/src/db/db/dbShapes3.cc +++ b/src/db/db/dbShapes3.cc @@ -152,6 +152,7 @@ template DB_PUBLIC layer template DB_PUBLIC layer, db::stable_layer_tag> &Shapes::get_layer, db::stable_layer_tag> (); template DB_PUBLIC layer &Shapes::get_layer (); template DB_PUBLIC layer, db::stable_layer_tag> &Shapes::get_layer, db::stable_layer_tag> (); + template DB_PUBLIC layer &Shapes::get_layer (); template DB_PUBLIC layer, db::unstable_layer_tag> &Shapes::get_layer, db::unstable_layer_tag> (); template DB_PUBLIC layer &Shapes::get_layer (); @@ -174,6 +175,8 @@ template DB_PUBLIC layer &Shapes:: template DB_PUBLIC layer, db::unstable_layer_tag> &Shapes::get_layer, db::unstable_layer_tag> (); template DB_PUBLIC layer &Shapes::get_layer (); template DB_PUBLIC layer, db::unstable_layer_tag> &Shapes::get_layer, db::unstable_layer_tag> (); +template DB_PUBLIC layer &Shapes::get_layer (); +template DB_PUBLIC layer, db::unstable_layer_tag> &Shapes::get_layer, db::unstable_layer_tag> (); template DB_PUBLIC layer &Shapes::get_layer (); template DB_PUBLIC layer, db::unstable_layer_tag> &Shapes::get_layer, db::unstable_layer_tag> (); template DB_PUBLIC layer &Shapes::get_layer (); @@ -231,6 +234,7 @@ template DB_PUBLIC const layer, db::stable_layer_tag> &Shapes::get_layer, db::stable_layer_tag> () const; template DB_PUBLIC const layer &Shapes::get_layer () const; template DB_PUBLIC const layer, db::stable_layer_tag> &Shapes::get_layer, db::stable_layer_tag> () const; + template DB_PUBLIC const layer &Shapes::get_layer () const; template DB_PUBLIC const layer, db::unstable_layer_tag> &Shapes::get_layer, db::unstable_layer_tag> () const; template DB_PUBLIC const layer &Shapes::get_layer () const; @@ -253,6 +257,8 @@ template DB_PUBLIC const layer &Sh template DB_PUBLIC const layer, db::unstable_layer_tag> &Shapes::get_layer, db::unstable_layer_tag> () const; template DB_PUBLIC const layer &Shapes::get_layer () const; template DB_PUBLIC const layer, db::unstable_layer_tag> &Shapes::get_layer, db::unstable_layer_tag> () const; +template DB_PUBLIC const layer &Shapes::get_layer () const; +template DB_PUBLIC const layer, db::unstable_layer_tag> &Shapes::get_layer, db::unstable_layer_tag> () const; template DB_PUBLIC const layer &Shapes::get_layer () const; template DB_PUBLIC const layer, db::unstable_layer_tag> &Shapes::get_layer, db::unstable_layer_tag> () const; template DB_PUBLIC const layer &Shapes::get_layer () const; diff --git a/src/db/unit_tests/dbEdgePairTests.cc b/src/db/unit_tests/dbEdgePairTests.cc index 2577bac33..fa7bf338f 100644 --- a/src/db/unit_tests/dbEdgePairTests.cc +++ b/src/db/unit_tests/dbEdgePairTests.cc @@ -35,11 +35,15 @@ TEST(1) EXPECT_EQ (ep == db::EdgePair (db::Edge (), db::Edge ()), true); EXPECT_EQ (ep != db::EdgePair (db::Edge (), db::Edge ()), false); EXPECT_EQ (ep < db::EdgePair (db::Edge (), db::Edge ()), false); + EXPECT_EQ (ep.area (), db::EdgePair::area_type (0)); + EXPECT_EQ (ep.perimeter (), db::EdgePair::perimeter_type (0)); ep = db::EdgePair (db::Edge (db::Point (10, 30), db::Point (15, 30)), db::Edge (db::Point (0, 30), db::Point (0, 40))); EXPECT_EQ (ep.to_string (), "(10,30;15,30)/(0,30;0,40)"); EXPECT_EQ (ep.normalized ().to_string (), "(15,30;10,30)/(0,30;0,40)"); EXPECT_EQ (ep.normalized ().normalized ().to_string (), "(15,30;10,30)/(0,30;0,40)"); + EXPECT_EQ (ep.area (), db::EdgePair::area_type (50)); // weird orientation :( + EXPECT_EQ (ep.perimeter (), db::EdgePair::perimeter_type (15)); ep = db::EdgePair (db::Edge (db::Point (1, 2), db::Point (11, 12)), db::Edge (db::Point (-5, 5), db::Point (5, 15))); EXPECT_EQ (ep.to_string (), "(1,2;11,12)/(-5,5;5,15)"); diff --git a/src/db/unit_tests/dbShapeTests.cc b/src/db/unit_tests/dbShapeTests.cc index 54ea3f717..4b5b013e6 100644 --- a/src/db/unit_tests/dbShapeTests.cc +++ b/src/db/unit_tests/dbShapeTests.cc @@ -815,3 +815,136 @@ TEST(8) } +// Edges, EdgePairs, Points +TEST(9) +{ + db::Manager m (true); + db::Shapes s (&m, 0, db::default_editable_mode ()); + + s.insert (db::Point (100, 200)); + s.insert (db::Edge (db::Point (100, 200), db::Point (200, 400))); + s.insert (db::EdgePair (db::Edge (db::Point (100, 200), db::Point (200, 400)), db::Edge (db::Point (0, 300), db::Point (100, 500)))); + + db::ShapeIterator si; + si = s.begin (db::ShapeIterator::All); + + EXPECT_EQ (si.at_end (), false); + EXPECT_EQ (si->is_edge (), true); + EXPECT_EQ (si->is_edge_pair (), false); + EXPECT_EQ (si->is_point (), false); + + EXPECT_EQ (si->to_string (), "edge (100,200;200,400)"); + EXPECT_EQ (si->edge ().to_string (), "(100,200;200,400)"); + + ++si; + + EXPECT_EQ (si.at_end (), false); + EXPECT_EQ (si->is_edge (), false); + EXPECT_EQ (si->is_edge_pair (), true); + EXPECT_EQ (si->is_point (), false); + + EXPECT_EQ (si->to_string (), "edge_pair (100,200;200,400)/(0,300;100,500)"); + EXPECT_EQ (si->edge_pair ().to_string (), "(100,200;200,400)/(0,300;100,500)"); + + ++si; + + EXPECT_EQ (si.at_end (), false); + EXPECT_EQ (si->is_edge (), false); + EXPECT_EQ (si->is_edge_pair (), false); + EXPECT_EQ (si->is_point (), true); + + EXPECT_EQ (si->to_string (), "point 100,200"); + EXPECT_EQ (si->point ().to_string (), "100,200"); + + ++si; + + EXPECT_EQ (si.at_end (), true); + + + si = s.begin (db::ShapeIterator::Edges); + + EXPECT_EQ (si.at_end (), false); + EXPECT_EQ (si->is_edge (), true); + EXPECT_EQ (si->is_edge_pair (), false); + EXPECT_EQ (si->is_point (), false); + + EXPECT_EQ (si->to_string (), "edge (100,200;200,400)"); + EXPECT_EQ (si->edge ().to_string (), "(100,200;200,400)"); + + ++si; + + EXPECT_EQ (si.at_end (), true); + + + si = s.begin (db::ShapeIterator::EdgePairs); + + EXPECT_EQ (si.at_end (), false); + EXPECT_EQ (si->is_edge (), false); + EXPECT_EQ (si->is_edge_pair (), true); + EXPECT_EQ (si->is_point (), false); + + EXPECT_EQ (si->to_string (), "edge_pair (100,200;200,400)/(0,300;100,500)"); + EXPECT_EQ (si->edge_pair ().to_string (), "(100,200;200,400)/(0,300;100,500)"); + + ++si; + + EXPECT_EQ (si.at_end (), true); + + si = s.begin (db::ShapeIterator::Points); + + EXPECT_EQ (si.at_end (), false); + EXPECT_EQ (si->is_edge (), false); + EXPECT_EQ (si->is_edge_pair (), false); + EXPECT_EQ (si->is_point (), true); + + EXPECT_EQ (si->to_string (), "point 100,200"); + EXPECT_EQ (si->point ().to_string (), "100,200"); + + ++si; + + EXPECT_EQ (si.at_end (), true); + + + s.clear (); + s.insert (db::PointWithProperties (db::Point (100, 200), 1)); + s.insert (db::EdgeWithProperties (db::Edge (db::Point (100, 200), db::Point (200, 400)), 2)); + s.insert (db::EdgePairWithProperties (db::EdgePair (db::Edge (db::Point (100, 200), db::Point (200, 400)), db::Edge (db::Point (0, 300), db::Point (100, 500))), 3)); + + si = s.begin (db::ShapeIterator::All); + + EXPECT_EQ (si.at_end (), false); + EXPECT_EQ (si->is_edge (), true); + EXPECT_EQ (si->prop_id (), db::properties_id_type (2)); + EXPECT_EQ (si->is_edge_pair (), false); + EXPECT_EQ (si->is_point (), false); + + EXPECT_EQ (si->to_string (), "edge (100,200;200,400) prop_id=2"); + EXPECT_EQ (si->edge ().to_string (), "(100,200;200,400)"); + + ++si; + + EXPECT_EQ (si.at_end (), false); + EXPECT_EQ (si->is_edge (), false); + EXPECT_EQ (si->is_edge_pair (), true); + EXPECT_EQ (si->prop_id (), db::properties_id_type (3)); + EXPECT_EQ (si->is_point (), false); + + EXPECT_EQ (si->to_string (), "edge_pair (100,200;200,400)/(0,300;100,500) prop_id=3"); + EXPECT_EQ (si->edge_pair ().to_string (), "(100,200;200,400)/(0,300;100,500)"); + + ++si; + + EXPECT_EQ (si.at_end (), false); + EXPECT_EQ (si->is_edge (), false); + EXPECT_EQ (si->is_edge_pair (), false); + EXPECT_EQ (si->is_point (), true); + EXPECT_EQ (si->prop_id (), db::properties_id_type (1)); + + EXPECT_EQ (si->to_string (), "point 100,200 prop_id=1"); + EXPECT_EQ (si->point ().to_string (), "100,200"); + + ++si; + + EXPECT_EQ (si.at_end (), true); +} + diff --git a/src/db/unit_tests/dbShapesTests.cc b/src/db/unit_tests/dbShapesTests.cc index 213b2feee..dbb0bf9ed 100644 --- a/src/db/unit_tests/dbShapesTests.cc +++ b/src/db/unit_tests/dbShapesTests.cc @@ -3406,33 +3406,6 @@ TEST(24c) EXPECT_EQ (shapes_to_string_norm (_this, s1), ""); } -// Bug #107 -TEST(100) -{ - db::Manager m (true); - db::Shapes shapes1 (&m, 0, true); - - m.transaction ("y"); - shapes1.insert (db::Box (200, -200, 100, -100)); - m.commit (); - - EXPECT_EQ (shapes_to_string_norm (_this, shapes1), - "box (100,-200;200,-100) #0\n" - ); - m.undo (); - EXPECT_EQ (shapes_to_string_norm (_this, shapes1), - "" - ); - m.redo (); - EXPECT_EQ (shapes_to_string_norm (_this, shapes1), - "box (100,-200;200,-100) #0\n" - ); - m.undo (); - EXPECT_EQ (shapes_to_string_norm (_this, shapes1), - "" - ); -} - // Shape insert and clear and undo/redo - different layouts TEST(24d) { @@ -3499,6 +3472,33 @@ TEST(24d) EXPECT_EQ (shapes_to_string_norm (_this, s1), ""); } +// Bug #107 +TEST(100) +{ + db::Manager m (true); + db::Shapes shapes1 (&m, 0, true); + + m.transaction ("y"); + shapes1.insert (db::Box (200, -200, 100, -100)); + m.commit (); + + EXPECT_EQ (shapes_to_string_norm (_this, shapes1), + "box (100,-200;200,-100) #0\n" + ); + m.undo (); + EXPECT_EQ (shapes_to_string_norm (_this, shapes1), + "" + ); + m.redo (); + EXPECT_EQ (shapes_to_string_norm (_this, shapes1), + "box (100,-200;200,-100) #0\n" + ); + m.undo (); + EXPECT_EQ (shapes_to_string_norm (_this, shapes1), + "" + ); +} + // Bug #835 TEST(101) { diff --git a/testdata/ruby/dbEdgePairTest.rb b/testdata/ruby/dbEdgePairTest.rb index ad6a4cea6..c8d5fda3f 100644 --- a/testdata/ruby/dbEdgePairTest.rb +++ b/testdata/ruby/dbEdgePairTest.rb @@ -31,6 +31,8 @@ class DBEdgePair_TestClass < TestBase ep = RBA::EdgePair::new assert_equal(ep.to_s, "(0,0;0,0)/(0,0;0,0)") + assert_equal(ep.to_s, "(0,0;0,0)/(0,0;0,0)") + ep.first = RBA::Edge::new(0, 0, 10, 20) assert_equal(ep.to_s, "(0,0;10,20)/(0,0;0,0)") @@ -57,6 +59,18 @@ class DBEdgePair_TestClass < TestBase assert_equal(ep.simple_polygon(0).to_s, "(-10,0;-10,30;0,0;10,20)") assert_equal(ep.simple_polygon(0).class.to_s, "RBA::SimplePolygon") + ep = RBA::EdgePair::new(RBA::Edge::new(0, 0, 10, 0), RBA::Edge::new(0, 20, 0, 0)) + + assert_equal(ep.perimeter, 30) + assert_equal(ep.area, 100) + assert_equal(ep.simple_polygon(0).area, 100) + + ep = RBA::EdgePair::new(RBA::Edge::new(0, 0, 10, 0), RBA::Edge::new(0, 0, 0, 20)) + + assert_equal(ep.perimeter, 30) + assert_equal(ep.area, 0) + assert_equal(ep.simple_polygon(0).area, 0) + end # Basics @@ -92,6 +106,18 @@ class DBEdgePair_TestClass < TestBase assert_equal(ep.simple_polygon(0).to_s, "(-10,0;-10,30;0,0;10,20)") assert_equal(ep.simple_polygon(0).class.to_s, "RBA::DSimplePolygon") + ep = RBA::DEdgePair::new(RBA::DEdge::new(0, 0, 10, 0), RBA::DEdge::new(0, 20, 0, 0)) + + assert_equal(ep.perimeter, 30) + assert_equal(ep.area, 100) + assert_equal(ep.simple_polygon(0).area, 100) + + ep = RBA::DEdgePair::new(RBA::DEdge::new(0, 0, 10, 0), RBA::DEdge::new(0, 0, 0, 20)) + + assert_equal(ep.perimeter, 30) + assert_equal(ep.area, 0) + assert_equal(ep.simple_polygon(0).area, 0) + end # Fuzzy compare diff --git a/testdata/ruby/dbShapesTest.rb b/testdata/ruby/dbShapesTest.rb index d59c38229..b3a6a5c5c 100644 --- a/testdata/ruby/dbShapesTest.rb +++ b/testdata/ruby/dbShapesTest.rb @@ -158,6 +158,9 @@ class DBShapes_TestClass < TestBase shapes.each( RBA::Shapes::SEdges ) { |s| arr.push( s ) } assert_equal( arr.size, 0 ) arr = [] + shapes.each( RBA::Shapes::SPoints ) { |s| arr.push( s ) } + assert_equal( arr.size, 0 ) + arr = [] shapes.each( RBA::Shapes::SBoxes ) { |s| arr.push( s ) } assert_equal( arr.size, 1 ) assert_equal( arr[0].prop_id, 0 ) @@ -166,6 +169,7 @@ class DBShapes_TestClass < TestBase assert_equal( arr[0].type, RBA::Shape::t_box ) assert_equal( arr[0].polygon.to_s, "(10,-10;10,40;50,40;50,-10)" ) assert_equal( arr[0].simple_polygon.to_s, "(10,-10;10,40;50,40;50,-10)" ) + assert_equal( arr[0].point.inspect, "nil" ) assert_equal( arr[0].edge.inspect, "nil" ) assert_equal( arr[0].edge_pair.inspect, "nil" ) assert_equal( arr[0].box.to_s, "(10,-10;50,40)" ) @@ -190,6 +194,7 @@ class DBShapes_TestClass < TestBase assert_equal( arr[0].is_edge?, true ) assert_equal( arr[0].polygon.inspect, "nil" ) assert_equal( arr[0].simple_polygon.inspect, "nil" ) + assert_equal( arr[0].point.inspect, "nil" ) assert_equal( arr[0].edge.to_s, "(-1,2;5,2)" ) assert_equal( arr[0].edge_pair.inspect, "nil" ) assert_equal( arr[0].box.inspect, "nil" ) @@ -217,6 +222,7 @@ class DBShapes_TestClass < TestBase assert_equal( arr[0].polygon.inspect, "nil" ) assert_equal( arr[0].simple_polygon.inspect, "nil" ) assert_equal( arr[0].edge_pair.to_s, "(-1,2;5,2)/(-1,5;5,5)" ) + assert_equal( arr[0].point.inspect, "nil" ) assert_equal( arr[0].edge.inspect, "nil" ) assert_equal( arr[0].box.inspect, "nil" ) assert_equal( arr[0].path.inspect, "nil" ) @@ -228,6 +234,33 @@ class DBShapes_TestClass < TestBase assert_equal( arr.size, 1 ) assert_equal( arr[0].is_box?, true ) + # points + + a = RBA::Point::new( -1, 2 ) + c1.shapes( lindex ).insert( a ) + arr = [] + shapes.each( RBA::Shapes::SPoints ) { |s| arr.push( s ) } + assert_equal( arr.size, 1 ) + assert_equal( arr[0].prop_id, 0 ) + assert_equal( arr[0].has_prop_id?, false ) + assert_equal( arr[0].is_null?, false ) + assert_equal( arr[0].type, RBA::Shape::t_point ) + assert_equal( arr[0].is_point?, true ) + assert_equal( arr[0].polygon.inspect, "nil" ) + assert_equal( arr[0].simple_polygon.inspect, "nil" ) + assert_equal( arr[0].point.to_s, "-1,2" ) + assert_equal( arr[0].edge.inspect, "nil" ) + assert_equal( arr[0].edge_pair.inspect, "nil" ) + assert_equal( arr[0].box.inspect, "nil" ) + assert_equal( arr[0].path.inspect, "nil" ) + assert_equal( arr[0].text.inspect, "nil" ) + assert_equal( arr[0].point == a, true ) + assert_equal( arr[0].bbox == RBA::Box::new(a, a), true ) + arr = [] + shapes.each( RBA::Shapes::SBoxes ) { |s| arr.push( s ) } + assert_equal( arr.size, 1 ) + assert_equal( arr[0].is_box?, true ) + # paths a = RBA::Path::new( [ RBA::Point::new( 0, 10 ), RBA::Point::new( 10, 50 ) ], 25 ) @@ -486,6 +519,9 @@ class DBShapes_TestClass < TestBase shapes.each( RBA::Shapes::SEdges ) { |s| arr.push( s ) } assert_equal( arr.size, 0 ) arr = [] + shapes.each( RBA::Shapes::SPoints ) { |s| arr.push( s ) } + assert_equal( arr.size, 0 ) + arr = [] shapes.each( RBA::Shapes::SBoxes ) { |s| arr.push( s ) } assert_equal( arr.size, 1 ) assert_equal( arr[0].prop_id, 0 ) @@ -543,6 +579,7 @@ class DBShapes_TestClass < TestBase assert_equal( arr[0].is_edge_pair?, true ) assert_equal( arr[0].dpolygon.inspect, "nil" ) assert_equal( arr[0].dsimple_polygon.inspect, "nil" ) + assert_equal( arr[0].dpoint.inspect, "nil" ) assert_equal( arr[0].dedge_pair.to_s, "(-0.001,0.002;0.005,0.002)/(-0.001,0.005;0.005,0.005)" ) assert_equal( arr[0].dedge.inspect, "nil" ) assert_equal( arr[0].dbox.inspect, "nil" ) @@ -554,6 +591,32 @@ class DBShapes_TestClass < TestBase assert_equal( arr.size, 1 ) assert_equal( arr[0].is_box?, true ) + # points + + a = RBA::DPoint::new( -1, 2 ) + c1.shapes( lindex ).insert( a ) + arr = [] + shapes.each( RBA::Shapes::SPoints ) { |s| arr.push( s ) } + assert_equal( arr.size, 1 ) + assert_equal( arr[0].prop_id, 0 ) + assert_equal( arr[0].has_prop_id?, false ) + assert_equal( arr[0].is_null?, false ) + assert_equal( arr[0].type, RBA::Shape::t_point ) + assert_equal( arr[0].is_point?, true ) + assert_equal( arr[0].dpolygon.inspect, "nil" ) + assert_equal( arr[0].dsimple_polygon.inspect, "nil" ) + assert_equal( arr[0].dpoint.to_s, "-1,2" ) + assert_equal( arr[0].dedge.inspect, "nil" ) + assert_equal( arr[0].dedge_pair.inspect, "nil" ) + assert_equal( arr[0].dbox.inspect, "nil" ) + assert_equal( arr[0].dpath.inspect, "nil" ) + assert_equal( arr[0].dtext.inspect, "nil" ) + assert_equal( arr[0].dbbox.to_s, "(-1,2;-1,2)" ) + arr = [] + shapes.each( RBA::Shapes::SBoxes ) { |s| arr.push( s ) } + assert_equal( arr.size, 1 ) + assert_equal( arr[0].is_box?, true ) + # paths a = RBA::DPath::new( [ RBA::DPoint::new( 0, 0.010 ), RBA::DPoint::new( 0.010, 0.050 ) ], 0.025 ) From 43ff59750ab17fe3c3a13f504c03a7a1244a6f68 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 4 Dec 2022 21:04:21 +0100 Subject: [PATCH 07/21] Fixed a race condition in DRC local processor with multiple threads --- src/db/db/dbHierProcessor.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/db/db/dbHierProcessor.cc b/src/db/db/dbHierProcessor.cc index db7210bd6..9bc161bf9 100644 --- a/src/db/db/dbHierProcessor.cc +++ b/src/db/db/dbHierProcessor.cc @@ -1747,6 +1747,8 @@ local_processor::compute_results (local_processor_contexts::const_iterator bu = cells_bu.begin (); bu != cells_bu.end (); ++bu) { + tl::MutexLocker locker (& contexts.lock ()); + typename local_processor_contexts::iterator cpc = contexts.context_map ().find (&mp_subject_layout->cell (*bu)); if (cpc != contexts.context_map ().end ()) { From 035232c97866a2919e644dd26811cc18764b572b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 5 Dec 2022 02:07:25 +0100 Subject: [PATCH 08/21] Providing single-linked list implementation with fast size to address DRC merge performance issue on CentOS --- src/db/db/dbHierNetworkProcessor.cc | 2 +- src/db/db/dbHierNetworkProcessor.h | 460 ++++++++++++++++------------ src/tl/tl/tl.pro | 2 + src/tl/tl/tlSList.cc | 31 ++ src/tl/tl/tlSList.h | 320 +++++++++++++++++++ src/tl/unit_tests/tlSListTests.cc | 192 ++++++++++++ src/tl/unit_tests/unit_tests.pro | 1 + 7 files changed, 816 insertions(+), 192 deletions(-) create mode 100644 src/tl/tl/tlSList.cc create mode 100644 src/tl/tl/tlSList.h create mode 100644 src/tl/unit_tests/tlSListTests.cc diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index fd6554b5f..e2a9bbec8 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -1264,7 +1264,7 @@ connected_clusters::join_cluster_with (typename local_cluster::id_type id, } connections_type &target = m_connections [id]; - target.splice (target.end (), to_join, to_join.begin (), to_join.end ()); + target.splice (to_join); m_connections.erase (tc); diff --git a/src/db/db/dbHierNetworkProcessor.h b/src/db/db/dbHierNetworkProcessor.h index 030f41c87..2c6b10cbd 100644 --- a/src/db/db/dbHierNetworkProcessor.h +++ b/src/db/db/dbHierNetworkProcessor.h @@ -211,6 +211,273 @@ private: edge_connectivity_type m_ec; }; +/** + * @brief The instance information for a cluster + */ +class DB_PUBLIC ClusterInstElement +{ +public: + ClusterInstElement (const db::InstElement &ie) + { + if (ie.array_inst.at_end ()) { + + m_inst_cell_index = std::numeric_limits::max (); + m_inst_trans = db::ICplxTrans (); + m_inst_prop_id = 0; + + } else { + + m_inst_cell_index = ie.inst_ptr.cell_index (); + m_inst_trans = ie.complex_trans (); + m_inst_prop_id = ie.inst_ptr.prop_id (); + + } + } + + ClusterInstElement (db::cell_index_type inst_cell_index, const db::ICplxTrans &inst_trans, db::properties_id_type inst_prop_id) + : m_inst_cell_index (inst_cell_index), m_inst_trans (inst_trans), m_inst_prop_id (inst_prop_id) + { + // .. nothing yet .. + } + + ClusterInstElement () + : m_inst_cell_index (std::numeric_limits::max ()), m_inst_trans (), m_inst_prop_id (0) + { + // .. nothing yet .. + } + + /** + * @brief Returns true, if the cluster does not have an instance + */ + bool has_instance () const + { + return m_inst_cell_index != std::numeric_limits::max (); + } + + /** + * @brief Gets the cell index of the cell which is instantiated + */ + db::cell_index_type inst_cell_index () const + { + return m_inst_cell_index; + } + + /** + * @brief Gets the instance transformation + */ + const db::ICplxTrans &inst_trans () const + { + return m_inst_trans; + } + + /** + * @brief Gets the instance properties id + */ + db::properties_id_type inst_prop_id () const + { + return m_inst_prop_id; + } + + /** + * @brief Sets the instance properties id + */ + void set_inst_prop_id (db::properties_id_type pid) + { + m_inst_prop_id = pid; + } + + /** + * @brief Transform with the given transformation + */ + void transform (const db::ICplxTrans &tr) + { + m_inst_trans = tr * m_inst_trans; + } + + /** + * @brief Equality + */ + bool operator== (const ClusterInstElement &other) const + { + return m_inst_cell_index == other.m_inst_cell_index && m_inst_trans.equal (other.m_inst_trans) && m_inst_prop_id == other.m_inst_prop_id; + } + + /** + * @brief Inequality + */ + bool operator!= (const ClusterInstElement &other) const + { + return ! operator== (other); + } + + /** + * @brief Less operator + */ + bool operator< (const ClusterInstElement &other) const + { + if (m_inst_cell_index != other.m_inst_cell_index) { + return m_inst_cell_index < other.m_inst_cell_index; + } + if (! m_inst_trans.equal (other.m_inst_trans)) { + return m_inst_trans.less (other.m_inst_trans); + } + return m_inst_prop_id < other.m_inst_prop_id; + } + +private: + db::cell_index_type m_inst_cell_index; + db::ICplxTrans m_inst_trans; + db::properties_id_type m_inst_prop_id; +}; + +/** + * @brief A connection to a cluster in a child instance + */ +class DB_PUBLIC ClusterInstance + : public ClusterInstElement +{ +public: + ClusterInstance (size_t id, db::cell_index_type inst_cell_index, const db::ICplxTrans &inst_trans, db::properties_id_type inst_prop_id) + : ClusterInstElement (inst_cell_index, inst_trans, inst_prop_id), m_id (id) + { + // .. nothing yet .. + } + + ClusterInstance (size_t id, const db::InstElement &inst_element) + : ClusterInstElement (inst_element), m_id (id) + { + // .. nothing yet .. + } + + ClusterInstance (size_t id) + : ClusterInstElement (), m_id (id) + { + // .. nothing yet .. + } + + ClusterInstance () + : ClusterInstElement (), m_id (0) + { + // .. nothing yet .. + } + + /** + * @brief Gets the cluster ID + */ + size_t id () const + { + return m_id; + } + + /** + * @brief Equality + */ + bool operator== (const ClusterInstance &other) const + { + return m_id == other.m_id && ClusterInstElement::operator== (other); + } + + /** + * @brief Inequality + */ + bool operator!= (const ClusterInstance &other) const + { + return ! operator== (other); + } + + /** + * @brief Less operator + */ + bool operator< (const ClusterInstance &other) const + { + if (m_id != other.m_id) { + return m_id < other.m_id; + } + return ClusterInstElement::operator< (other); + } + +private: + size_t m_id; +}; + +/** + * @brief A class representing a list of ClusterInstance objects + * + * It is using a std::list internally, but adds fast size support for STLs which do not have that. + */ +class DB_PUBLIC ClusterInstanceList +{ +public: + typedef std::list inner_list; + typedef inner_list::iterator iterator; + typedef inner_list::const_iterator const_iterator; + + ClusterInstanceList () + : m_list (), m_size (0) + { + // .. nothing yet .. + } + + ClusterInstanceList (const ClusterInstanceList &other) + : m_list (other.m_list), m_size (other.m_size) + { + // .. nothing yet .. + } + + ClusterInstanceList (ClusterInstanceList &&other) + : m_list (other.m_list), m_size (other.m_size) + { + // .. nothing yet .. + } + + ClusterInstanceList &operator= (const ClusterInstanceList &other) + { + if (this != &other) { + m_list = other.m_list; + m_size = other.m_size; + } + return *this; + } + + iterator begin () { return m_list.begin (); } + iterator end () { return m_list.end (); } + const_iterator begin () const { return m_list.begin (); } + const_iterator end () const { return m_list.end (); } + + bool empty () const + { + return m_list.empty (); + } + + void push_back (const ClusterInstance &inst) + { + m_list.push_back (inst); + ++m_size; + } + + void push_back (ClusterInstance &&inst) + { + m_list.push_back (inst); + ++m_size; + } + + void splice (ClusterInstanceList &other) + { + m_size += other.m_size; + m_list.splice (m_list.end (), other.m_list, other.m_list.begin (), other.m_list.end ()); + other.m_size = 0; + } + + size_t size () const + { + return m_size; + } + +private: + inner_list m_list; + size_t m_size; +}; + /** * @brief Represents a cluster of shapes * @@ -596,195 +863,6 @@ inline void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int x.mem_stat (stat, purpose, cat, no_self, parent); } -/** - * @brief The instance information for a cluster - */ -class DB_PUBLIC ClusterInstElement -{ -public: - ClusterInstElement (const db::InstElement &ie) - { - if (ie.array_inst.at_end ()) { - - m_inst_cell_index = std::numeric_limits::max (); - m_inst_trans = db::ICplxTrans (); - m_inst_prop_id = 0; - - } else { - - m_inst_cell_index = ie.inst_ptr.cell_index (); - m_inst_trans = ie.complex_trans (); - m_inst_prop_id = ie.inst_ptr.prop_id (); - - } - } - - ClusterInstElement (db::cell_index_type inst_cell_index, const db::ICplxTrans &inst_trans, db::properties_id_type inst_prop_id) - : m_inst_cell_index (inst_cell_index), m_inst_trans (inst_trans), m_inst_prop_id (inst_prop_id) - { - // .. nothing yet .. - } - - ClusterInstElement () - : m_inst_cell_index (std::numeric_limits::max ()), m_inst_trans (), m_inst_prop_id (0) - { - // .. nothing yet .. - } - - /** - * @brief Returns true, if the cluster does not have an instance - */ - bool has_instance () const - { - return m_inst_cell_index != std::numeric_limits::max (); - } - - /** - * @brief Gets the cell index of the cell which is instantiated - */ - db::cell_index_type inst_cell_index () const - { - return m_inst_cell_index; - } - - /** - * @brief Gets the instance transformation - */ - const db::ICplxTrans &inst_trans () const - { - return m_inst_trans; - } - - /** - * @brief Gets the instance properties id - */ - db::properties_id_type inst_prop_id () const - { - return m_inst_prop_id; - } - - /** - * @brief Sets the instance properties id - */ - void set_inst_prop_id (db::properties_id_type pid) - { - m_inst_prop_id = pid; - } - - /** - * @brief Transform with the given transformation - */ - void transform (const db::ICplxTrans &tr) - { - m_inst_trans = tr * m_inst_trans; - } - - /** - * @brief Equality - */ - bool operator== (const ClusterInstElement &other) const - { - return m_inst_cell_index == other.m_inst_cell_index && m_inst_trans.equal (other.m_inst_trans) && m_inst_prop_id == other.m_inst_prop_id; - } - - /** - * @brief Inequality - */ - bool operator!= (const ClusterInstElement &other) const - { - return ! operator== (other); - } - - /** - * @brief Less operator - */ - bool operator< (const ClusterInstElement &other) const - { - if (m_inst_cell_index != other.m_inst_cell_index) { - return m_inst_cell_index < other.m_inst_cell_index; - } - if (! m_inst_trans.equal (other.m_inst_trans)) { - return m_inst_trans.less (other.m_inst_trans); - } - return m_inst_prop_id < other.m_inst_prop_id; - } - -private: - db::cell_index_type m_inst_cell_index; - db::ICplxTrans m_inst_trans; - db::properties_id_type m_inst_prop_id; -}; - -/** - * @brief A connection to a cluster in a child instance - */ -class DB_PUBLIC ClusterInstance - : public ClusterInstElement -{ -public: - ClusterInstance (size_t id, db::cell_index_type inst_cell_index, const db::ICplxTrans &inst_trans, db::properties_id_type inst_prop_id) - : ClusterInstElement (inst_cell_index, inst_trans, inst_prop_id), m_id (id) - { - // .. nothing yet .. - } - - ClusterInstance (size_t id, const db::InstElement &inst_element) - : ClusterInstElement (inst_element), m_id (id) - { - // .. nothing yet .. - } - - ClusterInstance (size_t id) - : ClusterInstElement (), m_id (id) - { - // .. nothing yet .. - } - - ClusterInstance () - : ClusterInstElement (), m_id (0) - { - // .. nothing yet .. - } - - /** - * @brief Gets the cluster ID - */ - size_t id () const - { - return m_id; - } - - /** - * @brief Equality - */ - bool operator== (const ClusterInstance &other) const - { - return m_id == other.m_id && ClusterInstElement::operator== (other); - } - - /** - * @brief Inequality - */ - bool operator!= (const ClusterInstance &other) const - { - return ! operator== (other); - } - - /** - * @brief Less operator - */ - bool operator< (const ClusterInstance &other) const - { - if (m_id != other.m_id) { - return m_id < other.m_id; - } - return ClusterInstElement::operator< (other); - } - -private: - size_t m_id; -}; - typedef std::list > cluster_instance_pair_list_type; inline bool equal_array_delegates (const db::ArrayBase *a, const db::ArrayBase *b) @@ -1040,7 +1118,7 @@ public: private: typename local_clusters::const_iterator m_lc_iter; - typedef std::list connections_type; + typedef ClusterInstanceList connections_type; typename std::map::id_type, connections_type>::const_iterator m_x_iter, m_x_iter_end; }; @@ -1060,7 +1138,7 @@ class DB_PUBLIC_TEMPLATE connected_clusters { public: typedef typename local_clusters::id_type id_type; - typedef std::list connections_type; + typedef ClusterInstanceList connections_type; typedef typename local_clusters::box_type box_type; typedef connected_clusters_iterator all_iterator; typedef typename std::map::id_type, connections_type>::const_iterator connections_iterator; diff --git a/src/tl/tl/tl.pro b/src/tl/tl/tl.pro index 0cc8c7ea4..558134601 100644 --- a/src/tl/tl/tl.pro +++ b/src/tl/tl/tl.pro @@ -51,6 +51,7 @@ SOURCES = \ tlLongInt.cc \ tlUniqueId.cc \ tlList.cc \ + tlSList.cc \ tlEquivalenceClusters.cc \ tlUniqueName.cc \ tlRecipe.cc \ @@ -115,6 +116,7 @@ HEADERS = \ tlLongInt.h \ tlUniqueId.h \ tlList.h \ + tlSList.h \ tlEquivalenceClusters.h \ tlUniqueName.h \ tlRecipe.h \ diff --git a/src/tl/tl/tlSList.cc b/src/tl/tl/tlSList.cc new file mode 100644 index 000000000..c70a255b1 --- /dev/null +++ b/src/tl/tl/tlSList.cc @@ -0,0 +1,31 @@ + +/* + + 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 "tlSList.h" + +namespace tl +{ + + // .. nothing yet .. + +} diff --git a/src/tl/tl/tlSList.h b/src/tl/tl/tlSList.h new file mode 100644 index 000000000..44d16611c --- /dev/null +++ b/src/tl/tl/tlSList.h @@ -0,0 +1,320 @@ + +/* + + 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_tlSList +#define HDR_tlSList + +#include "tlCommon.h" + +#include +#include + +namespace tl +{ + +/** + * @brief A simple single-linked list implementation + * + * This implementation supports: + * - fast size + * - push_back, push_front + * - forward iterator, const_iterator + * - splice + * - pop_front + * - clear + * - empty + */ + +template +class slist +{ +private: + struct node_type + { + node_type (const T &_t) : next (0), t (_t) { } + node_type (T &&_t) : next (0), t (_t) { } + node_type *next; + T t; + }; + +public: + class iterator + { + public: + typedef std::forward_iterator_tag category; + typedef T value_type; + typedef T &reference; + typedef T *pointer; + + iterator (node_type *p = 0) : mp_p (p) { } + iterator operator++ () { mp_p = mp_p->next; return *this; } + + T *operator-> () const + { + return &mp_p->t; + } + + T &operator* () const + { + return mp_p->t; + } + + bool operator== (iterator other) const { return mp_p == other.mp_p; } + bool operator!= (iterator other) const { return mp_p != other.mp_p; } + + private: + node_type *mp_p; + }; + + class const_iterator + { + public: + typedef std::forward_iterator_tag category; + typedef const T value_type; + typedef const T &reference; + typedef const T *pointer; + + const_iterator (const node_type *p = 0) : mp_p (p) { } + const_iterator operator++ () { mp_p = mp_p->next; return *this; } + + const T *operator-> () const + { + return &mp_p->t; + } + + const T &operator* () const + { + return mp_p->t; + } + + bool operator== (const_iterator other) const { return mp_p == other.mp_p; } + bool operator!= (const_iterator other) const { return mp_p != other.mp_p; } + + private: + const node_type *mp_p; + }; + + slist () + : mp_first (0), mp_last (0) + { + // .. nothing yet .. + } + + template + slist (Iter from, Iter to) + : mp_first (0), mp_last (0), m_size (0) + { + for (Iter i = from; i != to; ++i) { + push_back (*i); + } + } + + slist (const slist &other) + : mp_first (0), mp_last (0), m_size (0) + { + for (auto i = other.begin (); i != other.end (); ++i) { + push_back (*i); + } + } + + slist (slist &&other) + : mp_first (0), mp_last (0), m_size (0) + { + std::swap (mp_first, other.mp_first); + std::swap (mp_last, other.mp_last); + std::swap (m_size, other.m_size); + } + + slist &operator= (const slist &other) + { + if (this != &other) { + clear (); + for (const_iterator i = other.begin (); i != other.end (); ++i) { + push_back (*i); + } + } + return *this; + } + + slist &operator= (slist &&other) + { + clear (); + std::swap (mp_first, other.mp_first); + std::swap (mp_last, other.mp_last); + std::swap (m_size, other.m_size); + return *this; + } + + ~slist () + { + clear (); + } + + iterator begin () + { + return iterator (mp_first); + } + + iterator end () + { + return iterator (0); + } + + const_iterator begin () const + { + return const_iterator (mp_first); + } + + const_iterator end () const + { + return const_iterator (0); + } + + size_t size () const + { + return m_size; + } + + bool empty () const + { + return mp_first == 0; + } + + void clear () + { + while (! empty ()) { + pop_front (); + } + } + + void swap (slist &other) + { + std::swap (mp_first, other.mp_first); + std::swap (mp_last, other.mp_last); + std::swap (m_size, other.m_size); + } + + void pop_front () + { + if (mp_first) { + node_type *n = mp_first; + if (n == mp_last) { + mp_first = mp_last = 0; + } else { + mp_first = mp_first->next; + } + delete n; + --m_size; + } + } + + T &front () + { + return mp_first->t; + } + + const T &front () const + { + return mp_first->t; + } + + T &back () + { + return mp_last->t; + } + + const T &back () const + { + return mp_last->t; + } + + void push_front (const T &t) + { + push_front_impl (new node_type (t)); + } + + void push_front (T &&t) + { + push_front_impl (new node_type (t)); + } + + void push_back (const T &t) + { + push_back_impl (new node_type (t)); + } + + void push_back (T &&t) + { + push_back_impl (new node_type (t)); + } + + void splice (slist &other) + { + if (! other.mp_first) { + return; + } + + if (! mp_first) { + mp_first = other.mp_first; + } else { + mp_last->next = other.mp_first; + } + + mp_last = other.mp_last; + m_size += other.m_size; + + other.mp_first = other.mp_last = 0; + other.m_size = 0; + } + +private: + node_type *mp_first, *mp_last; + size_t m_size; + + void push_front_impl (node_type *n) + { + if (mp_first) { + n->next = mp_first; + mp_first = n; + } else { + mp_first = mp_last = n; + } + ++m_size; + } + + void push_back_impl (node_type *n) + { + if (mp_last) { + mp_last->next = n; + mp_last = n; + } else { + mp_first = mp_last = n; + } + ++m_size; + } +}; + +} + +#endif diff --git a/src/tl/unit_tests/tlSListTests.cc b/src/tl/unit_tests/tlSListTests.cc new file mode 100644 index 000000000..63ef20321 --- /dev/null +++ b/src/tl/unit_tests/tlSListTests.cc @@ -0,0 +1,192 @@ + +/* + + 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 "tlSList.h" +#include "tlUnitTest.h" +#include "tlString.h" + +namespace +{ + +static size_t obj_count = 0; + +struct MyClass1 +{ + MyClass1 (int _n) : n (_n) { ++obj_count; } + MyClass1 (const MyClass1 &other) : n (other.n) { ++obj_count; } + MyClass1 &operator= (const MyClass1 &other) { n = other.n; return *this; } + ~MyClass1 () { --obj_count; } + int n; + bool operator== (const MyClass1 &other) const { return n == other.n; } + bool operator< (const MyClass1 &other) const { return n < other.n; } +}; + +} + +template +static std::string l2s (const tl::slist &l) +{ + std::string x; + for (typename tl::slist::const_iterator i = l.begin (); i != l.end (); ++i) { + if (!x.empty ()) { + x += ","; + } + x += tl::to_string (i->n); + } + return x; +} + +template +static std::string l2s_nc (tl::slist &l) +{ + std::string x; + for (typename tl::slist::iterator i = l.begin (); i != l.end (); ++i) { + if (!x.empty ()) { + x += ","; + } + x += tl::to_string (i->n); + } + return x; +} + +TEST(1_Basic) +{ + obj_count = 0; + + { + MyClass1 c1 (-1); + tl::slist l1, l2; + + EXPECT_EQ (l1.empty (), true); + EXPECT_EQ (l1.size (), size_t (0)); + EXPECT_EQ (l2s (l1), ""); + + l1.push_back (MyClass1 (17)); + EXPECT_EQ (l1.empty (), false); + EXPECT_EQ (l1.size (), size_t (1)); + EXPECT_EQ (l2s (l1), "17"); + + l1.push_back (MyClass1 (42)); + l2 = l1; + tl::slist l3 (l2); + EXPECT_EQ (l1.empty (), false); + EXPECT_EQ (l1.size (), size_t (2)); + EXPECT_EQ (l2s (l1), "17,42"); + + l1.pop_front (); + EXPECT_EQ (l1.empty (), false); + EXPECT_EQ (l1.size (), size_t (1)); + EXPECT_EQ (l2s (l1), "42"); + + l1.clear (); + EXPECT_EQ (l1.empty (), true); + EXPECT_EQ (l1.size (), size_t (0)); + EXPECT_EQ (l2s (l1), ""); + + EXPECT_EQ (l2s (l2), "17,42"); + l2.pop_front (); + EXPECT_EQ (l2s (l2), "42"); + + l3.push_back (MyClass1 (2)); + l3.push_front (MyClass1 (1)); + EXPECT_EQ (l2s (l3), "1,17,42,2"); + EXPECT_EQ (l2s_nc (l3), "1,17,42,2"); + EXPECT_EQ (l3.size (), size_t (4)); + + l3.pop_front (); + EXPECT_EQ (l2s (l3), "17,42,2"); + EXPECT_EQ (l3.size (), size_t (3)); + + c1 = l3.front (); + EXPECT_EQ (c1.n, 17); + + c1 = l3.back (); + EXPECT_EQ (c1.n, 2); + + l3.pop_front (); + EXPECT_EQ (l2s (l3), "42,2"); + EXPECT_EQ (l3.size (), size_t (2)); + + l3.push_back (MyClass1 (1)); + EXPECT_EQ (l2s (l3), "42,2,1"); + EXPECT_EQ (l3.size (), size_t (3)); + + l3.swap (l2); + EXPECT_EQ (l2s (l2), "42,2,1"); + EXPECT_EQ (l2s (l3), "42"); + + l1.clear (); + l2.swap (l1); + EXPECT_EQ (l2s (l1), "42,2,1"); + EXPECT_EQ (l2s (l2), ""); + + l1.clear (); + l3.clear (); + + l2.swap (l1); + EXPECT_EQ (l2s (l1), ""); + EXPECT_EQ (l2s (l2), ""); + } + + EXPECT_EQ (obj_count, size_t (0)); +} + +TEST(2_SpliceAndMove) +{ + obj_count = 0; + + { + tl::slist l1, l2; + + l1.splice (l2); + EXPECT_EQ (l2s (l1), ""); + + l1.push_back (MyClass1 (17)); + l1.push_back (MyClass1 (42)); + + l1.splice (l2); + EXPECT_EQ (l2s (l1), "17,42"); + EXPECT_EQ (l2s (l2), ""); + l2.splice (l1); + EXPECT_EQ (l2s (l2), "17,42"); + EXPECT_EQ (l2s (l1), ""); + + l1.swap (l2); + + l2.push_back (MyClass1 (2)); + l2.push_back (MyClass1 (1)); + + l1.splice (l2); + EXPECT_EQ (l2s (l1), "17,42,2,1"); + EXPECT_EQ (l2s (l2), ""); + + l2 = std::move (l1); + EXPECT_EQ (l2s (l2), "17,42,2,1"); + EXPECT_EQ (l2s (l1), ""); + + l1 = tl::slist (std::move (l2)); + EXPECT_EQ (l2s (l1), "17,42,2,1"); + EXPECT_EQ (l2s (l2), ""); + } + + EXPECT_EQ (obj_count, size_t (0)); +} diff --git a/src/tl/unit_tests/unit_tests.pro b/src/tl/unit_tests/unit_tests.pro index 692ba586e..c648dcb1b 100644 --- a/src/tl/unit_tests/unit_tests.pro +++ b/src/tl/unit_tests/unit_tests.pro @@ -39,6 +39,7 @@ SOURCES = \ tlThreadsTests.cc \ tlUniqueIdTests.cc \ tlListTests.cc \ + tlSListTests.cc \ tlEquivalenceClustersTests.cc \ tlUniqueNameTests.cc \ tlGlobPatternTests.cc \ From 2601f870ec25457696960aed15225d7b279e106f Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 5 Dec 2022 02:28:08 +0100 Subject: [PATCH 09/21] Fixed compile errors --- src/db/db/dbHierNetworkProcessor.h | 461 ++++++++++++----------------- src/tl/tl/tlSList.h | 6 +- 2 files changed, 197 insertions(+), 270 deletions(-) diff --git a/src/db/db/dbHierNetworkProcessor.h b/src/db/db/dbHierNetworkProcessor.h index 2c6b10cbd..424f3313f 100644 --- a/src/db/db/dbHierNetworkProcessor.h +++ b/src/db/db/dbHierNetworkProcessor.h @@ -32,6 +32,7 @@ #include "dbInstElement.h" #include "tlEquivalenceClusters.h" #include "tlAssert.h" +#include "tlSList.h" #include #include @@ -211,273 +212,6 @@ private: edge_connectivity_type m_ec; }; -/** - * @brief The instance information for a cluster - */ -class DB_PUBLIC ClusterInstElement -{ -public: - ClusterInstElement (const db::InstElement &ie) - { - if (ie.array_inst.at_end ()) { - - m_inst_cell_index = std::numeric_limits::max (); - m_inst_trans = db::ICplxTrans (); - m_inst_prop_id = 0; - - } else { - - m_inst_cell_index = ie.inst_ptr.cell_index (); - m_inst_trans = ie.complex_trans (); - m_inst_prop_id = ie.inst_ptr.prop_id (); - - } - } - - ClusterInstElement (db::cell_index_type inst_cell_index, const db::ICplxTrans &inst_trans, db::properties_id_type inst_prop_id) - : m_inst_cell_index (inst_cell_index), m_inst_trans (inst_trans), m_inst_prop_id (inst_prop_id) - { - // .. nothing yet .. - } - - ClusterInstElement () - : m_inst_cell_index (std::numeric_limits::max ()), m_inst_trans (), m_inst_prop_id (0) - { - // .. nothing yet .. - } - - /** - * @brief Returns true, if the cluster does not have an instance - */ - bool has_instance () const - { - return m_inst_cell_index != std::numeric_limits::max (); - } - - /** - * @brief Gets the cell index of the cell which is instantiated - */ - db::cell_index_type inst_cell_index () const - { - return m_inst_cell_index; - } - - /** - * @brief Gets the instance transformation - */ - const db::ICplxTrans &inst_trans () const - { - return m_inst_trans; - } - - /** - * @brief Gets the instance properties id - */ - db::properties_id_type inst_prop_id () const - { - return m_inst_prop_id; - } - - /** - * @brief Sets the instance properties id - */ - void set_inst_prop_id (db::properties_id_type pid) - { - m_inst_prop_id = pid; - } - - /** - * @brief Transform with the given transformation - */ - void transform (const db::ICplxTrans &tr) - { - m_inst_trans = tr * m_inst_trans; - } - - /** - * @brief Equality - */ - bool operator== (const ClusterInstElement &other) const - { - return m_inst_cell_index == other.m_inst_cell_index && m_inst_trans.equal (other.m_inst_trans) && m_inst_prop_id == other.m_inst_prop_id; - } - - /** - * @brief Inequality - */ - bool operator!= (const ClusterInstElement &other) const - { - return ! operator== (other); - } - - /** - * @brief Less operator - */ - bool operator< (const ClusterInstElement &other) const - { - if (m_inst_cell_index != other.m_inst_cell_index) { - return m_inst_cell_index < other.m_inst_cell_index; - } - if (! m_inst_trans.equal (other.m_inst_trans)) { - return m_inst_trans.less (other.m_inst_trans); - } - return m_inst_prop_id < other.m_inst_prop_id; - } - -private: - db::cell_index_type m_inst_cell_index; - db::ICplxTrans m_inst_trans; - db::properties_id_type m_inst_prop_id; -}; - -/** - * @brief A connection to a cluster in a child instance - */ -class DB_PUBLIC ClusterInstance - : public ClusterInstElement -{ -public: - ClusterInstance (size_t id, db::cell_index_type inst_cell_index, const db::ICplxTrans &inst_trans, db::properties_id_type inst_prop_id) - : ClusterInstElement (inst_cell_index, inst_trans, inst_prop_id), m_id (id) - { - // .. nothing yet .. - } - - ClusterInstance (size_t id, const db::InstElement &inst_element) - : ClusterInstElement (inst_element), m_id (id) - { - // .. nothing yet .. - } - - ClusterInstance (size_t id) - : ClusterInstElement (), m_id (id) - { - // .. nothing yet .. - } - - ClusterInstance () - : ClusterInstElement (), m_id (0) - { - // .. nothing yet .. - } - - /** - * @brief Gets the cluster ID - */ - size_t id () const - { - return m_id; - } - - /** - * @brief Equality - */ - bool operator== (const ClusterInstance &other) const - { - return m_id == other.m_id && ClusterInstElement::operator== (other); - } - - /** - * @brief Inequality - */ - bool operator!= (const ClusterInstance &other) const - { - return ! operator== (other); - } - - /** - * @brief Less operator - */ - bool operator< (const ClusterInstance &other) const - { - if (m_id != other.m_id) { - return m_id < other.m_id; - } - return ClusterInstElement::operator< (other); - } - -private: - size_t m_id; -}; - -/** - * @brief A class representing a list of ClusterInstance objects - * - * It is using a std::list internally, but adds fast size support for STLs which do not have that. - */ -class DB_PUBLIC ClusterInstanceList -{ -public: - typedef std::list inner_list; - typedef inner_list::iterator iterator; - typedef inner_list::const_iterator const_iterator; - - ClusterInstanceList () - : m_list (), m_size (0) - { - // .. nothing yet .. - } - - ClusterInstanceList (const ClusterInstanceList &other) - : m_list (other.m_list), m_size (other.m_size) - { - // .. nothing yet .. - } - - ClusterInstanceList (ClusterInstanceList &&other) - : m_list (other.m_list), m_size (other.m_size) - { - // .. nothing yet .. - } - - ClusterInstanceList &operator= (const ClusterInstanceList &other) - { - if (this != &other) { - m_list = other.m_list; - m_size = other.m_size; - } - return *this; - } - - iterator begin () { return m_list.begin (); } - iterator end () { return m_list.end (); } - const_iterator begin () const { return m_list.begin (); } - const_iterator end () const { return m_list.end (); } - - bool empty () const - { - return m_list.empty (); - } - - void push_back (const ClusterInstance &inst) - { - m_list.push_back (inst); - ++m_size; - } - - void push_back (ClusterInstance &&inst) - { - m_list.push_back (inst); - ++m_size; - } - - void splice (ClusterInstanceList &other) - { - m_size += other.m_size; - m_list.splice (m_list.end (), other.m_list, other.m_list.begin (), other.m_list.end ()); - other.m_size = 0; - } - - size_t size () const - { - return m_size; - } - -private: - inner_list m_list; - size_t m_size; -}; - /** * @brief Represents a cluster of shapes * @@ -863,6 +597,195 @@ inline void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int x.mem_stat (stat, purpose, cat, no_self, parent); } +/** + * @brief The instance information for a cluster + */ +class DB_PUBLIC ClusterInstElement +{ +public: + ClusterInstElement (const db::InstElement &ie) + { + if (ie.array_inst.at_end ()) { + + m_inst_cell_index = std::numeric_limits::max (); + m_inst_trans = db::ICplxTrans (); + m_inst_prop_id = 0; + + } else { + + m_inst_cell_index = ie.inst_ptr.cell_index (); + m_inst_trans = ie.complex_trans (); + m_inst_prop_id = ie.inst_ptr.prop_id (); + + } + } + + ClusterInstElement (db::cell_index_type inst_cell_index, const db::ICplxTrans &inst_trans, db::properties_id_type inst_prop_id) + : m_inst_cell_index (inst_cell_index), m_inst_trans (inst_trans), m_inst_prop_id (inst_prop_id) + { + // .. nothing yet .. + } + + ClusterInstElement () + : m_inst_cell_index (std::numeric_limits::max ()), m_inst_trans (), m_inst_prop_id (0) + { + // .. nothing yet .. + } + + /** + * @brief Returns true, if the cluster does not have an instance + */ + bool has_instance () const + { + return m_inst_cell_index != std::numeric_limits::max (); + } + + /** + * @brief Gets the cell index of the cell which is instantiated + */ + db::cell_index_type inst_cell_index () const + { + return m_inst_cell_index; + } + + /** + * @brief Gets the instance transformation + */ + const db::ICplxTrans &inst_trans () const + { + return m_inst_trans; + } + + /** + * @brief Gets the instance properties id + */ + db::properties_id_type inst_prop_id () const + { + return m_inst_prop_id; + } + + /** + * @brief Sets the instance properties id + */ + void set_inst_prop_id (db::properties_id_type pid) + { + m_inst_prop_id = pid; + } + + /** + * @brief Transform with the given transformation + */ + void transform (const db::ICplxTrans &tr) + { + m_inst_trans = tr * m_inst_trans; + } + + /** + * @brief Equality + */ + bool operator== (const ClusterInstElement &other) const + { + return m_inst_cell_index == other.m_inst_cell_index && m_inst_trans.equal (other.m_inst_trans) && m_inst_prop_id == other.m_inst_prop_id; + } + + /** + * @brief Inequality + */ + bool operator!= (const ClusterInstElement &other) const + { + return ! operator== (other); + } + + /** + * @brief Less operator + */ + bool operator< (const ClusterInstElement &other) const + { + if (m_inst_cell_index != other.m_inst_cell_index) { + return m_inst_cell_index < other.m_inst_cell_index; + } + if (! m_inst_trans.equal (other.m_inst_trans)) { + return m_inst_trans.less (other.m_inst_trans); + } + return m_inst_prop_id < other.m_inst_prop_id; + } + +private: + db::cell_index_type m_inst_cell_index; + db::ICplxTrans m_inst_trans; + db::properties_id_type m_inst_prop_id; +}; + +/** + * @brief A connection to a cluster in a child instance + */ +class DB_PUBLIC ClusterInstance + : public ClusterInstElement +{ +public: + ClusterInstance (size_t id, db::cell_index_type inst_cell_index, const db::ICplxTrans &inst_trans, db::properties_id_type inst_prop_id) + : ClusterInstElement (inst_cell_index, inst_trans, inst_prop_id), m_id (id) + { + // .. nothing yet .. + } + + ClusterInstance (size_t id, const db::InstElement &inst_element) + : ClusterInstElement (inst_element), m_id (id) + { + // .. nothing yet .. + } + + ClusterInstance (size_t id) + : ClusterInstElement (), m_id (id) + { + // .. nothing yet .. + } + + ClusterInstance () + : ClusterInstElement (), m_id (0) + { + // .. nothing yet .. + } + + /** + * @brief Gets the cluster ID + */ + size_t id () const + { + return m_id; + } + + /** + * @brief Equality + */ + bool operator== (const ClusterInstance &other) const + { + return m_id == other.m_id && ClusterInstElement::operator== (other); + } + + /** + * @brief Inequality + */ + bool operator!= (const ClusterInstance &other) const + { + return ! operator== (other); + } + + /** + * @brief Less operator + */ + bool operator< (const ClusterInstance &other) const + { + if (m_id != other.m_id) { + return m_id < other.m_id; + } + return ClusterInstElement::operator< (other); + } + +private: + size_t m_id; +}; + typedef std::list > cluster_instance_pair_list_type; inline bool equal_array_delegates (const db::ArrayBase *a, const db::ArrayBase *b) @@ -1118,7 +1041,7 @@ public: private: typename local_clusters::const_iterator m_lc_iter; - typedef ClusterInstanceList connections_type; + typedef tl::slist connections_type; typename std::map::id_type, connections_type>::const_iterator m_x_iter, m_x_iter_end; }; @@ -1138,7 +1061,7 @@ class DB_PUBLIC_TEMPLATE connected_clusters { public: typedef typename local_clusters::id_type id_type; - typedef ClusterInstanceList connections_type; + typedef tl::slist connections_type; typedef typename local_clusters::box_type box_type; typedef connected_clusters_iterator all_iterator; typedef typename std::map::id_type, connections_type>::const_iterator connections_iterator; diff --git a/src/tl/tl/tlSList.h b/src/tl/tl/tlSList.h index 44d16611c..5e170ead7 100644 --- a/src/tl/tl/tlSList.h +++ b/src/tl/tl/tlSList.h @@ -59,6 +59,8 @@ private: }; public: + class const_iterator; + class iterator { public: @@ -84,6 +86,7 @@ public: bool operator!= (iterator other) const { return mp_p != other.mp_p; } private: + friend class slist::const_iterator; node_type *mp_p; }; @@ -95,6 +98,7 @@ public: typedef const T &reference; typedef const T *pointer; + const_iterator (iterator i) : mp_p (i.mp_p) { } const_iterator (const node_type *p = 0) : mp_p (p) { } const_iterator operator++ () { mp_p = mp_p->next; return *this; } @@ -116,7 +120,7 @@ public: }; slist () - : mp_first (0), mp_last (0) + : mp_first (0), mp_last (0), m_size (0) { // .. nothing yet .. } From 4543eaabace3fc20442b222e3db9a1d27e2dff9d Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 5 Dec 2022 23:47:46 +0100 Subject: [PATCH 10/21] Fixed some small flaws in instance properties dialog: sort by cell name, update tree on apply --- src/edt/edt/edtInstPropertiesPage.cc | 69 +++++++++++++++++++------- src/layui/layui/layPropertiesDialog.cc | 8 +++ 2 files changed, 60 insertions(+), 17 deletions(-) diff --git a/src/edt/edt/edtInstPropertiesPage.cc b/src/edt/edt/edtInstPropertiesPage.cc index 96cb7530f..3e4f4df73 100644 --- a/src/edt/edt/edtInstPropertiesPage.cc +++ b/src/edt/edt/edtInstPropertiesPage.cc @@ -45,6 +45,53 @@ namespace edt { +// ------------------------------------------------------------------------- + +static std::string cell_name_from_sel (const edt::Service::obj_iterator &pos, edt::Service *service) +{ + if (! pos->is_cell_inst ()) { + return std::string (); + } + + const lay::CellView &cv = service->view ()->cellview (pos->cv_index ()); + + db::Layout *def_layout = &cv->layout (); + db::cell_index_type def_cell_index = pos->back ().inst_ptr.cell_index (); + std::pair dl = def_layout->defining_library (def_cell_index); + if (dl.first) { + def_layout = &dl.first->layout (); + def_cell_index = dl.second; + } + + std::pair pci = def_layout->is_pcell_instance (def_cell_index); + if (pci.first && def_layout->pcell_declaration (pci.second)) { + return def_layout->pcell_header (pci.second)->get_name (); + } else { + return def_layout->cell_name (def_cell_index); + } +} + +namespace { + +struct SelectionPtrSort +{ + SelectionPtrSort (edt::Service *service) + : mp_service (service) + { + // .. nothing yet .. + } + + bool operator() (const edt::Service::obj_iterator &a, const edt::Service::obj_iterator &b) + { + return cell_name_from_sel (a, mp_service) < cell_name_from_sel (b, mp_service); + } + +private: + edt::Service *mp_service; +}; + +} + // ------------------------------------------------------------------------- // InstPropertiesPage implementation @@ -61,6 +108,9 @@ InstPropertiesPage::InstPropertiesPage (edt::Service *service, db::Manager *mana for (edt::Service::obj_iterator s = service->selection ().begin (); s != service->selection ().end (); ++s) { m_selection_ptrs.push_back (s); } + + std::sort (m_selection_ptrs.begin (), m_selection_ptrs.end (), SelectionPtrSort (service)); + m_prop_id = 0; mp_service->clear_highlights (); @@ -249,9 +299,9 @@ InstPropertiesPage::select_entries (const std::vector &entries) std::string InstPropertiesPage::description (size_t entry) const { - std::string d; - edt::Service::obj_iterator pos = m_selection_ptrs [entry]; + std::string d = cell_name_from_sel (pos, mp_service); + if (! pos->is_cell_inst ()) { return d; } @@ -259,21 +309,6 @@ InstPropertiesPage::description (size_t entry) const const lay::CellView &cv = mp_service->view ()->cellview (pos->cv_index ()); double dbu = cv->layout ().dbu (); - db::Layout *def_layout = &cv->layout (); - db::cell_index_type def_cell_index = pos->back ().inst_ptr.cell_index (); - std::pair dl = def_layout->defining_library (def_cell_index); - if (dl.first) { - def_layout = &dl.first->layout (); - def_cell_index = dl.second; - } - - std::pair pci = def_layout->is_pcell_instance (def_cell_index); - if (pci.first && def_layout->pcell_declaration (pci.second)) { - d += def_layout->pcell_header (pci.second)->get_name (); - } else { - d += def_layout->cell_name (def_cell_index); - } - db::ICplxTrans t (pos->back ().inst_ptr.complex_trans ()); db::DCplxTrans dt = db::CplxTrans (dbu) * t * db::CplxTrans (dbu).inverted (); diff --git a/src/layui/layui/layPropertiesDialog.cc b/src/layui/layui/layPropertiesDialog.cc index 84b867137..49423c928 100644 --- a/src/layui/layui/layPropertiesDialog.cc +++ b/src/layui/layui/layPropertiesDialog.cc @@ -153,6 +153,11 @@ public: } } + void emit_data_changed () + { + emit dataChanged (index (0, 0, QModelIndex ()), index (rowCount (QModelIndex ()) - 1, columnCount (QModelIndex ()) - 1, QModelIndex ())); + } + private: PropertiesDialog *mp_dialog; int m_icon_width, m_icon_height; @@ -566,6 +571,9 @@ BEGIN_PROTECTED m_transaction_id = t.id (); } + // updates cell names in instances for example + mp_tree_model->emit_data_changed (); + END_PROTECTED } From dc6408a0680cd6bd07764d55485b3d6539913a1e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 6 Dec 2022 18:44:29 +0100 Subject: [PATCH 11/21] Some cleanup --- src/db/db/dbAsIfFlatRegion.cc | 1 - src/db/db/dbCompoundOperation.cc | 10 +++++----- src/db/db/dbRegionLocalOperations.cc | 9 ++++++--- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index be42a4843..11d770c69 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -1070,7 +1070,6 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons, #if defined(USE_LOCAL_PROCESSOR) bool needs_merged_primary = different_polygons || options.needs_merged (); -needs_merged_primary = true; // @@@ db::RegionIterator polygons (needs_merged_primary ? begin_merged () : begin ()); bool primary_is_merged = ! merged_semantics () || needs_merged_primary || is_merged (); diff --git a/src/db/db/dbCompoundOperation.cc b/src/db/db/dbCompoundOperation.cc index 11122a2ae..3bfbfada9 100644 --- a/src/db/db/dbCompoundOperation.cc +++ b/src/db/db/dbCompoundOperation.cc @@ -1561,7 +1561,7 @@ CompoundRegionCheckOperationNode::CompoundRegionCheckOperationNode (CompoundRegi tl_assert (input == 0); // input is a dummy parameter m_has_other = other->has_external_inputs (); -// @@@ needs a concept to deal with merged/non-merged inputs + // TODO: needs a concept to deal with merged/non-merged inputs m_is_other_merged = other->is_merged (); set_description ("check"); @@ -1588,8 +1588,8 @@ CompoundRegionCheckOperationNode::computed_dist () const void CompoundRegionCheckOperationNode::do_compute_local (CompoundRegionOperationCache * /*cache*/, db::Layout *layout, const shape_interactions &interactions, std::vector > &results, size_t max_vertex_count, double area_ratio) const { -// @@@ needs a concept to deal with merged/non-merged primary -bool is_merged = true; + // TODO: needs a concept to deal with merged/non-merged inputs + bool is_merged = true; db::check_local_operation op (m_check, m_different_polygons, is_merged, m_has_other, m_is_other_merged, m_options); tl_assert (results.size () == 1); @@ -1606,8 +1606,8 @@ bool is_merged = true; void CompoundRegionCheckOperationNode::do_compute_local (CompoundRegionOperationCache * /*cache*/, db::Layout *layout, const shape_interactions &interactions, std::vector > &results, size_t max_vertex_count, double area_ratio) const { -// @@@ needs a concept to deal with merged/non-merged primary -bool is_merged = true; + // TODO: needs a concept to deal with merged/non-merged inputs + bool is_merged = true; db::check_local_operation op (m_check, m_different_polygons, is_merged, m_has_other, m_is_other_merged, m_options); tl_assert (results.size () == 1); diff --git a/src/db/db/dbRegionLocalOperations.cc b/src/db/db/dbRegionLocalOperations.cc index f1d543a62..0f439efc7 100644 --- a/src/db/db/dbRegionLocalOperations.cc +++ b/src/db/db/dbRegionLocalOperations.cc @@ -317,7 +317,7 @@ check_local_operation::do_compute_local (db::Layout *layout, const shape ++nn; } -// @@@ Use edges directly + // TODO: Use edges directly polygons.clear (); db::polygon_ref_generator ps (layout, polygons); @@ -402,7 +402,7 @@ check_local_operation::do_compute_local (db::Layout *layout, const shape ++nn; } -// @@@ Use edges directly + // TODO: Use edges directly spolygons.clear (); db::polygon_ref_generator ps (layout, spolygons); @@ -836,7 +836,10 @@ void interacting_local_operation::do_compute_local (db::Layout * /*l } - tl_assert (nstart > 0); + if (nstart == 0) { + // should not happen - but for safety we return here. + return; + } db::InteractionDetector id (m_mode, nstart - 1); id.set_include_touching (m_touching); From 4281cde169036a484657f125f859b504fb131e1b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 6 Dec 2022 22:40:41 +0100 Subject: [PATCH 12/21] (maybe) fix builds for Qt without SSL --- src/tl/tl/tlHttpStreamQt.cc | 4 ++++ src/tl/tl/tlHttpStreamQt.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/tl/tl/tlHttpStreamQt.cc b/src/tl/tl/tlHttpStreamQt.cc index c3e198102..97f261952 100644 --- a/src/tl/tl/tlHttpStreamQt.cc +++ b/src/tl/tl/tlHttpStreamQt.cc @@ -263,7 +263,9 @@ InputHttpStreamPrivateData::InputHttpStreamPrivateData (InputHttpStream *stream, s_auth_handler = new AuthenticationHandler (); connect (s_network_manager, SIGNAL (authenticationRequired (QNetworkReply *, QAuthenticator *)), s_auth_handler, SLOT (authenticationRequired (QNetworkReply *, QAuthenticator *))); connect (s_network_manager, SIGNAL (proxyAuthenticationRequired (const QNetworkProxy &, QAuthenticator *)), s_auth_handler, SLOT (proxyAuthenticationRequired (const QNetworkProxy &, QAuthenticator *))); +#if !defined(QT_NO_SSL) connect (s_network_manager, SIGNAL (sslErrors (QNetworkReply *, const QList &)), this, SLOT (sslErrors (QNetworkReply *, const QList &))); +#endif tl::StaticObjects::reg (&s_network_manager); tl::StaticObjects::reg (&s_auth_handler); @@ -515,6 +517,7 @@ InputHttpStreamPrivateData::read (char *b, size_t n) return data.size (); } +#if !defined(QT_NO_SSL) void InputHttpStreamPrivateData::sslErrors (QNetworkReply *, const QList &errors) { @@ -528,6 +531,7 @@ InputHttpStreamPrivateData::sslErrors (QNetworkReply *, const QList & m_ssl_errors += "\""; } } +#endif void InputHttpStreamPrivateData::reset () diff --git a/src/tl/tl/tlHttpStreamQt.h b/src/tl/tl/tlHttpStreamQt.h index b3f5d7885..018571260 100644 --- a/src/tl/tl/tlHttpStreamQt.h +++ b/src/tl/tl/tlHttpStreamQt.h @@ -108,7 +108,9 @@ public: private slots: void finished (QNetworkReply *); void resend (); +#if !defined(QT_NO_SSL) void sslErrors (QNetworkReply *reply, const QList &errors); +#endif private: std::string m_url; From 53dd0ba22ed8c70439c43e80579d53ecbe35b34d Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 7 Dec 2022 00:51:03 +0100 Subject: [PATCH 13/21] Updated Changelog --- Changelog | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 128 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index 8f786d3f7..3d7eba745 100644 --- a/Changelog +++ b/Changelog @@ -1,5 +1,132 @@ +0.28 +Changes (list may not be complete): +* Bugfix: %GITHUB%/issues/989 "Layout#convert_pcell_to_static" does not handle"defunct" cells +* Bugfix: %GITHUB%/issues/991 Basic library not available in Python module +* Bugfix: %GITHUB%/issues/1059 Cleanup of PCell orphans after re-evaluation on load +* Bugfix: %GITHUB%/issues/1081 Using a layer properties file from recent list without layout loaded crashes KLayout +* Bugfix: %GITHUB%/issues/1138 Provide a way to suppress or redirect log output or disable warnings, specifically from file readers, in Python module +* Bugfix: %GITHUB%/issues/1178 technology-data xml results in SEGV +* Bugfix: %GITHUB%/issues/1190 General compatibility issue of Edges#extended/extended_* with deep mode +* Enhacnement: %GITHUB%/issues/1056 X2 net names +* Enhancement: %GITHUB%/issues/1052 Pdf documentation +* Enhancement: %GITHUB%/issues/1053 Lefdef enhancements +* Enhancement: Support for Qt6 +* Enhancement: KLayout paths + - $KLAYOUT_HOME can now be empty string (no home folder used) + - $KLAYOUT_PATH can now be empty string (no further and implicit search paths) +* Enhancement: Python typehints + - Python include files are generated for Python module +* Enhancement: Properties dialog now features object list on left side (select and change) +* Enhancement: Compute area and perimeter from selection (Edit/Selection/Area and Perimeter) +* Enhancement: Callbacks for PCells + - Allow dynamic change of some attributes (visibility, enabled etc.) + - By implementing "callback_impl" in PCellDeclarationHelper subclasses +* Enhancement: Report browser + - Shape user properties are turned into RDB values + - Scanning of text objects +* Enhancement: Support for high-DPI modes (scale factor 200%) + - "Highres" option to fully exploit resolution, normally follows screen scaling +* Enhancement: Multiple tech stacks for net tracer per technology +* Enhancement: New rulers + - Angle + - Radius (%GITHUB%/issues/906) + - Multi-segment +* Enhancement: LVS + - Generates a log view which may have useful hints + - Schematic and extracted netlists are available as separate tabs for LVS view +* Enhancement: DRC + - Antenna DRC measured values output on edge pair properties and into report file + - inside, not_inside, outside and not_outside also for edge/edge and edge/polygon layers + - split_inside, split_outside for edge/edge and edge/polygon layers + - andnot (edge/edge) + - inside_outside_part (edge/polygon) + - angle-class selectors (multiples or 90 or 45 degree) + - performance enhancements + - in_and_out (edge and polygon layers) +* Enhancement: "data:" URL schemes to pass direct base-64 encoded data +* Enhancement: "Close all except", "left of", "right of" etc. in layout tabs and macro editor tabs +* Enhancmennt: Drop-down list to select tab in layout views +* Enhancement: Setting for disabling "Save needed" dialog box +* Enhancement: File details are shown (dump of file header) for unknown file formats +* Enhancement: NoQt option for LayoutView + - PixelBuffer object instead of QImage + - LayoutView can be build without Qt + - Functions exist to emulate mouse events + - Included in standalone Python module + - Allows implementation of KLayout backend in web server +* Enhancement: New command "-rr" (like -r but keeps application running, for UI macros) +* Enhancement: PCell errors are shown on a special error layer which is visible together with guiding shapes +* Enhancement: custom queries support micron-unit attributes (dbbox, path_dtrans etc.) +* Enhancement: custom queries highlight results of queries when selected +* Enhancement: scale and snap improvements (edge pair support, properties maintained, arrays not always flattened) +* Enhancement: auto-run macros can not be given a priority in which they are executed +* Enhancement: D25 module overhauled + - Uses a DRC subset to generate layers + - Allows booleans and specific color assignments + - Supports edges and edge pairs (will build walls) + - Not backward compatible! +* Python/Ruby API: + - DText/Text: bbox, alignment enums + - Polygon#size with vector arguments + - DBox/Box#world + - Layout#unique_cell_name + - RecursiveShapeIterator#each, RecursiveInstanceIterator#each + - Layout#clip with DBox and Cell arguments + - Better automatic conversion of enum to int and vice versa + - CellInstArray constructor with Cell argument + - AbstractMenu#insert_menu, #clear_menu + - ActionBase#icon=, #on_menu_opening, #on_triggered + - CellMapping convinience methods + - Cell#read for easy importing of a layout into a cell + subtree + - LayerMap#map and #mmap: logical layer is optional now (needed to be incremental) + - Shapes#cell and #layout + - Edges#andnot, #split_interacting, #inside, #not_inside, #outside, #not_outside and related (for Region and Edges arguments) + - GenericDeviceExtractor#define_terminal convenience methods + - Box/DBox square and rectangle convenience constructor + - Box#enlarge convenience isotropic variant + - Region#in_and_out, Edges#in_and_out -0.28 (2022-xx-xx): +0.27.13 (2022-11-30): +* Bugfixes: + - selection did not work in non-editable mode + - partial selection did not work for guiding shapes + - compile issue: NDEBUG is not usable after ruby.h + +0.27.12 (2022-11-01): +* Bugfix: %GITHUB%/issues/1173 DXF SPLINE implementation not compatible with ezdxf +* Bugfix: %GITHUB%/issues/1167 delete_cells slow in some cases +* Bugfix: %GITHUB%/issues/1164 Deleting cells: 'basic_string: construction from null is not valid' +* Bugfix: %GITHUB%/issues/1145 Crash when clearing a Shapes container by script while a shape is selected +* Bugfix: %GITHUB%/issues/1144 Copy layer not choosing the right "new" target layer sometimes +* Bugfix: %GITHUB%/issues/1143 DBU not taken from technology by default +* Bugfix: %GITHUB%/issues/1097 Change oasis writer defaults to strict + cblocks, discourage the usage of oas.gz +* Bugfix: Incorrect behavior of some deep-mode DRC functions + - deep edges "and" with Region: incorrect behavior if region is empty or non-deep + - deep edges "inside_part" with Region: incorrect behavior if region is empty or non-deep + - deep edges "outside_part" with Region: incorrect behavior if region is empty or non-deep +* Enhancement: Python include files are now provided for the Python package. This will add type information to the methods. + +0.27.11 (2022-08-10): +* Bugfix: %GITHUB%/issues/1098 Normalize zero dimension when generating regular array instance +* Enhancement: %GITHUB%/issues/1103 Add setting to disable Save Needed dialog box +* Bugfix: %GITHUB%/issues/1106 "move by" does not move instances from partial selection +* Bugfix: %GITHUB%/issues/1111 GenericDeviceExtractor#define_opt_layer not working +* Bugfix: %GITHUB%/issues/1114 MSYS2 compatibility with latest revision (based on gcc 12.1) +* Bugfix: %GITHUB%/issues/1126 Internal error on DRC operation +* Bugfix: %GITHUB%/issues/1135 LVS mismatch on parallel devices and issue on ambiguity resolution +* Enhancement: Support for Python 3.11 +* Enhancement: L2N and LVSDB readers made compatible with potential future extensions +* Enhancement: DRC Antenna check now can be given a text layer which receives output describing the measured and computed values +* Bugfix: *= method (e.g. Point, DPoint) properly listed in help and reflection API +* Bugfixes: Fixed a number of potential segfaults due to memory corruption found during master branch refactoring + +0.27.10 (2022-06-04): +* Bugfix: %GITHUB%/issues/1081 Using a layer properties file from recent list without layout loaded crashes KLayout +* Enhancement: %GITHUB%/issues/1079 PCell update: Library#refresh should call coerce_parameters_impl +* Bugfix: %GITHUB%/issues/1075 Edit layer specification doesn't work well with PCells +* Bugfix: %GITHUB%/issues/1071 Issues with GDS text format and "Save As" +* Bugfix: %GITHUB%/issues/1068 Circle handle not shown sometimes +* Bugfixes: two potential segfaults fixed due to early delete of LayoutView and access to non-initialized memory 0.27.9 (2022-04-23): * Bugfix: %GITHUB%/issues/1008 Don't optimize away points on path edit From a9833bf32ec17559a0803bab7f69c5f7244838ff Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 7 Dec 2022 21:43:43 +0100 Subject: [PATCH 14/21] Small bugfix: do not mess up annotation templates after used older KLayout versions again. --- src/ant/ant/antPlugin.cc | 17 +++++++++++++++-- src/ant/ant/antTemplate.cc | 37 ++++++++++++++++++++++++++++++++----- src/ant/ant/antTemplate.h | 22 ++++++++++++++++++++++ 3 files changed, 69 insertions(+), 7 deletions(-) diff --git a/src/ant/ant/antPlugin.cc b/src/ant/ant/antPlugin.cc index 3545deb40..2c19ec65e 100644 --- a/src/ant/ant/antPlugin.cc +++ b/src/ant/ant/antPlugin.cc @@ -26,6 +26,7 @@ #include "layDispatcher.h" #include "layAbstractMenu.h" #include "tlColor.h" +#include "tlLog.h" #if defined(HAVE_QT) # include "layConfigurationDialog.h" #endif @@ -217,7 +218,8 @@ PluginDeclaration::initialized (lay::Dispatcher *root) bool any_missing = false; auto std_templates = make_standard_templates (); for (auto t = std_templates.begin (); ! any_missing && t != std_templates.end (); ++t) { - if (! t->category ().empty () && cat_names.find (t->category ()) == cat_names.end ()) { + if (! t->category ().empty () && + (cat_names.find (t->category ()) == cat_names.end () || cat_names.find (t->category ())->second->version () != ant::Template::current_version ())) { any_missing = true; } } @@ -225,6 +227,9 @@ PluginDeclaration::initialized (lay::Dispatcher *root) if (cat_names.empty ()) { // full initial configuration + if (tl::verbosity () >= 20) { + tl::info << "Resetting annotation templates"; + } root->config_set (cfg_ruler_templates, ant::TemplatesConverter ().to_string (make_standard_templates ())); root->config_end (); @@ -235,9 +240,12 @@ PluginDeclaration::initialized (lay::Dispatcher *root) for (auto t = std_templates.begin (); t != std_templates.end (); ++t) { if (! t->category ().empty ()) { auto tt = cat_names.find (t->category ()); - if (tt != cat_names.end ()) { + if (tt != cat_names.end () && tt->second->version () == ant::Template::current_version ()) { new_templates.push_back (*tt->second); } else { + if (tl::verbosity () >= 20) { + tl::info << "Resetting annotation template: " << t->title (); + } new_templates.push_back (*t); } } @@ -248,6 +256,11 @@ PluginDeclaration::initialized (lay::Dispatcher *root) } } + // upgrade + for (auto i = new_templates.begin (); i != new_templates.end (); ++i) { + i->version (ant::Template::current_version ()); + } + root->config_set (cfg_ruler_templates, ant::TemplatesConverter ().to_string (new_templates)); root->config_end (); diff --git a/src/ant/ant/antTemplate.cc b/src/ant/ant/antTemplate.cc index 84590a2e2..572a84214 100644 --- a/src/ant/ant/antTemplate.cc +++ b/src/ant/ant/antTemplate.cc @@ -30,6 +30,12 @@ namespace ant { +int +Template::current_version () +{ + return 1; +} + ant::Template Template::from_object (const ant::Object &a, const std::string &title, int mode) { @@ -57,7 +63,8 @@ Template::from_object (const ant::Object &a, const std::string &title, int mode) } Template::Template () - : m_title (tl::to_string (tr ("Ruler"))), + : m_version (current_version ()), + m_title (tl::to_string (tr ("Ruler"))), m_fmt_x ("$X"), m_fmt_y ("$Y"), m_fmt ("$D"), m_style (ant::Object::STY_ruler), m_outline (ant::Object::OL_diag), m_snap (true), m_angle_constraint (lay::AC_Global), @@ -74,7 +81,8 @@ Template::Template (const std::string &title, const std::string &fmt_x, const std::string &fmt_y, const std::string &fmt, style_type style, outline_type outline, bool snap, lay::angle_constraint_type angle_constraint, const std::string &cat) - : m_title (title), + : m_version (current_version ()), + m_title (title), m_category (cat), m_fmt_x (fmt_x), m_fmt_y (fmt_y), m_fmt (fmt), m_style (style), m_outline (outline), @@ -89,7 +97,8 @@ Template::Template (const std::string &title, } Template::Template (const ant::Template &d) - : m_title (d.m_title), + : m_version (d.m_version), + m_title (d.m_title), m_category (d.m_category), m_fmt_x (d.m_fmt_x), m_fmt_y (d.m_fmt_y), m_fmt (d.m_fmt), m_style (d.m_style), m_outline (d.m_outline), @@ -107,6 +116,7 @@ Template & Template::operator= (const ant::Template &d) { if (this != &d) { + m_version = d.m_version; m_title = d.m_title; m_category = d.m_category; m_fmt_x = d.m_fmt_x; @@ -132,7 +142,7 @@ std::vector