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 {
/**
* @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
@ -48,6 +73,11 @@ static db::RecursiveInstanceIterator *new_si2a (const db::Layout &layout, const
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)
{
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 "
"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"),
"@brief Specifies the maximum hierarchy depth to look into\n"
"\n"
@ -468,6 +513,12 @@ Class<db::RecursiveInstanceIterator> decl_RecursiveInstanceIterator ("db", "Recu
"end\n"
"@/code\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"
"'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. "

View File

@ -1,4 +1,4 @@
#
/*
KLayout Layout Viewer
@ -27,12 +27,39 @@
#include "tlGlobPattern.h"
#include <iterator>
namespace gsi
{
// ---------------------------------------------------------------
// 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)
{
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);
}
static IteratorIterator each (db::RecursiveShapeIterator *r)
{
return IteratorIterator (r);
}
static db::DCplxTrans si_dtrans (const db::RecursiveShapeIterator *r)
{
const db::Layout *ly = r->layout ();
@ -236,6 +268,21 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
"\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"),
"@brief Specifies the maximum hierarchy depth to look into\n"
"\n"
@ -560,6 +607,15 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
" end\n"
" iter.next\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"
"\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)
# 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 = []
s.reset
while !s.at_end?
r = "[#{s.inst_cell.name}]"
r += (s.trans * s.inst_trans).to_s
@ -35,6 +44,8 @@ class DBLayout_TestClass < TestBase
s.next
end
assert_equal(res, res2)
return res.join("/")
end

View File

@ -27,7 +27,21 @@ class DBRecursiveShapeIterator_TestClass < TestBase
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 = []
s.reset
while !s.at_end?
r = "[#{l.cell_name(s.cell_index)}]"
if s.shape.is_box?
@ -40,6 +54,8 @@ class DBRecursiveShapeIterator_TestClass < TestBase
res.push(r)
end
assert_equal(res, res2)
return res.join("/")
end