Convenience 'each' for recursive shape iterator / recursive instance iterator

This commit is contained in:
Matthias Koefferlein 2022-02-08 22:28:09 +01:00
parent e49b189f64
commit 1a53cd00d2
4 changed files with 135 additions and 1 deletions

View File

@ -30,6 +30,31 @@
namespace gsi namespace gsi
{ {
namespace {
/**
* @brief A wrapper that allows using "each" on the iterator
*/
class IteratorIterator
{
public:
typedef db::RecursiveInstanceIterator value_type;
typedef db::RecursiveInstanceIterator &reference;
typedef db::RecursiveInstanceIterator *pointer;
typedef std::forward_iterator_tag iterator_category;
typedef void difference_type;
IteratorIterator (db::RecursiveInstanceIterator *iter) : mp_iter (iter) { }
bool at_end () const { return mp_iter->at_end (); }
reference operator* () const { return *mp_iter; }
void operator++ () { ++*mp_iter; }
private:
db::RecursiveInstanceIterator *mp_iter;
};
}
// --------------------------------------------------------------- // ---------------------------------------------------------------
// db::RecursiveInstanceIterator binding // db::RecursiveInstanceIterator binding
@ -48,6 +73,11 @@ static db::RecursiveInstanceIterator *new_si2a (const db::Layout &layout, const
return new db::RecursiveInstanceIterator (layout, cell, region, overlapping); return new db::RecursiveInstanceIterator (layout, cell, region, overlapping);
} }
static IteratorIterator each (db::RecursiveInstanceIterator *r)
{
return IteratorIterator (r);
}
static db::DCplxTrans si_dtrans (const db::RecursiveInstanceIterator *r) static db::DCplxTrans si_dtrans (const db::RecursiveInstanceIterator *r)
{ {
const db::Layout *ly = r->layout (); const db::Layout *ly = r->layout ();
@ -184,6 +214,21 @@ Class<db::RecursiveInstanceIterator> decl_RecursiveInstanceIterator ("db", "Recu
"bounding box touches the search region are reported. The bounding box of instances is measured taking all layers " "bounding box touches the search region are reported. The bounding box of instances is measured taking all layers "
"of the target cell into account.\n" "of the target cell into account.\n"
) + ) +
gsi::iterator_ext ("each", &each,
"@brief Native iteration\n"
"This method enables native iteration, e.g.\n"
"\n"
"@code\n"
" iter = ... # RecursiveInstanceIterator\n"
" iter.each do |i|\n"
" ... i is the iterator itself\n"
" end\n"
"@/code\n"
"\n"
"This is slightly more convenient than the 'at_end' .. 'next' loop.\n"
"\n"
"This feature has been introduced in version 0.28.\n"
) +
gsi::method ("max_depth=", (void (db::RecursiveInstanceIterator::*) (int)) &db::RecursiveInstanceIterator::max_depth, gsi::arg ("depth"), gsi::method ("max_depth=", (void (db::RecursiveInstanceIterator::*) (int)) &db::RecursiveInstanceIterator::max_depth, gsi::arg ("depth"),
"@brief Specifies the maximum hierarchy depth to look into\n" "@brief Specifies the maximum hierarchy depth to look into\n"
"\n" "\n"
@ -468,6 +513,12 @@ Class<db::RecursiveInstanceIterator> decl_RecursiveInstanceIterator ("db", "Recu
"end\n" "end\n"
"@/code\n" "@/code\n"
"\n" "\n"
"# or shorter:\n"
"cell.begin_instances_rec.each do |iter|\n"
" puts \"Instance of #{iter.inst_cell.name} in #{cell.name}: \" + (iter.dtrans * iter.inst_dtrans).to_s\n"
"end\n"
"@/code\n"
"\n"
"Here, a target cell is specified which confines the search to instances of this particular cell.\n" "Here, a target cell is specified which confines the search to instances of this particular cell.\n"
"'iter.dtrans' gives us the accumulated transformation of all parents up to the top cell. " "'iter.dtrans' gives us the accumulated transformation of all parents up to the top cell. "
"'iter.inst_dtrans' gives us the transformation from the current instance. " "'iter.inst_dtrans' gives us the transformation from the current instance. "

View File

@ -1,4 +1,4 @@
#
/* /*
KLayout Layout Viewer KLayout Layout Viewer
@ -27,12 +27,39 @@
#include "tlGlobPattern.h" #include "tlGlobPattern.h"
#include <iterator>
namespace gsi namespace gsi
{ {
// --------------------------------------------------------------- // ---------------------------------------------------------------
// db::RecursiveShapeIterator binding // db::RecursiveShapeIterator binding
namespace {
/**
* @brief A wrapper that allows using "each" on the iterator
*/
class IteratorIterator
{
public:
typedef db::RecursiveShapeIterator value_type;
typedef db::RecursiveShapeIterator &reference;
typedef db::RecursiveShapeIterator *pointer;
typedef std::forward_iterator_tag iterator_category;
typedef void difference_type;
IteratorIterator (db::RecursiveShapeIterator *iter) : mp_iter (iter) { }
bool at_end () const { return mp_iter->at_end (); }
reference operator* () const { return *mp_iter; }
void operator++ () { ++*mp_iter; }
private:
db::RecursiveShapeIterator *mp_iter;
};
}
static db::RecursiveShapeIterator *new_si1 (const db::Layout &layout, const db::Cell &cell, unsigned int layer) static db::RecursiveShapeIterator *new_si1 (const db::Layout &layout, const db::Cell &cell, unsigned int layer)
{ {
return new db::RecursiveShapeIterator (layout, cell, layer); return new db::RecursiveShapeIterator (layout, cell, layer);
@ -63,6 +90,11 @@ static db::RecursiveShapeIterator *new_si4a (const db::Layout &layout, const db:
return new db::RecursiveShapeIterator (layout, cell, layers, region, overlapping); return new db::RecursiveShapeIterator (layout, cell, layers, region, overlapping);
} }
static IteratorIterator each (db::RecursiveShapeIterator *r)
{
return IteratorIterator (r);
}
static db::DCplxTrans si_dtrans (const db::RecursiveShapeIterator *r) static db::DCplxTrans si_dtrans (const db::RecursiveShapeIterator *r)
{ {
const db::Layout *ly = r->layout (); const db::Layout *ly = r->layout ();
@ -236,6 +268,21 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
"\n" "\n"
"This constructor has been introduced in version 0.23. The 'overlapping' parameter has been made optional in version 0.27.\n" "This constructor has been introduced in version 0.23. The 'overlapping' parameter has been made optional in version 0.27.\n"
) + ) +
gsi::iterator_ext ("each", &each,
"@brief Native iteration\n"
"This method enables native iteration, e.g.\n"
"\n"
"@code\n"
" iter = ... # RecursiveShapeIterator\n"
" iter.each do |i|\n"
" ... i is the iterator itself\n"
" end\n"
"@/code\n"
"\n"
"This is slightly more convenient than the 'at_end' .. 'next' loop.\n"
"\n"
"This feature has been introduced in version 0.28.\n"
) +
gsi::method ("max_depth=", (void (db::RecursiveShapeIterator::*) (int)) &db::RecursiveShapeIterator::max_depth, gsi::arg ("depth"), gsi::method ("max_depth=", (void (db::RecursiveShapeIterator::*) (int)) &db::RecursiveShapeIterator::max_depth, gsi::arg ("depth"),
"@brief Specifies the maximum hierarchy depth to look into\n" "@brief Specifies the maximum hierarchy depth to look into\n"
"\n" "\n"
@ -560,6 +607,15 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
" end\n" " end\n"
" iter.next\n" " iter.next\n"
"end\n" "end\n"
"\n"
"# or shorter:\n"
"iter = cell.begin_shapes_rec(layer)\n"
"iter.each do |iter|\n"
" if iter.shape.renders_polygon?\n"
" polygon = iter.shape.polygon.transformed(iter.itrans)\n"
" puts \"In cell #{iter.cell.name}: \" + polygon.to_s\n"
" end\n"
"end\n"
"@/code\n" "@/code\n"
"\n" "\n"
"\\Cell offers three methods to get these iterators: begin_shapes_rec, begin_shapes_rec_touching and begin_shapes_rec_overlapping.\n" "\\Cell offers three methods to get these iterators: begin_shapes_rec, begin_shapes_rec_touching and begin_shapes_rec_overlapping.\n"

View File

@ -27,7 +27,16 @@ class DBLayout_TestClass < TestBase
def collect(s, l) def collect(s, l)
# check native iteration here too ..
res2 = []
s.each do |s|
r = "[#{s.inst_cell.name}]"
r += (s.trans * s.inst_trans).to_s
res2.push(r)
end
res = [] res = []
s.reset
while !s.at_end? while !s.at_end?
r = "[#{s.inst_cell.name}]" r = "[#{s.inst_cell.name}]"
r += (s.trans * s.inst_trans).to_s r += (s.trans * s.inst_trans).to_s
@ -35,6 +44,8 @@ class DBLayout_TestClass < TestBase
s.next s.next
end end
assert_equal(res, res2)
return res.join("/") return res.join("/")
end end

View File

@ -27,7 +27,21 @@ class DBRecursiveShapeIterator_TestClass < TestBase
def collect(s, l) def collect(s, l)
# check native iteration here too ..
res2 = []
s.each do |s|
r = "[#{l.cell_name(s.cell_index)}]"
if s.shape.is_box?
box = s.shape.box
r += box.transformed(s.trans).to_s
else
r += "X";
end
res2.push(r)
end
res = [] res = []
s.reset
while !s.at_end? while !s.at_end?
r = "[#{l.cell_name(s.cell_index)}]" r = "[#{l.cell_name(s.cell_index)}]"
if s.shape.is_box? if s.shape.is_box?
@ -40,6 +54,8 @@ class DBRecursiveShapeIterator_TestClass < TestBase
res.push(r) res.push(r)
end end
assert_equal(res, res2)
return res.join("/") return res.join("/")
end end