WIP on complex regions for RecursiveShapeIterator

- Added some tests
- Performance improvements for insert of
  regions into shapes
- Added LayoutLocker for that purpose
  (locks a layout against updates temporarily)
- Improved implementation on RecursiveShapeIterator
  with complex regions: will now check if a shape
  is really inside the region.
This commit is contained in:
Matthias Koefferlein 2017-02-14 00:13:57 +01:00
parent 282c6f70e2
commit fb6cf92b15
7 changed files with 177 additions and 54 deletions

View File

@ -1672,6 +1672,45 @@ private:
void do_prune_cells_or_subcells (const std::set<cell_index_type> &ids, int levels, bool subcells);
};
/**
* @brief A nice helper class that employs RAII for locking the layout against updates
*
* If a layout shall be locked against internal updates temporarily, use this locker:
* @code
* Layout *ly = ...;
* {
* db::LayoutLocker locker (ly);
* // the layout is not updated here
* ... modify the layout
* }
* // now only the layout gets updated
* @endcode
*/
class DB_PUBLIC LayoutLocker
{
public:
explicit LayoutLocker (db::Layout *layout = 0)
: mp_layout (layout)
{
if (mp_layout) {
mp_layout->start_changes ();
}
}
~LayoutLocker ()
{
if (mp_layout) {
mp_layout->end_changes ();
}
}
private:
LayoutLocker (const LayoutLocker &);
LayoutLocker &operator= (const LayoutLocker &);
db::Layout *mp_layout;
};
}
#endif

View File

@ -497,6 +497,60 @@ RecursiveShapeIterator::bbox () const
return box;
}
void
RecursiveShapeIterator::skip_shape_iter_for_complex_region () const
{
while (! m_shape.at_end ()) {
// skip shape quad if possible
while (! m_shape.at_end ()) {
if (is_outside_complex_region (m_shape.quad_box ())) {
m_shape.skip_quad ();
} else {
m_shape_quad_id = m_shape.quad_id ();
break;
}
}
// skip shapes outside the complex region
if (! m_shape.at_end ()) {
if (! is_outside_complex_region (m_shape->bbox ())) {
break;
} else {
++m_shape;
}
}
}
}
void
RecursiveShapeIterator::skip_inst_iter_for_complex_region () const
{
while (! m_inst.at_end ()) {
// skip inst quad if possible
while (! m_inst.at_end ()) {
if (is_outside_complex_region (m_inst.quad_box ())) {
m_inst.skip_quad ();
} else {
m_inst_quad_id = m_inst.quad_id ();
break;
}
}
// skip insts outside the complex region
if (! m_inst.at_end ()) {
if (! is_outside_complex_region (m_inst->bbox ())) {
break;
} else {
++m_inst;
}
}
}
}
void
RecursiveShapeIterator::next ()
{
@ -504,16 +558,8 @@ RecursiveShapeIterator::next ()
++m_shape;
// skip shape quad if possible
if (! m_local_complex_region_stack.empty () && m_shape_quad_id != m_shape.quad_id ()) {
while (! m_shape.at_end ()) {
if (is_outside_complex_region (m_shape.quad_box ())) {
m_shape.skip_quad ();
} else {
m_shape_quad_id = m_shape.quad_id ();
break;
}
}
if (! m_local_complex_region_stack.empty ()) {
skip_shape_iter_for_complex_region ();
}
if (! mp_shapes && m_shape.at_end ()) {
@ -626,9 +672,8 @@ RecursiveShapeIterator::down () const
if (! m_local_complex_region_stack.empty ()) {
const box_tree_type &pcl = m_local_complex_region_stack.back ();
m_local_complex_region_stack.push_back (box_tree_type ());
const box_tree_type &pcl = m_local_complex_region_stack.end ()[-2];
if (! new_region.empty ()) {
@ -694,16 +739,8 @@ RecursiveShapeIterator::start_shapes () const
m_shape_quad_id = 0;
// skip instance quad if possible
if (! m_local_complex_region_stack.empty ()) {
while (! m_shape.at_end ()) {
if (is_outside_complex_region (m_shape.quad_box ())) {
m_shape.skip_quad ();
} else {
m_shape_quad_id = m_shape.quad_id ();
break;
}
}
skip_shape_iter_for_complex_region ();
}
}
@ -722,14 +759,7 @@ RecursiveShapeIterator::new_layer () const
// skip instance quad if possible
if (! m_local_complex_region_stack.empty ()) {
while (! m_shape.at_end ()) {
if (is_outside_complex_region (m_shape.quad_box ())) {
m_shape.skip_quad ();
} else {
m_shape_quad_id = m_shape.quad_id ();
break;
}
}
skip_shape_iter_for_complex_region ();
}
}
@ -755,14 +785,7 @@ RecursiveShapeIterator::new_cell () const
// skip instance quad if possible
if (! m_local_complex_region_stack.empty ()) {
while (! m_inst.at_end ()) {
if (is_outside_complex_region (m_inst.quad_box ())) {
m_inst.skip_quad ();
} else {
m_inst_quad_id = m_inst.quad_id ();
break;
}
}
skip_inst_iter_for_complex_region ();
}
new_inst ();
@ -777,21 +800,11 @@ RecursiveShapeIterator::new_inst () const
while (! m_inst.at_end ()) {
// skip instance quad if possible
if (! m_local_complex_region_stack.empty () && m_inst_quad_id != m_inst.quad_id ()) {
while (! m_inst.at_end ()) {
if (is_outside_complex_region (m_inst.quad_box ())) {
m_inst.skip_quad ();
} else {
m_inst_quad_id = m_inst.quad_id ();
break;
}
}
if (! m_local_complex_region_stack.empty ()) {
skip_inst_iter_for_complex_region ();
if (m_inst.at_end ()) {
break;
}
}
if (m_local_region_stack.back () != box_type::world ()) {

View File

@ -694,6 +694,8 @@ private:
void init ();
void init_complex_region (const box_type &box, const region_type &excl_region);
void init_complex_region (const region_type &excl_region);
void skip_shape_iter_for_complex_region () const;
void skip_inst_iter_for_complex_region () const;
void validate () const;
void start_shapes () const;
void next_shape () const;

View File

@ -161,7 +161,7 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("RecursiveShapeIt
) +
gsi::constructor ("new", &new_si3a,
"@brief Creates a recursive, single-layer shape iterator with a region.\n"
"@args layout, cell, layer, box, overlapping\n"
"@args layout, cell, layer, box, excl_region, overlapping\n"
"@param layout The layout which shall be iterated\n"
"@param cell The initial cell which shall be iterated (including it's children)\n"
"@param layer The layer (index) from which the shapes are taken\n"
@ -184,7 +184,7 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("RecursiveShapeIt
) +
gsi::constructor ("new", &new_si3b,
"@brief Creates a recursive, single-layer shape iterator with a region.\n"
"@args layout, cell, layer, box, overlapping\n"
"@args layout, cell, layer, region, overlapping\n"
"@param layout The layout which shall be iterated\n"
"@param cell The initial cell which shall be iterated (including it's children)\n"
"@param layer The layer (index) from which the shapes are taken\n"
@ -222,7 +222,7 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("RecursiveShapeIt
) +
gsi::constructor ("new", &new_si4a,
"@brief Creates a recursive, multi-layer shape iterator with a region.\n"
"@args layout, cell, layers, box, overlapping\n"
"@args layout, cell, layers, box, excl_region, overlapping\n"
"@param layout The layout which shall be iterated\n"
"@param cell The initial cell which shall be iterated (including it's children)\n"
"@param layers The layer indexes from which the shapes are taken\n"
@ -246,7 +246,7 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("RecursiveShapeIt
) +
gsi::constructor ("new", &new_si4b,
"@brief Creates a recursive, multi-layer shape iterator with a region.\n"
"@args layout, cell, layers, box, overlapping\n"
"@args layout, cell, layers, region, overlapping\n"
"@param layout The layout which shall be iterated\n"
"@param cell The initial cell which shall be iterated (including it's children)\n"
"@param layers The layer indexes from which the shapes are taken\n"

View File

@ -20,7 +20,6 @@
*/
#include "gsiDecl.h"
#include "dbRegion.h"

View File

@ -207,6 +207,9 @@ static db::Shape insert_shape_with_dcplx_trans (db::Shapes *s, const db::Shape &
static void insert_region (db::Shapes *sh, const db::Region &r)
{
// NOTE: if the source (r) is from the same layout than the shapes live in, we better
// lock the layout against updates while inserting
db::LayoutLocker locker (sh->layout ());
for (db::Region::const_iterator s = r.begin (); ! s.at_end (); ++s) {
sh->insert (*s);
}
@ -214,6 +217,9 @@ static void insert_region (db::Shapes *sh, const db::Region &r)
static void insert_region_with_trans (db::Shapes *sh, const db::Region &r, const db::ICplxTrans &trans)
{
// NOTE: if the source (r) is from the same layout than the shapes live in, we better
// lock the layout against updates while inserting
db::LayoutLocker locker (sh->layout ());
for (db::Region::const_iterator s = r.begin (); ! s.at_end (); ++s) {
sh->insert (s->transformed (trans));
}

View File

@ -22,6 +22,7 @@
#include "dbRecursiveShapeIterator.h"
#include "dbRegion.h"
#include "tlString.h"
#include "utHead.h"
@ -274,6 +275,10 @@ TEST(1a)
std::string x;
db::RecursiveShapeIterator i0 (g, c0, 0, db::Box ());
x = collect(i0, g);
EXPECT_EQ (x, "");
db::RecursiveShapeIterator i1 (g, c0, 0, db::Box (0, 0, 100, 100));
x = collect(i1, g);
EXPECT_EQ (x, "[$2](0,100;1000,1200)/[$3](100,0;1100,1100)");
@ -393,6 +398,10 @@ TEST(2)
std::string x;
db::RecursiveShapeIterator i0 (g, c0, 0, db::Box ());
x = collect(i0, g);
EXPECT_EQ (x, "");
db::RecursiveShapeIterator i (g, c0, 0, db::Box::world ());
x = collect(i, g);
EXPECT_EQ (x, "[$3](1000,-500;2000,500)/[$3](1000,1500;2000,2500)/[$3](4000,500;5000,1500)/[$3](4000,2500;5000,3500)/[$3](1000,5500;2000,6500)/[$3](1000,7500;2000,8500)/[$3](4000,6500;5000,7500)/[$3](4000,8500;5000,9500)/[$3](7000,-500;8000,500)/[$3](7000,1500;8000,2500)/[$3](10000,500;11000,1500)/[$3](10000,2500;11000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)/[$3](10000,6500;11000,7500)/[$3](10000,8500;11000,9500)");
@ -414,4 +423,59 @@ TEST(2)
EXPECT_EQ (x, "[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)");
}
TEST(3)
{
db::Manager m;
db::Layout g (&m);
g.insert_layer(0);
db::Cell &c0 (g.cell (g.add_cell ()));
db::Cell &c1 (g.cell (g.add_cell ()));
db::Cell &c2 (g.cell (g.add_cell ()));
db::Box b (1000, -500, 2000, 500);
c2.shapes (0).insert (b);
db::Trans tt;
c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), tt, db::Vector (0, 6000), db::Vector (6000, 0), 2, 2));
c1.insert (db::CellInstArray (db::CellInst (c2.cell_index ()), tt, db::Vector (0, 2000), db::Vector (3000, 1000), 2, 2));
std::string x;
db::RecursiveShapeIterator i (g, c0, 0, db::Box::world ());
x = collect(i, g);
EXPECT_EQ (x, "[$3](1000,-500;2000,500)/[$3](1000,1500;2000,2500)/[$3](4000,500;5000,1500)/[$3](4000,2500;5000,3500)/[$3](1000,5500;2000,6500)/[$3](1000,7500;2000,8500)/[$3](4000,6500;5000,7500)/[$3](4000,8500;5000,9500)/[$3](7000,-500;8000,500)/[$3](7000,1500;8000,2500)/[$3](10000,500;11000,1500)/[$3](10000,2500;11000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)/[$3](10000,6500;11000,7500)/[$3](10000,8500;11000,9500)");
db::RecursiveShapeIterator i2 (g, c0, 0, db::Region (db::Box (3400, 3450, 5600, 6500)));
x = collect(i2, g);
EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](4000,6500;5000,7500)");
db::RecursiveShapeIterator i3 (g, c0, 0, db::Region (db::Box (6650, 5300, 10000, 7850)));
x = collect(i3, g);
EXPECT_EQ (x, "[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)/[$3](10000,6500;11000,7500)");
db::Region rr;
rr.insert (db::Box (3400, 3450, 5600, 6500));
rr.insert (db::Box (6650, 5300, 10000, 7850));
db::RecursiveShapeIterator i23 (g, c0, 0, rr);
x = collect(i23, g);
EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](4000,6500;5000,7500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)/[$3](10000,6500;11000,7500)");
db::RecursiveShapeIterator i2o (g, c0, 0, db::Region (db::Box (3400, 3450, 5600, 6500)), true);
x = collect(i2o, g);
EXPECT_EQ (x, "[$3](4000,2500;5000,3500)");
db::RecursiveShapeIterator i3o (g, c0, 0, db::Region (db::Box (6650, 5300, 10000, 7850)), true);
x = collect(i3o, g);
EXPECT_EQ (x, "[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)");
db::Region rro;
rro.insert (db::Box (3400, 3450, 5600, 6500));
rro.insert (db::Box (6650, 5300, 10000, 7850));
db::RecursiveShapeIterator i23o (g, c0, 0, rro);
x = collect(i23o, g);
EXPECT_EQ (x, "[$3](4000,2500;5000,3500)/[$3](7000,5500;8000,6500)/[$3](7000,7500;8000,8500)");
}