Merge pull request #221 from KLayout/issue-200

Fixed #200 by introducing layout locking during iteration
This commit is contained in:
Matthias Köfferlein 2019-01-09 01:11:49 +01:00 committed by GitHub
commit 1144899976
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 256 additions and 73 deletions

View File

@ -208,7 +208,8 @@ HEADERS = \
dbForceLink.h \
dbPlugin.h \
dbInit.h \
dbConverters.h
dbConverters.h \
gsiDeclDbHelpers.h
!equals(HAVE_QT, "0") {

View File

@ -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;
};

View File

@ -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<db::Shapes::shape_iterator> begin_shapes (const db::Cell *s, unsigned int layer_index, unsigned int flags)
{
return s->begin (layer_index, flags);
return gsi::layout_locking_iterator1<db::Shapes::shape_iterator> (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<db::Shapes::shape_iterator> begin_shapes_all (const db::Cell *s, unsigned int layer_index)
{
return s->begin (layer_index, db::ShapeIterator::All);
return gsi::layout_locking_iterator1<db::Shapes::shape_iterator> (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<db::Shapes::shape_iterator> 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<db::Shapes::shape_iterator> (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<db::Shapes::shape_iterator> 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<db::Shapes::shape_iterator> (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<db::Shapes::shape_iterator> 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<db::Shapes::shape_iterator> (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<db::Shapes::shape_iterator> 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<db::Shapes::shape_iterator> (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<db::Shapes::shape_iterator> 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<db::Shapes::shape_iterator> (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<db::Shapes::shape_iterator> 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<db::Shapes::shape_iterator> (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<db::Shapes::shape_iterator> 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<db::Shapes::shape_iterator> (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<db::Shapes::shape_iterator> 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<db::Shapes::shape_iterator> (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<db::Cell::overlapping_iterator> 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<db::Cell::overlapping_iterator> (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<db::Cell::overlapping_iterator> 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<db::Cell::overlapping_iterator> (cell->layout (), cell->begin_overlapping (dbu_trans.inverted () * dbox));
}
gsi::layout_locking_iterator1<db::Cell::touching_iterator> begin_touching_inst (const db::Cell *cell, const db::Cell::box_type &b)
{
return gsi::layout_locking_iterator1<db::Cell::touching_iterator> (cell->layout (), cell->begin_touching (b));
}
gsi::layout_locking_iterator1<db::Cell::touching_iterator> 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<db::Cell::touching_iterator> (cell->layout (), cell->begin_touching (dbu_trans.inverted () * dbox));
}
gsi::layout_locking_iterator1<db::Cell::child_cell_iterator> begin_child_cells (const db::Cell *cell)
{
return gsi::layout_locking_iterator1<db::Cell::child_cell_iterator> (cell->layout (), cell->begin_child_cells ());
}
gsi::layout_locking_iterator1<db::Cell::parent_inst_iterator> begin_parent_insts (const db::Cell *cell)
{
return gsi::layout_locking_iterator1<db::Cell::parent_inst_iterator> (cell->layout (), cell->begin_parent_insts ());
}
gsi::layout_locking_iterator2<db::Cell::parent_cell_iterator> begin_parent_cells (const db::Cell *cell)
{
return gsi::layout_locking_iterator2<db::Cell::parent_cell_iterator> (cell->layout (), cell->begin_parent_cells (), cell->end_parent_cells ());
}
static layout_locking_iterator1<db::Cell::const_iterator> begin_inst (db::Cell *cell)
{
return layout_locking_iterator1<db::Cell::const_iterator> (cell->layout (), cell->begin ());
}
Class<db::Cell> decl_Cell ("db", "Cell",
@ -2569,7 +2601,7 @@ Class<db::Cell> 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<db::Cell> 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<db::Cell> 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<db::Cell> 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<db::Cell> 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<db::Cell> 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<db::Cell> 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"

View File

@ -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 I>
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<db::Layout *> (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 I>
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<db::Layout *> (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

View File

@ -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<ISh> (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<db::Shapes::shape_iterator> begin (const db::Shapes *s, unsigned int flags)
{
return s->begin (flags);
return gsi::layout_locking_iterator1<db::Shapes::shape_iterator> (s->layout (), s->begin (flags));
}
static db::Shapes::shape_iterator begin_all (const db::Shapes *s)
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator>begin_all (const db::Shapes *s)
{
return s->begin (db::ShapeIterator::All);
return gsi::layout_locking_iterator1<db::Shapes::shape_iterator> (s->layout (), s->begin (db::ShapeIterator::All));
}
static db::Shapes::shape_iterator begin_overlapping (const db::Shapes *s, unsigned int flags, const db::Box &region)
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator>begin_overlapping (const db::Shapes *s, unsigned int flags, const db::Box &region)
{
return s->begin_overlapping (region, flags);
return gsi::layout_locking_iterator1<db::Shapes::shape_iterator> (s->layout (), s->begin_overlapping (region, flags));
}
static db::Shapes::shape_iterator begin_doverlapping (const db::Shapes *s, unsigned int flags, const db::DBox &region)
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator>begin_doverlapping (const db::Shapes *s, unsigned int flags, const db::DBox &region)
{
return s->begin_overlapping (db::CplxTrans (shapes_dbu (s)).inverted () * region, flags);
return gsi::layout_locking_iterator1<db::Shapes::shape_iterator> (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 &region)
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator>begin_overlapping_all (const db::Shapes *s, const db::Box &region)
{
return s->begin_overlapping (region, db::ShapeIterator::All);
return gsi::layout_locking_iterator1<db::Shapes::shape_iterator> (s->layout (), s->begin_overlapping (region, db::ShapeIterator::All));
}
static db::Shapes::shape_iterator begin_doverlapping_all (const db::Shapes *s, const db::DBox &region)
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator>begin_doverlapping_all (const db::Shapes *s, const db::DBox &region)
{
return s->begin_overlapping (db::CplxTrans (shapes_dbu (s)).inverted () * region, db::ShapeIterator::All);
return gsi::layout_locking_iterator1<db::Shapes::shape_iterator> (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 &region)
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator>begin_touching (const db::Shapes *s, unsigned int flags, const db::Box &region)
{
return s->begin_touching (region, flags);
return gsi::layout_locking_iterator1<db::Shapes::shape_iterator> (s->layout (), s->begin_touching (region, flags));
}
static db::Shapes::shape_iterator begin_dtouching (const db::Shapes *s, unsigned int flags, const db::DBox &region)
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator>begin_dtouching (const db::Shapes *s, unsigned int flags, const db::DBox &region)
{
return s->begin_touching (db::CplxTrans (shapes_dbu (s)).inverted () * region, flags);
return gsi::layout_locking_iterator1<db::Shapes::shape_iterator> (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 &region)
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator>begin_touching_all (const db::Shapes *s, const db::Box &region)
{
return s->begin_touching (region, db::ShapeIterator::All);
return gsi::layout_locking_iterator1<db::Shapes::shape_iterator> (s->layout (), s->begin_touching (region, db::ShapeIterator::All));
}
static db::Shapes::shape_iterator begin_dtouching_all (const db::Shapes *s, const db::DBox &region)
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator>begin_dtouching_all (const db::Shapes *s, const db::DBox &region)
{
return s->begin_touching (db::CplxTrans (shapes_dbu (s)).inverted () * region, db::ShapeIterator::All);
return gsi::layout_locking_iterator1<db::Shapes::shape_iterator> (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)

View File

@ -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) {

BIN
testdata/gds/t200.gds vendored Normal file

Binary file not shown.

View File

@ -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")