From aeeb6d7c875c7b78a54daa6a1efa2f94967ccc1c Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 9 Jan 2019 01:06:11 +0100 Subject: [PATCH] Fixed #200 by introducing layout locking during iteration The cause for the problem was that the layout got updated while iterating causing the mess within the iterator. This solution is to lock the layout while an iterator is present. This happens for various Cell and Shapes iterator, so it's a major enhancement. --- src/db/db/db.pro | 3 +- src/db/db/dbLayout.h | 27 ++++++++- src/db/db/gsiDeclDbCell.cc | 108 +++++++++++++++++++++++------------ src/db/db/gsiDeclDbHelpers.h | 83 +++++++++++++++++++++++++++ src/db/db/gsiDeclDbShapes.cc | 42 +++++++------- src/tl/tl/tlReuseVector.h | 27 +++++---- testdata/gds/t200.gds | Bin 0 -> 1354 bytes testdata/ruby/dbLayout.rb | 39 +++++++++++++ 8 files changed, 256 insertions(+), 73 deletions(-) create mode 100644 src/db/db/gsiDeclDbHelpers.h create mode 100644 testdata/gds/t200.gds diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 8c0a4e558..90b03bf16 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -208,7 +208,8 @@ HEADERS = \ dbForceLink.h \ dbPlugin.h \ dbInit.h \ - dbConverters.h + dbConverters.h \ + gsiDeclDbHelpers.h !equals(HAVE_QT, "0") { diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h index 8a1d0a591..94e5cd184 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -1725,9 +1725,32 @@ public: } } + LayoutLocker (const LayoutLocker &other) + : mp_layout (other.mp_layout) + { + if (mp_layout) { + mp_layout->start_changes (); + } + } + + LayoutLocker &operator= (const LayoutLocker &other) + { + if (this == &other) { + return *this; + } + + if (mp_layout) { + mp_layout->end_changes (); + } + mp_layout = other.mp_layout; + if (mp_layout) { + mp_layout->start_changes (); + } + + return *this; + } + private: - LayoutLocker (const LayoutLocker &); - LayoutLocker &operator= (const LayoutLocker &); db::Layout *mp_layout; }; diff --git a/src/db/db/gsiDeclDbCell.cc b/src/db/db/gsiDeclDbCell.cc index f0e3a3637..0865ab1e7 100644 --- a/src/db/db/gsiDeclDbCell.cc +++ b/src/db/db/gsiDeclDbCell.cc @@ -23,6 +23,8 @@ #include "gsiDecl.h" + +#include "gsiDeclDbHelpers.h" #include "dbLayout.h" #include "dbBoxConvert.h" #include "dbRegion.h" @@ -711,70 +713,70 @@ static void dump_mem_statistics (const db::Cell *cell, bool detailed) ms.print (); } -static db::Shapes::shape_iterator begin_shapes (const db::Cell *s, unsigned int layer_index, unsigned int flags) +static gsi::layout_locking_iterator1 begin_shapes (const db::Cell *s, unsigned int layer_index, unsigned int flags) { - return s->begin (layer_index, flags); + return gsi::layout_locking_iterator1 (s->layout (), s->begin (layer_index, flags)); } -static db::Shapes::shape_iterator begin_shapes_all (const db::Cell *s, unsigned int layer_index) +static gsi::layout_locking_iterator1 begin_shapes_all (const db::Cell *s, unsigned int layer_index) { - return s->begin (layer_index, db::ShapeIterator::All); + return gsi::layout_locking_iterator1 (s->layout (), s->begin (layer_index, db::ShapeIterator::All)); } -static db::Shapes::shape_iterator begin_touching_shapes (const db::Cell *s, unsigned int layer_index, const db::Box &box, unsigned int flags) +static gsi::layout_locking_iterator1 begin_touching_shapes (const db::Cell *s, unsigned int layer_index, const db::Box &box, unsigned int flags) { - return s->begin_touching (layer_index, box, flags); + return gsi::layout_locking_iterator1 (s->layout (), s->begin_touching (layer_index, box, flags)); } -static db::Shapes::shape_iterator begin_touching_shapes_all (const db::Cell *s, unsigned int layer_index, const db::Box &box) +static gsi::layout_locking_iterator1 begin_touching_shapes_all (const db::Cell *s, unsigned int layer_index, const db::Box &box) { - return s->begin_touching (layer_index, box, db::ShapeIterator::All); + return gsi::layout_locking_iterator1 (s->layout (), s->begin_touching (layer_index, box, db::ShapeIterator::All)); } -static db::Shapes::shape_iterator begin_overlapping_shapes (const db::Cell *s, unsigned int layer_index, const db::Box &box, unsigned int flags) +static gsi::layout_locking_iterator1 begin_overlapping_shapes (const db::Cell *s, unsigned int layer_index, const db::Box &box, unsigned int flags) { - return s->begin_overlapping (layer_index, box, flags); + return gsi::layout_locking_iterator1 (s->layout (), s->begin_overlapping (layer_index, box, flags)); } -static db::Shapes::shape_iterator begin_overlapping_shapes_all (const db::Cell *s, unsigned int layer_index, const db::Box &box) +static gsi::layout_locking_iterator1 begin_overlapping_shapes_all (const db::Cell *s, unsigned int layer_index, const db::Box &box) { - return s->begin_overlapping (layer_index, box, db::ShapeIterator::All); + return gsi::layout_locking_iterator1 (s->layout (), s->begin_overlapping (layer_index, box, db::ShapeIterator::All)); } -static db::Shapes::shape_iterator begin_touching_shapes_um (const db::Cell *s, unsigned int layer_index, const db::DBox &box, unsigned int flags) +static gsi::layout_locking_iterator1 begin_touching_shapes_um (const db::Cell *s, unsigned int layer_index, const db::DBox &box, unsigned int flags) { const db::Layout *layout = s->layout (); if (! layout) { throw tl::Exception (tl::to_string (tr ("Cell does not reside inside a layout - cannot use a micrometer search box"))); } - return s->begin_touching (layer_index, db::CplxTrans (layout->dbu ()).inverted () * box, flags); + return gsi::layout_locking_iterator1 (s->layout (), s->begin_touching (layer_index, db::CplxTrans (layout->dbu ()).inverted () * box, flags)); } -static db::Shapes::shape_iterator begin_touching_shapes_all_um (const db::Cell *s, unsigned int layer_index, const db::DBox &box) +static gsi::layout_locking_iterator1 begin_touching_shapes_all_um (const db::Cell *s, unsigned int layer_index, const db::DBox &box) { const db::Layout *layout = s->layout (); if (! layout) { throw tl::Exception (tl::to_string (tr ("Cell does not reside inside a layout - cannot use a micrometer search box"))); } - return s->begin_touching (layer_index, db::CplxTrans (layout->dbu ()).inverted () * box, db::ShapeIterator::All); + return gsi::layout_locking_iterator1 (s->layout (), s->begin_touching (layer_index, db::CplxTrans (layout->dbu ()).inverted () * box, db::ShapeIterator::All)); } -static db::Shapes::shape_iterator begin_overlapping_shapes_um (const db::Cell *s, unsigned int layer_index, const db::DBox &box, unsigned int flags) +static gsi::layout_locking_iterator1 begin_overlapping_shapes_um (const db::Cell *s, unsigned int layer_index, const db::DBox &box, unsigned int flags) { const db::Layout *layout = s->layout (); if (! layout) { throw tl::Exception (tl::to_string (tr ("Cell does not reside inside a layout - cannot use a micrometer search box"))); } - return s->begin_overlapping (layer_index, db::CplxTrans (layout->dbu ()).inverted () * box, flags); + return gsi::layout_locking_iterator1 (s->layout (), s->begin_overlapping (layer_index, db::CplxTrans (layout->dbu ()).inverted () * box, flags)); } -static db::Shapes::shape_iterator begin_overlapping_shapes_all_um (const db::Cell *s, unsigned int layer_index, const db::DBox &box) +static gsi::layout_locking_iterator1 begin_overlapping_shapes_all_um (const db::Cell *s, unsigned int layer_index, const db::DBox &box) { const db::Layout *layout = s->layout (); if (! layout) { throw tl::Exception (tl::to_string (tr ("Cell does not reside inside a layout - cannot use a micrometer search box"))); } - return s->begin_overlapping (layer_index, db::CplxTrans (layout->dbu ()).inverted () * box, db::ShapeIterator::All); + return gsi::layout_locking_iterator1 (s->layout (), s->begin_overlapping (layer_index, db::CplxTrans (layout->dbu ()).inverted () * box, db::ShapeIterator::All)); } static db::Instance insert_inst_with_props (db::Cell *c, const db::Cell::cell_inst_array_type &inst, db::properties_id_type id) @@ -1679,18 +1681,12 @@ static db::DBox cell_dbbox_per_layer (const db::Cell *cell, unsigned int layer_i return cell->bbox (layer_index) * layout->dbu (); } -static db::Cell::overlapping_iterator cell_begin_overlapping_inst_um (const db::Cell *cell, const db::DBox &db) +gsi::layout_locking_iterator1 begin_overlapping_inst (const db::Cell *cell, const db::Cell::box_type &b) { - const db::Layout *layout = cell->layout (); - if (! layout) { - throw tl::Exception (tl::to_string (tr ("Cell does not reside inside a layout - cannot use a micrometer-unit search boxes"))); - } - - db::CplxTrans dbu_trans (layout->dbu ()); - return cell->begin_overlapping (dbu_trans.inverted () * db); + return gsi::layout_locking_iterator1 (cell->layout (), cell->begin_overlapping (b)); } -static db::Cell::touching_iterator cell_begin_touching_inst_um (const db::Cell *cell, const db::DBox &db) +gsi::layout_locking_iterator1 begin_overlapping_inst_um (const db::Cell *cell, const db::DBox &dbox) { const db::Layout *layout = cell->layout (); if (! layout) { @@ -1698,7 +1694,43 @@ static db::Cell::touching_iterator cell_begin_touching_inst_um (const db::Cell * } db::CplxTrans dbu_trans (layout->dbu ()); - return cell->begin_touching (dbu_trans.inverted () * db); + return gsi::layout_locking_iterator1 (cell->layout (), cell->begin_overlapping (dbu_trans.inverted () * dbox)); +} + +gsi::layout_locking_iterator1 begin_touching_inst (const db::Cell *cell, const db::Cell::box_type &b) +{ + return gsi::layout_locking_iterator1 (cell->layout (), cell->begin_touching (b)); +} + +gsi::layout_locking_iterator1 begin_touching_inst_um (const db::Cell *cell, const db::DBox &dbox) +{ + const db::Layout *layout = cell->layout (); + if (! layout) { + throw tl::Exception (tl::to_string (tr ("Cell does not reside inside a layout - cannot use a micrometer-unit search boxes"))); + } + + db::CplxTrans dbu_trans (layout->dbu ()); + return gsi::layout_locking_iterator1 (cell->layout (), cell->begin_touching (dbu_trans.inverted () * dbox)); +} + +gsi::layout_locking_iterator1 begin_child_cells (const db::Cell *cell) +{ + return gsi::layout_locking_iterator1 (cell->layout (), cell->begin_child_cells ()); +} + +gsi::layout_locking_iterator1 begin_parent_insts (const db::Cell *cell) +{ + return gsi::layout_locking_iterator1 (cell->layout (), cell->begin_parent_insts ()); +} + +gsi::layout_locking_iterator2 begin_parent_cells (const db::Cell *cell) +{ + return gsi::layout_locking_iterator2 (cell->layout (), cell->begin_parent_cells (), cell->end_parent_cells ()); +} + +static layout_locking_iterator1 begin_inst (db::Cell *cell) +{ + return layout_locking_iterator1 (cell->layout (), cell->begin ()); } Class decl_Cell ("db", "Cell", @@ -2569,7 +2601,7 @@ Class decl_Cell ("db", "Cell", "\n" "This method has been introduced in version 0.25." ) + - gsi::iterator ("each_overlapping_inst", (db::Cell::overlapping_iterator (db::Cell::*) (const db::Cell::box_type &b) const) &db::Cell::begin_overlapping, gsi::arg ("b"), + gsi::iterator_ext ("each_overlapping_inst", &begin_overlapping_inst, gsi::arg ("b"), "@brief Gets the instances overlapping the given rectangle\n" "\n" "This will iterate over all child cell\n" @@ -2579,7 +2611,7 @@ Class decl_Cell ("db", "Cell", "\n" "Starting with version 0.15, this iterator delivers \\Instance objects rather than \\CellInstArray objects." ) + - gsi::iterator_ext ("each_overlapping_inst", &cell_begin_overlapping_inst_um, gsi::arg ("b"), + gsi::iterator_ext ("each_overlapping_inst", &begin_overlapping_inst_um, gsi::arg ("b"), "@brief Gets the instances overlapping the given rectangle, with the rectangle in micrometer units\n" "\n" "This will iterate over all child cell\n" @@ -2592,7 +2624,7 @@ Class decl_Cell ("db", "Cell", "\n" "This variant has been introduced in version 0.25." ) + - gsi::iterator ("each_touching_inst", (db::Cell::touching_iterator (db::Cell::*) (const db::Cell::box_type &b) const) &db::Cell::begin_touching, gsi::arg ("b"), + gsi::iterator_ext ("each_touching_inst", &begin_touching_inst, gsi::arg ("b"), "@brief Gets the instances touching the given rectangle\n" "\n" "This will iterate over all child cell\n" @@ -2602,7 +2634,7 @@ Class decl_Cell ("db", "Cell", "\n" "Starting with version 0.15, this iterator delivers \\Instance objects rather than \\CellInstArray objects." ) + - gsi::iterator_ext ("each_touching_inst", &cell_begin_touching_inst_um, gsi::arg ("b"), + gsi::iterator_ext ("each_touching_inst", &begin_touching_inst_um, gsi::arg ("b"), "@brief Gets the instances touching the given rectangle, with the rectangle in micrometer units\n" "\n" "This will iterate over all child cell\n" @@ -2615,7 +2647,7 @@ Class decl_Cell ("db", "Cell", "\n" "This variant has been introduced in version 0.25." ) + - gsi::iterator ("each_child_cell", &db::Cell::begin_child_cells, + gsi::iterator_ext ("each_child_cell", &begin_child_cells, "@brief Iterates over all child cells\n" "\n" "This iterator will report the child cell indices, not every instance.\n" @@ -2626,12 +2658,12 @@ Class decl_Cell ("db", "Cell", "The number of child cells (not child instances!) is returned.\n" "CAUTION: this method is SLOW, in particular if many instances are present.\n" ) + - gsi::iterator ("each_inst", (db::Cell::const_iterator (db::Cell::*) () const) &db::Cell::begin, + gsi::iterator_ext ("each_inst", &begin_inst, "@brief Iterates over all child instances (which may actually be instance arrays)\n" "\n" "Starting with version 0.15, this iterator delivers \\Instance objects rather than \\CellInstArray objects." ) + - gsi::iterator ("each_parent_inst", &db::Cell::begin_parent_insts, + gsi::iterator_ext ("each_parent_inst", &begin_parent_insts, "@brief Iterates over the parent instance list (which may actually be instance arrays)\n" "\n" "The parent instances are basically inversions of the instances. Using parent instances " @@ -2642,7 +2674,7 @@ Class decl_Cell ("db", "Cell", "\n" "The number of parent cells (cells which reference our cell) is reported." ) + - gsi::iterator ("each_parent_cell", &db::Cell::begin_parent_cells, &db::Cell::end_parent_cells, + gsi::iterator_ext ("each_parent_cell", &begin_parent_cells, "@brief Iterates over all parent cells\n" "\n" "This iterator will iterate over the parent cells, just returning their\n" diff --git a/src/db/db/gsiDeclDbHelpers.h b/src/db/db/gsiDeclDbHelpers.h new file mode 100644 index 000000000..22b5f5e50 --- /dev/null +++ b/src/db/db/gsiDeclDbHelpers.h @@ -0,0 +1,83 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2019 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_gsiDeclDbHelpers +#define HDR_gsiDeclDbHelpers + +#include "dbLayoutUtils.h" + +namespace gsi +{ + /** + * @brief A safe iterator locking the layout while iterating a container within it + */ + template + class layout_locking_iterator2 + : private db::LayoutLocker + { + public: + typedef typename I::value_type value_type; + typedef typename I::reference reference; + typedef typename I::pointer pointer; + typedef typename I::difference_type difference_type; + typedef typename I::iterator_category iterator_category; + + layout_locking_iterator2 (const db::Layout *layout, const I &b, const I &e) : db::LayoutLocker (const_cast (layout)), m_b (b), m_e (e) {} + bool at_end () const { return m_b == m_e; } + void operator++ () { ++m_b; } + + reference operator* () const { return *m_b; } + pointer operator-> () const { return m_b.operator-> (); } + + private: + I m_b, m_e; + }; + + /** + * @brief A safe iterator locking the layout while iterating a container within it + */ + template + class layout_locking_iterator1 + : private db::LayoutLocker + { + public: + typedef typename I::value_type value_type; + typedef typename I::reference reference; + typedef typename I::pointer pointer; + typedef typename I::difference_type difference_type; + typedef typename I::iterator_category iterator_category; + + layout_locking_iterator1 (const db::Layout *layout, const I &i) : db::LayoutLocker (const_cast (layout)), m_i (i) { } + bool at_end () const { return m_i.at_end (); } + void operator++ () { ++m_i; } + + reference operator* () const { return *m_i; } + pointer operator-> () const { return m_i.operator-> (); } + + private: + I m_i; + }; + +} + +#endif diff --git a/src/db/db/gsiDeclDbShapes.cc b/src/db/db/gsiDeclDbShapes.cc index 05d8a5217..19b7661be 100644 --- a/src/db/db/gsiDeclDbShapes.cc +++ b/src/db/db/gsiDeclDbShapes.cc @@ -22,6 +22,8 @@ #include "gsiDecl.h" + +#include "gsiDeclDbHelpers.h" #include "dbShapes.h" #include "dbShape.h" #include "dbLayout.h" @@ -101,54 +103,54 @@ static db::Shape dinsert_with_properties (db::Shapes *s, const Sh &p, db::proper return s->insert (db::object_with_properties (db::CplxTrans (shapes_dbu (s)).inverted () * p, id)); } -static db::Shapes::shape_iterator begin (const db::Shapes *s, unsigned int flags) +static gsi::layout_locking_iterator1 begin (const db::Shapes *s, unsigned int flags) { - return s->begin (flags); + return gsi::layout_locking_iterator1 (s->layout (), s->begin (flags)); } -static db::Shapes::shape_iterator begin_all (const db::Shapes *s) +static gsi::layout_locking_iterator1begin_all (const db::Shapes *s) { - return s->begin (db::ShapeIterator::All); + return gsi::layout_locking_iterator1 (s->layout (), s->begin (db::ShapeIterator::All)); } -static db::Shapes::shape_iterator begin_overlapping (const db::Shapes *s, unsigned int flags, const db::Box ®ion) +static gsi::layout_locking_iterator1begin_overlapping (const db::Shapes *s, unsigned int flags, const db::Box ®ion) { - return s->begin_overlapping (region, flags); + return gsi::layout_locking_iterator1 (s->layout (), s->begin_overlapping (region, flags)); } -static db::Shapes::shape_iterator begin_doverlapping (const db::Shapes *s, unsigned int flags, const db::DBox ®ion) +static gsi::layout_locking_iterator1begin_doverlapping (const db::Shapes *s, unsigned int flags, const db::DBox ®ion) { - return s->begin_overlapping (db::CplxTrans (shapes_dbu (s)).inverted () * region, flags); + return gsi::layout_locking_iterator1 (s->layout (), s->begin_overlapping (db::CplxTrans (shapes_dbu (s)).inverted () * region, flags)); } -static db::Shapes::shape_iterator begin_overlapping_all (const db::Shapes *s, const db::Box ®ion) +static gsi::layout_locking_iterator1begin_overlapping_all (const db::Shapes *s, const db::Box ®ion) { - return s->begin_overlapping (region, db::ShapeIterator::All); + return gsi::layout_locking_iterator1 (s->layout (), s->begin_overlapping (region, db::ShapeIterator::All)); } -static db::Shapes::shape_iterator begin_doverlapping_all (const db::Shapes *s, const db::DBox ®ion) +static gsi::layout_locking_iterator1begin_doverlapping_all (const db::Shapes *s, const db::DBox ®ion) { - return s->begin_overlapping (db::CplxTrans (shapes_dbu (s)).inverted () * region, db::ShapeIterator::All); + return gsi::layout_locking_iterator1 (s->layout (), s->begin_overlapping (db::CplxTrans (shapes_dbu (s)).inverted () * region, db::ShapeIterator::All)); } -static db::Shapes::shape_iterator begin_touching (const db::Shapes *s, unsigned int flags, const db::Box ®ion) +static gsi::layout_locking_iterator1begin_touching (const db::Shapes *s, unsigned int flags, const db::Box ®ion) { - return s->begin_touching (region, flags); + return gsi::layout_locking_iterator1 (s->layout (), s->begin_touching (region, flags)); } -static db::Shapes::shape_iterator begin_dtouching (const db::Shapes *s, unsigned int flags, const db::DBox ®ion) +static gsi::layout_locking_iterator1begin_dtouching (const db::Shapes *s, unsigned int flags, const db::DBox ®ion) { - return s->begin_touching (db::CplxTrans (shapes_dbu (s)).inverted () * region, flags); + return gsi::layout_locking_iterator1 (s->layout (), s->begin_touching (db::CplxTrans (shapes_dbu (s)).inverted () * region, flags)); } -static db::Shapes::shape_iterator begin_touching_all (const db::Shapes *s, const db::Box ®ion) +static gsi::layout_locking_iterator1begin_touching_all (const db::Shapes *s, const db::Box ®ion) { - return s->begin_touching (region, db::ShapeIterator::All); + return gsi::layout_locking_iterator1 (s->layout (), s->begin_touching (region, db::ShapeIterator::All)); } -static db::Shapes::shape_iterator begin_dtouching_all (const db::Shapes *s, const db::DBox ®ion) +static gsi::layout_locking_iterator1begin_dtouching_all (const db::Shapes *s, const db::DBox ®ion) { - return s->begin_touching (db::CplxTrans (shapes_dbu (s)).inverted () * region, db::ShapeIterator::All); + return gsi::layout_locking_iterator1 (s->layout (), s->begin_touching (db::CplxTrans (shapes_dbu (s)).inverted () * region, db::ShapeIterator::All)); } static void transform_shapes (db::Shapes *s, const db::Trans &trans) diff --git a/src/tl/tl/tlReuseVector.h b/src/tl/tl/tlReuseVector.h index f31236a3a..c7cad2b69 100644 --- a/src/tl/tl/tlReuseVector.h +++ b/src/tl/tl/tlReuseVector.h @@ -887,6 +887,21 @@ public: init (); } + /** + * @brief Returns a value indicating whether the given index is valid + */ + bool is_used (size_type n) const + { + if (n >= first () && n < last ()) { + if (mp_rdata) { + return mp_rdata->is_used (n); + } else { + return true; + } + } + return false; + } + /** * @brief For diagnostics purposes only */ @@ -908,18 +923,6 @@ private: mp_rdata = 0; } - bool is_used (size_type n) const - { - if (n >= first () && n < last ()) { - if (mp_rdata) { - return mp_rdata->is_used (n); - } else { - return true; - } - } - return false; - } - size_type first () const { if (mp_rdata) { diff --git a/testdata/gds/t200.gds b/testdata/gds/t200.gds new file mode 100644 index 0000000000000000000000000000000000000000..08552d3a49985d8f9354b16bffd037f25b26f6f6 GIT binary patch literal 1354 zcmb7EJxc>Y5FIaZEqcQCR;> z2``wP&J$%~@v(`$k(u&ob#&@{=;U~@KwWV+E*S)qYg^0fE957Lf+mj|C}{SGsIN7q zze!auO6nzdi$lrlUXCVDewx1F23lj%4=gySB|nZJc&R(_1}B=p@i9D>_a}Wlx5Ysd z7=yQY#)b5&GbwSVZ`khWeeve`U|zl6ui{XmhYa6`H|IeH3H*fTgpjNe|JC1Khj}%`?D@5;ML)D)4 zZT+Vi>+tG5bBKOm84q6YAcEh4mwv`-4hmD-;F39{?!-frwWA#*zDXHokC-v^#ooLEW^{lNAmP@X>s@xQ)|LQWT J>nVMoJ^(V&Jjeh5 literal 0 HcmV?d00001 diff --git a/testdata/ruby/dbLayout.rb b/testdata/ruby/dbLayout.rb index 04b418eb9..cb89a9e0d 100644 --- a/testdata/ruby/dbLayout.rb +++ b/testdata/ruby/dbLayout.rb @@ -1994,6 +1994,45 @@ END end + # Iterating while flatten + def test_issue200 + + ly = RBA::Layout.new + ly.read(ENV["TESTSRC"] + "/testdata/gds/t200.gds") + l1 = ly.layer(1, 0) + l2 = ly.layer(2, 0) + l3 = ly.layer(3, 0) + + tc_name = ly.top_cell.name + r1 = RBA::Region::new(ly.top_cell.begin_shapes_rec(l1)) + r2 = RBA::Region::new(ly.top_cell.begin_shapes_rec(l2)) + r3 = RBA::Region::new(ly.top_cell.begin_shapes_rec(l3)) + assert_equal(r1.size > 0, true) + assert_equal(r2.size > 0, true) + assert_equal(r3.size == 0, true) + + ly.top_cell.each_inst do |ci| + ci.flatten + end + + tc = ly.cell(tc_name) + assert_equal(ly.top_cells.size, 4) + assert_equal(tc.child_cells, 0) + assert_equal(tc.parent_cells, 0) + + rr1 = RBA::Region::new(tc.begin_shapes_rec(l1)) + rr2 = RBA::Region::new(tc.begin_shapes_rec(l2)) + rr3 = RBA::Region::new(tc.begin_shapes_rec(l3)) + assert_equal(r1.size, rr1.size) + assert_equal(r2.size, rr2.size) + assert_equal(r3.size, rr3.size) + + assert_equal((rr1 ^ r1).is_empty?, true) + assert_equal((rr2 ^ r2).is_empty?, true) + assert_equal((rr3 ^ r3).is_empty?, true) + + end + end load("test_epilogue.rb")