mirror of https://github.com/KLayout/klayout.git
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.
This commit is contained in:
parent
d2d28bc613
commit
aeeb6d7c87
|
|
@ -208,7 +208,8 @@ HEADERS = \
|
||||||
dbForceLink.h \
|
dbForceLink.h \
|
||||||
dbPlugin.h \
|
dbPlugin.h \
|
||||||
dbInit.h \
|
dbInit.h \
|
||||||
dbConverters.h
|
dbConverters.h \
|
||||||
|
gsiDeclDbHelpers.h
|
||||||
|
|
||||||
!equals(HAVE_QT, "0") {
|
!equals(HAVE_QT, "0") {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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:
|
private:
|
||||||
LayoutLocker (const LayoutLocker &);
|
|
||||||
LayoutLocker &operator= (const LayoutLocker &);
|
|
||||||
|
|
||||||
db::Layout *mp_layout;
|
db::Layout *mp_layout;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@
|
||||||
|
|
||||||
|
|
||||||
#include "gsiDecl.h"
|
#include "gsiDecl.h"
|
||||||
|
|
||||||
|
#include "gsiDeclDbHelpers.h"
|
||||||
#include "dbLayout.h"
|
#include "dbLayout.h"
|
||||||
#include "dbBoxConvert.h"
|
#include "dbBoxConvert.h"
|
||||||
#include "dbRegion.h"
|
#include "dbRegion.h"
|
||||||
|
|
@ -711,70 +713,70 @@ static void dump_mem_statistics (const db::Cell *cell, bool detailed)
|
||||||
ms.print ();
|
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 ();
|
const db::Layout *layout = s->layout ();
|
||||||
if (! layout) {
|
if (! layout) {
|
||||||
throw tl::Exception (tl::to_string (tr ("Cell does not reside inside a layout - cannot use a micrometer search box")));
|
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 ();
|
const db::Layout *layout = s->layout ();
|
||||||
if (! layout) {
|
if (! layout) {
|
||||||
throw tl::Exception (tl::to_string (tr ("Cell does not reside inside a layout - cannot use a micrometer search box")));
|
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 ();
|
const db::Layout *layout = s->layout ();
|
||||||
if (! layout) {
|
if (! layout) {
|
||||||
throw tl::Exception (tl::to_string (tr ("Cell does not reside inside a layout - cannot use a micrometer search box")));
|
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 ();
|
const db::Layout *layout = s->layout ();
|
||||||
if (! layout) {
|
if (! layout) {
|
||||||
throw tl::Exception (tl::to_string (tr ("Cell does not reside inside a layout - cannot use a micrometer search box")));
|
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)
|
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 ();
|
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 ();
|
return gsi::layout_locking_iterator1<db::Cell::overlapping_iterator> (cell->layout (), cell->begin_overlapping (b));
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 ();
|
const db::Layout *layout = cell->layout ();
|
||||||
if (! 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 ());
|
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",
|
Class<db::Cell> decl_Cell ("db", "Cell",
|
||||||
|
|
@ -2569,7 +2601,7 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
||||||
"\n"
|
"\n"
|
||||||
"This method has been introduced in version 0.25."
|
"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"
|
"@brief Gets the instances overlapping the given rectangle\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This will iterate over all child cell\n"
|
"This will iterate over all child cell\n"
|
||||||
|
|
@ -2579,7 +2611,7 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
||||||
"\n"
|
"\n"
|
||||||
"Starting with version 0.15, this iterator delivers \\Instance objects rather than \\CellInstArray objects."
|
"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"
|
"@brief Gets the instances overlapping the given rectangle, with the rectangle in micrometer units\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This will iterate over all child cell\n"
|
"This will iterate over all child cell\n"
|
||||||
|
|
@ -2592,7 +2624,7 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
||||||
"\n"
|
"\n"
|
||||||
"This variant has been introduced in version 0.25."
|
"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"
|
"@brief Gets the instances touching the given rectangle\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This will iterate over all child cell\n"
|
"This will iterate over all child cell\n"
|
||||||
|
|
@ -2602,7 +2634,7 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
||||||
"\n"
|
"\n"
|
||||||
"Starting with version 0.15, this iterator delivers \\Instance objects rather than \\CellInstArray objects."
|
"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"
|
"@brief Gets the instances touching the given rectangle, with the rectangle in micrometer units\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This will iterate over all child cell\n"
|
"This will iterate over all child cell\n"
|
||||||
|
|
@ -2615,7 +2647,7 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
||||||
"\n"
|
"\n"
|
||||||
"This variant has been introduced in version 0.25."
|
"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"
|
"@brief Iterates over all child cells\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This iterator will report the child cell indices, not every instance.\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"
|
"The number of child cells (not child instances!) is returned.\n"
|
||||||
"CAUTION: this method is SLOW, in particular if many instances are present.\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"
|
"@brief Iterates over all child instances (which may actually be instance arrays)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Starting with version 0.15, this iterator delivers \\Instance objects rather than \\CellInstArray objects."
|
"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"
|
"@brief Iterates over the parent instance list (which may actually be instance arrays)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"The parent instances are basically inversions of the instances. Using parent instances "
|
"The parent instances are basically inversions of the instances. Using parent instances "
|
||||||
|
|
@ -2642,7 +2674,7 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
||||||
"\n"
|
"\n"
|
||||||
"The number of parent cells (cells which reference our cell) is reported."
|
"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"
|
"@brief Iterates over all parent cells\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This iterator will iterate over the parent cells, just returning their\n"
|
"This iterator will iterate over the parent cells, just returning their\n"
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -22,6 +22,8 @@
|
||||||
|
|
||||||
|
|
||||||
#include "gsiDecl.h"
|
#include "gsiDecl.h"
|
||||||
|
|
||||||
|
#include "gsiDeclDbHelpers.h"
|
||||||
#include "dbShapes.h"
|
#include "dbShapes.h"
|
||||||
#include "dbShape.h"
|
#include "dbShape.h"
|
||||||
#include "dbLayout.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));
|
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 ®ion)
|
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator>begin_overlapping (const db::Shapes *s, unsigned int flags, const db::Box ®ion)
|
||||||
{
|
{
|
||||||
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 ®ion)
|
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator>begin_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<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 ®ion)
|
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator>begin_overlapping_all (const db::Shapes *s, const db::Box ®ion)
|
||||||
{
|
{
|
||||||
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 ®ion)
|
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator>begin_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<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 ®ion)
|
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator>begin_touching (const db::Shapes *s, unsigned int flags, const db::Box ®ion)
|
||||||
{
|
{
|
||||||
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 ®ion)
|
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator>begin_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<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 ®ion)
|
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator>begin_touching_all (const db::Shapes *s, const db::Box ®ion)
|
||||||
{
|
{
|
||||||
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 ®ion)
|
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator>begin_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<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)
|
static void transform_shapes (db::Shapes *s, const db::Trans &trans)
|
||||||
|
|
|
||||||
|
|
@ -887,6 +887,21 @@ public:
|
||||||
init ();
|
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
|
* @brief For diagnostics purposes only
|
||||||
*/
|
*/
|
||||||
|
|
@ -908,18 +923,6 @@ private:
|
||||||
mp_rdata = 0;
|
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
|
size_type first () const
|
||||||
{
|
{
|
||||||
if (mp_rdata) {
|
if (mp_rdata) {
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1994,6 +1994,45 @@ END
|
||||||
|
|
||||||
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
|
end
|
||||||
|
|
||||||
load("test_epilogue.rb")
|
load("test_epilogue.rb")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue