From 1a53cd00d25694ded1e24669fa646f06b32dd3cf Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 8 Feb 2022 22:28:09 +0100 Subject: [PATCH] Convenience 'each' for recursive shape iterator / recursive instance iterator --- .../db/gsiDeclDbRecursiveInstanceIterator.cc | 51 ++++++++++++++++ src/db/db/gsiDeclDbRecursiveShapeIterator.cc | 58 ++++++++++++++++++- testdata/ruby/dbRecursiveInstanceIterator.rb | 11 ++++ testdata/ruby/dbRecursiveShapeIterator.rb | 16 +++++ 4 files changed, 135 insertions(+), 1 deletion(-) diff --git a/src/db/db/gsiDeclDbRecursiveInstanceIterator.cc b/src/db/db/gsiDeclDbRecursiveInstanceIterator.cc index e2d9f93eb..48853b77c 100644 --- a/src/db/db/gsiDeclDbRecursiveInstanceIterator.cc +++ b/src/db/db/gsiDeclDbRecursiveInstanceIterator.cc @@ -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 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 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. " diff --git a/src/db/db/gsiDeclDbRecursiveShapeIterator.cc b/src/db/db/gsiDeclDbRecursiveShapeIterator.cc index 34e5a6650..b3d3ec8b9 100644 --- a/src/db/db/gsiDeclDbRecursiveShapeIterator.cc +++ b/src/db/db/gsiDeclDbRecursiveShapeIterator.cc @@ -1,4 +1,4 @@ - +# /* KLayout Layout Viewer @@ -27,12 +27,39 @@ #include "tlGlobPattern.h" +#include + 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 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 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" diff --git a/testdata/ruby/dbRecursiveInstanceIterator.rb b/testdata/ruby/dbRecursiveInstanceIterator.rb index 9448d147d..4d9aefa2b 100644 --- a/testdata/ruby/dbRecursiveInstanceIterator.rb +++ b/testdata/ruby/dbRecursiveInstanceIterator.rb @@ -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 diff --git a/testdata/ruby/dbRecursiveShapeIterator.rb b/testdata/ruby/dbRecursiveShapeIterator.rb index 2f46a306b..82d4b47b6 100644 --- a/testdata/ruby/dbRecursiveShapeIterator.rb +++ b/testdata/ruby/dbRecursiveShapeIterator.rb @@ -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