/* KLayout Layout Viewer Copyright (C) 2006-2016 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 */ #include "utHead.h" #include "dbLayoutQuery.h" #include "gsiExpression.h" #include "dbCell.h" #include "dbLayout.h" #include "dbPCellDeclaration.h" #include "dbLibrary.h" #include "dbLibraryManager.h" static std::string q2s_var (db::Layout &g, const std::string &query, const std::string &pname, const char *sep = ",") { db::LayoutQuery q (query); db::LayoutQueryIterator iq (q, &g); std::string res; while (! iq.at_end ()) { if (!res.empty ()) { res += sep; } tl::Variant v; iq.get (pname, v); res += v.to_string (); ++iq; } return res; } static std::string q2s_var_skip (db::LayoutQueryIterator &iq, const std::string &pname, const char *sep = ",") { iq.reset (); std::string res; while (! iq.at_end ()) { if (!res.empty ()) { res += sep; } tl::Variant v; iq.get (pname, v); res += v.to_string (); iq.next (true); } return res; } static std::string q2s_var (db::LayoutQueryIterator &iq, const std::string &pname, const char *sep = ",") { iq.reset (); std::string res; while (! iq.at_end ()) { if (!res.empty ()) { res += sep; } tl::Variant v; iq.get (pname, v); res += v.to_string (); ++iq; } return res; } static std::string q2s_expr (db::LayoutQueryIterator &iq, const std::string &es) { std::string res; iq.reset (); tl::Expression ex; iq.eval ().parse (ex, es, true); while (! iq.at_end ()) { if (!res.empty ()) { res += ","; } res += ex.execute().to_string (); ++iq; } return res; } static std::string q2s_cell (db::LayoutQueryIterator &iq, const std::string &pname) { iq.reset (); std::string res; while (! iq.at_end ()) { if (!res.empty ()) { res += ","; } tl::Variant v; iq.get (pname, v); if (v.is_nil ()) { res += v.to_string (); } else { res += iq.layout ()->cell_name (v.to_ulong ()); } ++iq; } return res; } TEST(1) { db::Layout g; g.insert_layer (0); g.insert_layer (1); db::Cell &c1 (g.cell (g.add_cell ("c1"))); db::Cell &c2 (g.cell (g.add_cell ("c2x"))); db::Cell &c3 (g.cell (g.add_cell ("c3"))); db::Cell &c4 (g.cell (g.add_cell ("c4"))); db::Cell &c5 (g.cell (g.add_cell ("c5x"))); c2.shapes (0).insert (db::Box (0, 1, 2, 3)); db::FTrans f (1, true); db::Vector p (-10, 20); db::Trans t (f.rot (), p); db::Vector pp (10, -20); db::Trans tt (0, pp); // c4->c1 (aref) c4.insert (db::array (db::CellInst (c1.cell_index ()), t, db::Vector(1, 1), db::Vector (0, 2), 2, 3)); // c5->c1 c5.insert (db::array (db::CellInst (c1.cell_index ()), t)); // c3->c5 (3x) c3.insert (db::array (db::CellInst (c5.cell_index ()), t)); c3.insert (db::array (db::CellInst (c5.cell_index ()), tt)); c3.insert (db::array (db::CellInst (c5.cell_index ()), t)); // c4->c3 c4.insert (db::array (db::CellInst (c3.cell_index ()), t)); // c4->c1 c4.insert (db::array (db::CellInst (c1.cell_index ()), tt)); // c2->c1 (2x) c2.insert (db::array (db::CellInst (c1.cell_index ()), t)); c2.insert (db::array (db::CellInst (c1.cell_index ()), tt)); // c2->c4 (2x) c2.insert (db::array (db::CellInst (c4.cell_index ()), t)); c2.insert (db::array (db::CellInst (c4.cell_index ()), t)); // c2->c5 (2x) c2.insert (db::array (db::CellInst (c5.cell_index ()), t)); c2.insert (db::array (db::CellInst (c5.cell_index ()), tt)); { db::LayoutQuery q ("*"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c2x,c4,c3,c5x,c1"); s = q2s_cell (iq, "cell_index"); EXPECT_EQ (s, "c2x,c4,c3,c5x,c1"); s = q2s_expr (iq, "cell.name"); EXPECT_EQ (s, "c2x,c4,c3,c5x,c1"); s = q2s_var (iq, "initial_cell_name"); EXPECT_EQ (s, "c2x,c4,c3,c5x,c1"); s = q2s_expr (iq, "initial_cell.name"); EXPECT_EQ (s, "c2x,c4,c3,c5x,c1"); s = q2s_cell (iq, "initial_cell_index"); EXPECT_EQ (s, "c2x,c4,c3,c5x,c1"); } { db::LayoutQuery q ("*x"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c2x,c5x"); s = q2s_cell (iq, "cell_index"); EXPECT_EQ (s, "c2x,c5x"); s = q2s_cell (iq, "initial_cell_index"); EXPECT_EQ (s, "c2x,c5x"); s = q2s_var (iq, "instances"); EXPECT_EQ (s, "1,8"); s = q2s_var (iq, "bbox"); EXPECT_EQ (s, "(0,1;2,3),()"); } { db::LayoutQuery q (".*"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c2x"); s = q2s_cell (iq, "cell_index"); EXPECT_EQ (s, "c2x"); s = q2s_cell (iq, "initial_cell_index"); EXPECT_EQ (s, "c2x"); s = q2s_expr (iq, "initial_cell.name"); EXPECT_EQ (s, "c2x"); s = q2s_var (iq, "initial_cell_name"); EXPECT_EQ (s, "c2x"); s = q2s_cell (iq, "parent_cell_index"); EXPECT_EQ (s, "nil"); s = q2s_var (iq, "parent_cell_name"); EXPECT_EQ (s, "nil"); s = q2s_var (iq, "path_names"); EXPECT_EQ (s, "c2x"); s = q2s_var (iq, "path"); EXPECT_EQ (s, "1"); s = q2s_var (iq, "hier_levels"); EXPECT_EQ (s, "0"); } { // all cells one level below the top cell db::LayoutQuery q (".*.*"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c1,c4,c5x"); s = q2s_expr (iq, "cell.name"); EXPECT_EQ (s, "c1,c4,c5x"); bool error = false; try { // errors: cannot call non-const method on const reference s = q2s_expr (iq, "cell.name='hallo'"); } catch (...) { error = true; } EXPECT_EQ (error, true); s = q2s_expr (iq, "cell.name"); EXPECT_EQ (s, "c1,c4,c5x"); s = q2s_cell (iq, "cell_index"); EXPECT_EQ (s, "c1,c4,c5x"); s = q2s_cell (iq, "initial_cell_index"); EXPECT_EQ (s, "c2x,c2x,c2x"); s = q2s_var (iq, "initial_cell_name"); EXPECT_EQ (s, "c2x,c2x,c2x"); s = q2s_cell (iq, "parent_cell_index"); EXPECT_EQ (s, "c2x,c2x,c2x"); s = q2s_var (iq, "parent_cell_name"); EXPECT_EQ (s, "c2x,c2x,c2x"); s = q2s_expr (iq, "parent_cell.name"); EXPECT_EQ (s, "c2x,c2x,c2x"); s = q2s_var (iq, "path_names"); EXPECT_EQ (s, "c2x,c1,c2x,c4,c2x,c5x"); s = q2s_var (iq, "hier_levels"); EXPECT_EQ (s, "1,1,1"); } { // all cells one level below the top cell db::LayoutQuery q (".c2x.*"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c1,c4,c5x"); } { // invalid top cell db::LayoutQuery q (".x.*"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, ""); } { // all cells two levels below the top cell db::LayoutQuery q (".*.*.*"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c1,c3,c1"); } { // all cells two levels below the top cell db::LayoutQuery q (".*.c4.*"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c1,c3"); } { db::LayoutQuery q ("cell (.*)[3]"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c1,c3,c1"); } { db::LayoutQuery q ("cell (.*)[1..2]"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c2x,c1,c4,c5x"); s = q2s_cell (iq, "cell_index"); EXPECT_EQ (s, "c2x,c1,c4,c5x"); s = q2s_cell (iq, "initial_cell_index"); EXPECT_EQ (s, "c2x,c2x,c2x,c2x"); s = q2s_var (iq, "initial_cell_name"); EXPECT_EQ (s, "c2x,c2x,c2x,c2x"); s = q2s_cell (iq, "parent_cell_index"); EXPECT_EQ (s, "nil,c2x,c2x,c2x"); s = q2s_var (iq, "parent_cell_name"); EXPECT_EQ (s, "nil,c2x,c2x,c2x"); s = q2s_var (iq, "path_names"); EXPECT_EQ (s, "c2x,c2x,c1,c2x,c4,c2x,c5x"); s = q2s_var (iq, "hier_levels"); EXPECT_EQ (s, "0,1,1,1"); } { db::LayoutQuery q ("cell (.*)(.*)?"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c2x,c1,c4,c5x"); s = q2s_var (iq, "bbox"); EXPECT_EQ (s, "(0,1;2,3),(),(),()"); } { db::LayoutQuery q ("cell (.*)[0..5]"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "nil,c2x,c1,c4,c1,c3,c5x,c1,c5x,c1"); s = q2s_var (iq, "references"); EXPECT_EQ (s, "nil,0,2,2,2,1,3,1,2,1"); s = q2s_var (iq, "weight"); EXPECT_EQ (s, "nil,0,2,2,7,1,3,1,2,1"); s = q2s_var (iq, "tot_weight"); EXPECT_EQ (s, "nil,0,2,2,14,2,6,6,2,2"); } { db::LayoutQuery q ("cell (.*)[0..5] where weight==7"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c1"); s = q2s_var (iq, "references"); EXPECT_EQ (s, "2"); s = q2s_var (iq, "weight"); EXPECT_EQ (s, "7"); s = q2s_var (iq, "tot_weight"); EXPECT_EQ (s, "14"); } { db::LayoutQuery q ("cell (.*)*"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "nil,c2x,c1,c4,c1,c3,c5x,c1,c5x,c1"); s = q2s_var (iq, "hier_levels"); EXPECT_EQ (s, "nil,0,1,1,2,2,3,4,1,2"); } { db::LayoutQuery q ("cell (.*)*.c5x"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c5x,c5x"); s = q2s_cell (iq, "cell_index"); EXPECT_EQ (s, "c5x,c5x"); s = q2s_cell (iq, "initial_cell_index"); EXPECT_EQ (s, "c2x,c2x"); s = q2s_var (iq, "initial_cell_name"); EXPECT_EQ (s, "c2x,c2x"); s = q2s_cell (iq, "parent_cell_index"); EXPECT_EQ (s, "c2x,c3"); s = q2s_var (iq, "parent_cell_name"); EXPECT_EQ (s, "c2x,c3"); s = q2s_var (iq, "path_names"); EXPECT_EQ (s, "c2x,c5x,c2x,c4,c3,c5x"); s = q2s_var (iq, "hier_levels"); EXPECT_EQ (s, "1,3"); } { db::LayoutQuery q ("c2x..c1"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c1,c1,c1,c1"); s = q2s_cell (iq, "cell_index"); EXPECT_EQ (s, "c1,c1,c1,c1"); s = q2s_cell (iq, "initial_cell_index"); EXPECT_EQ (s, "c2x,c2x,c2x,c2x"); s = q2s_var (iq, "initial_cell_name"); EXPECT_EQ (s, "c2x,c2x,c2x,c2x"); s = q2s_cell (iq, "parent_cell_index"); EXPECT_EQ (s, "c2x,c4,c5x,c5x"); s = q2s_var (iq, "parent_cell_name"); EXPECT_EQ (s, "c2x,c4,c5x,c5x"); s = q2s_var (iq, "path_names"); EXPECT_EQ (s, "c2x,c1,c2x,c4,c1,c2x,c4,c3,c5x,c1,c2x,c5x,c1"); s = q2s_var (iq, "hier_levels"); EXPECT_EQ (s, "1,2,4,2"); s = q2s_var (iq, "references"); EXPECT_EQ (s, "2,2,1,1"); s = q2s_var (iq, "weight"); EXPECT_EQ (s, "2,7,1,1"); s = q2s_var (iq, "tot_weight"); EXPECT_EQ (s, "2,14,6,2"); } { db::LayoutQuery q ("c2x...c1"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c1,c1,c1,c1"); s = q2s_cell (iq, "cell_index"); EXPECT_EQ (s, "c1,c1,c1,c1"); s = q2s_cell (iq, "initial_cell_index"); EXPECT_EQ (s, "c2x,c2x,c2x,c2x"); s = q2s_var (iq, "initial_cell_name"); EXPECT_EQ (s, "c2x,c2x,c2x,c2x"); s = q2s_cell (iq, "parent_cell_index"); EXPECT_EQ (s, "c2x,c4,c5x,c5x"); s = q2s_var (iq, "parent_cell_name"); EXPECT_EQ (s, "c2x,c4,c5x,c5x"); s = q2s_var (iq, "path_names"); EXPECT_EQ (s, "c2x,c1,c2x,c4,c1,c2x,c4,c3,c5x,c1,c2x,c5x,c1"); s = q2s_var (iq, "hier_levels"); EXPECT_EQ (s, "1,2,4,2"); s = q2s_var (iq, "references"); EXPECT_EQ (s, "2,2,1,1"); s = q2s_var (iq, "weight"); EXPECT_EQ (s, "2,7,1,1"); s = q2s_var (iq, "tot_weight"); EXPECT_EQ (s, "2,14,6,2"); } { db::LayoutQuery q ("c2x c1"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c1"); s = q2s_cell (iq, "cell_index"); EXPECT_EQ (s, "c1"); s = q2s_cell (iq, "initial_cell_index"); EXPECT_EQ (s, "c1"); s = q2s_var (iq, "initial_cell_name"); EXPECT_EQ (s, "c1"); s = q2s_cell (iq, "parent_cell_index"); EXPECT_EQ (s, "nil"); s = q2s_var (iq, "parent_cell_name"); EXPECT_EQ (s, "nil"); s = q2s_var (iq, "path_names"); EXPECT_EQ (s, "c1"); s = q2s_var (iq, "hier_levels"); EXPECT_EQ (s, "0"); s = q2s_var (iq, "references"); EXPECT_EQ (s, "0"); s = q2s_var (iq, "weight"); EXPECT_EQ (s, "0"); s = q2s_var (iq, "tot_weight"); EXPECT_EQ (s, "0"); s = q2s_var (iq, "instances"); EXPECT_EQ (s, "24"); } { // all cells one level below the top cell with an expression for the top cell db::LayoutQuery q (".$('c2'+'x').*"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c1,c4,c5x"); } { // Another way of saying "c2x.*" db::LayoutQuery q ("*.$(cell_name=='c2x'?'*':'')"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c1,c4,c5x"); } } TEST(2) { db::Layout g; g.insert_layer (0); g.insert_layer (1); db::Cell &c1 (g.cell (g.add_cell ("c1"))); db::Cell &c2 (g.cell (g.add_cell ("c2x"))); db::Cell &c3 (g.cell (g.add_cell ("c3"))); db::Cell &c4 (g.cell (g.add_cell ("c4"))); db::Cell &c5 (g.cell (g.add_cell ("c5x"))); c2.shapes (0).insert (db::Box (0, 1, 2, 3)); c1.shapes (1).insert (db::Box (0, 10, 10, 30)); db::FTrans f (1, true); db::Vector p (-10, 20); db::Trans t (f.rot (), p); db::Vector pp (10, -20); db::Trans tt (0, pp); // c4->c1 (aref) c4.insert (db::array (db::CellInst (c1.cell_index ()), t, db::Vector(1, 1), db::Vector (0, 2), 2, 3)); // c5->c1 c5.insert (db::array (db::CellInst (c1.cell_index ()), t)); // c3->c5 (3x) c3.insert (db::array (db::CellInst (c5.cell_index ()), t)); c3.insert (db::array (db::CellInst (c5.cell_index ()), tt)); c3.insert (db::array (db::CellInst (c5.cell_index ()), t)); // c4->c3 c4.insert (db::array (db::CellInst (c3.cell_index ()), t)); // c4->c1 c4.insert (db::array (db::CellInst (c1.cell_index ()), tt)); // c2->c1 (2x) c2.insert (db::array (db::CellInst (c1.cell_index ()), t)); c2.insert (db::array (db::CellInst (c1.cell_index ()), tt)); // c2->c4 (2x) c2.insert (db::array (db::CellInst (c4.cell_index ()), t)); c2.insert (db::array (db::CellInst (c4.cell_index ()), t)); // c2->c5 (2x) c2.insert (db::array (db::CellInst (c5.cell_index ()), t)); c2.insert (db::array (db::CellInst (c5.cell_index ()), tt)); { db::LayoutQuery q ("instances of c2x.c1"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c1,c1"); s = q2s_var (iq, "trans"); EXPECT_EQ (s, "r0 *1 10,-20,m45 *1 -10,20"); s = q2s_var (iq, "path_trans"); EXPECT_EQ (s, "r0 *1 10,-20,m45 *1 -10,20"); s = q2s_var (iq, "inst_bbox"); EXPECT_EQ (s, "(10,-10;20,10),(0,20;20,30)"); s = q2s_var (iq, "inst"); EXPECT_EQ (s, "cell_index=0 r0 10,-20,cell_index=0 m45 -10,20"); s = q2s_var (iq, "array_a"); EXPECT_EQ (s, "nil,nil"); s = q2s_var (iq, "array_b"); EXPECT_EQ (s, "nil,nil"); s = q2s_var (iq, "array_na"); EXPECT_EQ (s, "nil,nil"); s = q2s_var (iq, "array_nb"); EXPECT_EQ (s, "nil,nil"); s = q2s_var (iq, "array_ia"); EXPECT_EQ (s, "-1,-1"); s = q2s_var (iq, "array_ia"); EXPECT_EQ (s, "-1,-1"); } { db::LayoutQuery q ("instances of c4.c1"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c1,c1,c1,c1,c1,c1,c1"); s = q2s_var (iq, "trans"); EXPECT_EQ (s, "r0 *1 10,-20,m45 *1 -10,20,m45 *1 -9,21,m45 *1 -10,22,m45 *1 -9,23,m45 *1 -10,24,m45 *1 -9,25"); s = q2s_var (iq, "path_trans"); EXPECT_EQ (s, "r0 *1 10,-20,m45 *1 -10,20,m45 *1 -9,21,m45 *1 -10,22,m45 *1 -9,23,m45 *1 -10,24,m45 *1 -9,25"); s = q2s_var (iq, "inst_bbox"); EXPECT_EQ (s, "(10,-10;20,10),(0,20;20,30),(1,21;21,31),(0,22;20,32),(1,23;21,33),(0,24;20,34),(1,25;21,35)"); s = q2s_var (iq, "inst"); EXPECT_EQ (s, "cell_index=0 r0 10,-20,cell_index=0 m45 -10,20 array=(1,1,0,2 2x3),cell_index=0 m45 -10,20 array=(1,1,0,2 2x3),cell_index=0 m45 -10,20 array=(1,1,0,2 2x3),cell_index=0 m45 -10,20 array=(1,1,0,2 2x3),cell_index=0 m45 -10,20 array=(1,1,0,2 2x3),cell_index=0 m45 -10,20 array=(1,1,0,2 2x3)"); s = q2s_var (iq, "array_a"); EXPECT_EQ (s, "nil,1,1,1,1,1,1,1,1,1,1,1,1"); s = q2s_var (iq, "array_b"); EXPECT_EQ (s, "nil,0,2,0,2,0,2,0,2,0,2,0,2"); s = q2s_var (iq, "array_na"); EXPECT_EQ (s, "nil,2,2,2,2,2,2"); s = q2s_var (iq, "array_nb"); EXPECT_EQ (s, "nil,3,3,3,3,3,3"); s = q2s_var (iq, "array_ia"); EXPECT_EQ (s, "-1,0,1,0,1,0,1"); s = q2s_var (iq, "array_ib"); EXPECT_EQ (s, "-1,0,0,1,1,2,2"); } { db::LayoutQuery q ("instances of c4.c3"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c3"); s = q2s_var (iq, "trans"); EXPECT_EQ (s, "m45 *1 -10,20"); s = q2s_var (iq, "path_trans"); EXPECT_EQ (s, "m45 *1 -10,20"); } { db::LayoutQuery q ("instances of ...*"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_expr (iq, "inst&&inst.cell.qname"); EXPECT_EQ (s, "nil,c1,c1,c4,c4,c5x,c5x,c1,c1,c1,c1,c1,c1,c1,c3,c5x,c5x,c5x,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c3,c5x,c5x,c5x,c1,c1,c1,c1,c1"); } { db::LayoutQuery q ("arrays of c4.c1"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c1,c1"); s = q2s_var (iq, "trans"); EXPECT_EQ (s, "r0 *1 10,-20,m45 *1 -10,20"); s = q2s_var (iq, "path_trans"); EXPECT_EQ (s, "r0 *1 10,-20,m45 *1 -10,20"); s = q2s_var (iq, "inst_bbox"); EXPECT_EQ (s, "(20,-30;30,-10),(10,20;25,41)"); s = q2s_var (iq, "inst"); EXPECT_EQ (s, "cell_index=0 r0 10,-20,cell_index=0 m45 -10,20 array=(1,1,0,2 2x3)"); s = q2s_var (iq, "array_a"); EXPECT_EQ (s, "nil,1,1"); s = q2s_var (iq, "array_b"); EXPECT_EQ (s, "nil,0,2"); s = q2s_var (iq, "array_na"); EXPECT_EQ (s, "nil,2"); s = q2s_var (iq, "array_nb"); EXPECT_EQ (s, "nil,3"); s = q2s_var (iq, "array_ia"); EXPECT_EQ (s, "nil,nil"); s = q2s_var (iq, "array_ib"); EXPECT_EQ (s, "nil,nil"); } { db::LayoutQuery q ("arrays of (.*)*.c1"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1"); s = q2s_var (iq, "parent_cell_name"); EXPECT_EQ (s, "c2x,c2x,c4,c4,c5x,c5x,c5x,c4,c4,c5x,c5x,c5x,c5x,c5x"); s = q2s_var (iq, "trans"); EXPECT_EQ (s, "r0 *1 10,-20,m45 *1 -10,20,r0 *1 10,-20,m45 *1 -10,20,m45 *1 -10,20,m45 *1 -10,20,m45 *1 -10,20,r0 *1 10,-20,m45 *1 -10,20,m45 *1 -10,20,m45 *1 -10,20,m45 *1 -10,20,m45 *1 -10,20,m45 *1 -10,20"); s = q2s_var (iq, "path_trans"); EXPECT_EQ (s, "r0 *1 10,-20,m45 *1 -10,20,m45 *1 -30,30,r0 *1 10,10,m45 *1 10,10,r0 *1 20,20,r0 *1 20,20,m45 *1 -30,30,r0 *1 10,10,m45 *1 10,10,r0 *1 20,20,r0 *1 20,20,m45 *1 0,0,r0 *1 10,10"); } { db::LayoutQuery q ("arrays of (.*)*.c1 where trans.rot==0"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c1,c1,c1"); s = q2s_var (iq, "parent_cell_name"); EXPECT_EQ (s, "c2x,c4,c4"); s = q2s_var (iq, "trans"); EXPECT_EQ (s, "r0 *1 10,-20,r0 *1 10,-20,r0 *1 10,-20"); s = q2s_var (iq, "path_trans"); EXPECT_EQ (s, "r0 *1 10,-20,m45 *1 -30,30,m45 *1 -30,30"); } { db::LayoutQuery q ("arrays of ..'c1' where parent_cell_name=='c4' && trans.rot==0"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c1,c1"); s = q2s_var (iq, "parent_cell_name"); EXPECT_EQ (s, "c4,c4"); s = q2s_var (iq, "trans"); EXPECT_EQ (s, "r0 *1 10,-20,r0 *1 10,-20"); s = q2s_var (iq, "path_trans"); EXPECT_EQ (s, "m45 *1 -30,30,m45 *1 -30,30"); } } TEST(3) { db::Layout g; g.insert_layer (0, db::LayerProperties ("l0")); g.insert_layer (1, db::LayerProperties ("l1")); g.insert_layer (2, db::LayerProperties ("l2")); db::Cell &c1 (g.cell (g.add_cell ("c1"))); db::Cell &c2 (g.cell (g.add_cell ("c2x"))); db::Cell &c3 (g.cell (g.add_cell ("c3"))); db::Cell &c4 (g.cell (g.add_cell ("c4"))); db::Cell &c5 (g.cell (g.add_cell ("c5x"))); c2.shapes (0).insert (db::Box (0, 1, 2, 3)); c2.shapes (1).insert (db::Polygon (db::Box (0, 1, 2, 3))); c2.shapes (1).insert (db::Edge (db::Point (0, 1), db::Point (2, 3))); c2.shapes (2).insert (db::Text ("hallo", db::Trans (db::Vector (10, 11)))); c1.shapes (1).insert (db::Box (0, 10, 10, 30)); db::FTrans f (1, true); db::Vector p (-10, 20); db::Trans t (f.rot (), p); db::Vector pp (10, -20); db::Trans tt (0, pp); // c4->c1 (aref) c4.insert (db::array (db::CellInst (c1.cell_index ()), t, db::Vector(1, 1), db::Vector (0, 2), 2, 3)); // c5->c1 c5.insert (db::array (db::CellInst (c1.cell_index ()), t)); // c3->c5 (3x) c3.insert (db::array (db::CellInst (c5.cell_index ()), t)); c3.insert (db::array (db::CellInst (c5.cell_index ()), tt)); c3.insert (db::array (db::CellInst (c5.cell_index ()), t)); // c4->c3 c4.insert (db::array (db::CellInst (c3.cell_index ()), t)); // c4->c1 c4.insert (db::array (db::CellInst (c1.cell_index ()), tt)); // c2->c1 (2x) c2.insert (db::array (db::CellInst (c1.cell_index ()), t)); c2.insert (db::array (db::CellInst (c1.cell_index ()), tt)); // c2->c4 (2x) c2.insert (db::array (db::CellInst (c4.cell_index ()), t)); c2.insert (db::array (db::CellInst (c4.cell_index ()), t)); // c2->c5 (2x) c2.insert (db::array (db::CellInst (c5.cell_index ()), t)); c2.insert (db::array (db::CellInst (c5.cell_index ()), tt)); { db::LayoutQuery q ("shapes of c1"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c1"); s = q2s_var (iq, "shape"); EXPECT_EQ (s, "box (0,10;10,30)"); } { db::LayoutQuery q ("boxes of *"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c2x,c1"); s = q2s_var (iq, "shape"); EXPECT_EQ (s, "box (0,1;2,3),box (0,10;10,30)"); s = q2s_var (iq, "layer_info"); EXPECT_EQ (s, "l0,l1"); } { db::LayoutQuery q ("boxes of * where shape.area > 10"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c1"); s = q2s_var (iq, "shape"); EXPECT_EQ (s, "box (0,10;10,30)"); s = q2s_var (iq, "layer_info"); EXPECT_EQ (s, "l1"); } { db::LayoutQuery q ("shapes of c2x"); db::LayoutQueryIterator iq (q, &g); std::string s; s = q2s_var (iq, "shape"); EXPECT_EQ (s, "box (0,1;2,3),polygon (0,1;0,3;2,3;2,1),edge (0,1;2,3),text ('hallo',r0 10,11)"); s = q2s_var (iq, "layer_info"); EXPECT_EQ (s, "l0,l1,l1,l2"); s = q2s_var (iq, "layer_index"); EXPECT_EQ (s, "0,1,1,2"); s = q2s_var (iq, "bbox"); EXPECT_EQ (s, "(0,1;2,3),(0,1;2,3),(0,1;2,3),(10,11;10,11)"); } { db::LayoutQuery q ("polygons of c2x"); db::LayoutQueryIterator iq (q, &g); std::string s; s = q2s_var (iq, "shape"); EXPECT_EQ (s, "polygon (0,1;0,3;2,3;2,1)"); s = q2s_var (iq, "layer_info"); EXPECT_EQ (s, "l1"); s = q2s_var (iq, "layer_index"); EXPECT_EQ (s, "1"); s = q2s_var (iq, "bbox"); EXPECT_EQ (s, "(0,1;2,3)"); } { db::LayoutQuery q ("boxes of c2x"); db::LayoutQueryIterator iq (q, &g); std::string s; s = q2s_var (iq, "shape"); EXPECT_EQ (s, "box (0,1;2,3)"); s = q2s_var (iq, "layer_info"); EXPECT_EQ (s, "l0"); s = q2s_var (iq, "layer_index"); EXPECT_EQ (s, "0"); s = q2s_var (iq, "bbox"); EXPECT_EQ (s, "(0,1;2,3)"); } { db::LayoutQuery q ("boxes, polygons of c2x"); db::LayoutQueryIterator iq (q, &g); std::string s; s = q2s_var (iq, "shape"); EXPECT_EQ (s, "box (0,1;2,3),polygon (0,1;0,3;2,3;2,1)"); s = q2s_var (iq, "layer_info"); EXPECT_EQ (s, "l0,l1"); s = q2s_var (iq, "layer_index"); EXPECT_EQ (s, "0,1"); s = q2s_var (iq, "bbox"); EXPECT_EQ (s, "(0,1;2,3),(0,1;2,3)"); } { db::LayoutQuery q ("paths of c2x"); db::LayoutQueryIterator iq (q, &g); std::string s; s = q2s_var (iq, "shape"); EXPECT_EQ (s, ""); s = q2s_var (iq, "layer_info"); EXPECT_EQ (s, ""); s = q2s_var (iq, "layer_index"); EXPECT_EQ (s, ""); s = q2s_var (iq, "bbox"); EXPECT_EQ (s, ""); } c4.shapes (2).insert (db::Box (0, -1, 2, 1)); { db::LayoutQuery q ("boxes of c2x.*"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c1,c4"); s = q2s_var (iq, "shape"); EXPECT_EQ (s, "box (0,10;10,30),box (0,-1;2,1)"); s = q2s_var (iq, "layer_info"); EXPECT_EQ (s, "l1,l2"); } { db::LayoutQuery q ("boxes of instances of c2x.*"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c1,c1,c4,c4"); s = q2s_var (iq, "shape"); EXPECT_EQ (s, "box (0,10;10,30),box (0,10;10,30),box (0,-1;2,1),box (0,-1;2,1)"); s = q2s_expr (iq, "bbox.transformed(path_trans)"); EXPECT_EQ (s, "(10,-10;20,10),(0,20;20,30),(-11,20;-9,22),(-11,20;-9,22)"); s = q2s_var (iq, "layer_info"); EXPECT_EQ (s, "l1,l1,l2,l2"); } { db::LayoutQuery q ("boxes on 'l1';'l2' of instances of c2x.*"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c1,c1,c4,c4"); s = q2s_var (iq, "shape"); EXPECT_EQ (s, "box (0,10;10,30),box (0,10;10,30),box (0,-1;2,1),box (0,-1;2,1)"); s = q2s_var (iq, "layer_info"); EXPECT_EQ (s, "l1,l1,l2,l2"); } { db::LayoutQuery q ("boxes on 'l2' of instances of c2x.*"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c4,c4"); s = q2s_var (iq, "shape"); EXPECT_EQ (s, "box (0,-1;2,1),box (0,-1;2,1)"); s = q2s_var (iq, "layer_info"); EXPECT_EQ (s, "l2,l2"); } { db::LayoutQuery q ("boxes on 'l0';'l2' of instances of c2x.*"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c4,c4"); s = q2s_var (iq, "shape"); EXPECT_EQ (s, "box (0,-1;2,1),box (0,-1;2,1)"); s = q2s_var (iq, "layer_info"); EXPECT_EQ (s, "l2,l2"); } { db::LayoutQuery q ("boxes of instances of c2x..*"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c1,c1,c4,c4,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1"); s = q2s_var (iq, "shape"); EXPECT_EQ (s, "box (0,10;10,30),box (0,10;10,30),box (0,-1;2,1),box (0,-1;2,1),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30)"); } { db::LayoutQuery q ("boxes of instances of c2x..* where true"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c1,c1,c4,c4,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1"); s = q2s_var (iq, "shape"); EXPECT_EQ (s, "box (0,10;10,30),box (0,10;10,30),box (0,-1;2,1),box (0,-1;2,1),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30)"); } { db::LayoutQuery q ("boxes of instances of c2x.."); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c2x,c1,c1,c4,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c4,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1"); s = q2s_var (iq, "shape"); EXPECT_EQ (s, "box (0,1;2,3),box (0,10;10,30),box (0,10;10,30),box (0,-1;2,1),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,-1;2,1),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30)"); } { db::LayoutQuery q ("boxes of instances of c2x.. where true"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c2x,c1,c1,c4,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c4,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1"); s = q2s_var (iq, "shape"); EXPECT_EQ (s, "box (0,1;2,3),box (0,10;10,30),box (0,10;10,30),box (0,-1;2,1),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,-1;2,1),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30),box (0,10;10,30)"); } } void init_layout (db::Layout &g) { g = db::Layout (); g.insert_layer (0, db::LayerProperties ("l0")); g.insert_layer (1, db::LayerProperties ("l1")); g.insert_layer (2, db::LayerProperties ("l2")); db::Cell &c1 (g.cell (g.add_cell ("c1"))); db::Cell &c2 (g.cell (g.add_cell ("c2x"))); db::Cell &c3 (g.cell (g.add_cell ("c3"))); db::Cell &c4 (g.cell (g.add_cell ("c4"))); db::Cell &c5 (g.cell (g.add_cell ("c5x"))); c2.shapes (0).insert (db::Box (0, 1, 2, 3)); c2.shapes (1).insert (db::Polygon (db::Box (0, 1, 2, 3))); c2.shapes (1).insert (db::Edge (db::Point (0, 1), db::Point (2, 3))); c2.shapes (2).insert (db::Text ("hallo", db::Trans (db::Vector (10, 11)))); c1.shapes (1).insert (db::Box (0, 10, 10, 30)); db::FTrans f (1, true); db::Vector p (-10, 20); db::Trans t (f.rot (), p); db::Vector pp (10, -20); db::Trans tt (0, pp); // c4->c1 (aref) c4.insert (db::array (db::CellInst (c1.cell_index ()), t, db::Vector(1, 1), db::Vector (0, 2), 2, 3)); // c5->c1 c5.insert (db::array (db::CellInst (c1.cell_index ()), t)); // c3->c5 (3x) c3.insert (db::array (db::CellInst (c5.cell_index ()), t)); c3.insert (db::array (db::CellInst (c5.cell_index ()), tt)); c3.insert (db::array (db::CellInst (c5.cell_index ()), t)); // c4->c3 c4.insert (db::array (db::CellInst (c3.cell_index ()), t)); // c4->c1 c4.insert (db::array (db::CellInst (c1.cell_index ()), tt)); // c2->c1 (2x) c2.insert (db::array (db::CellInst (c1.cell_index ()), t)); c2.insert (db::array (db::CellInst (c1.cell_index ()), tt)); // c2->c4 (2x) c2.insert (db::array (db::CellInst (c4.cell_index ()), t)); c2.insert (db::array (db::CellInst (c4.cell_index ()), t)); // c2->c5 (2x) c2.insert (db::array (db::CellInst (c5.cell_index ()), t)); c2.insert (db::array (db::CellInst (c5.cell_index ()), tt)); } TEST(4) { db::Layout g; init_layout (g); { db::LayoutQuery q ("select cell_name+'#'+cell_index from *"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "data"); EXPECT_EQ (s, "c2x#1,c4#3,c3#2,c5x#4,c1#0"); } { db::LayoutQuery q ("select $1 from 'c(*)'"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "data"); EXPECT_EQ (s, "2x,4,3,5x,1"); } { db::LayoutQuery q ("select cell_index+'#'+cell_name from * sorted by cell_name"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "data"); EXPECT_EQ (s, "0#c1,1#c2x,2#c3,3#c4,4#c5x"); } { db::LayoutQuery q ("select cell_index+'#'+cell_name from ..* sorted by cell_name"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "data"); EXPECT_EQ (s, "0#c1,0#c1,0#c1,0#c1,1#c2x,2#c3,3#c4,4#c5x,4#c5x"); } { db::LayoutQuery q ("select cell_index+'#'+cell_name from ..* sorted by cell_name unique"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "data"); EXPECT_EQ (s, "0#c1,1#c2x,2#c3,3#c4,4#c5x"); } { db::LayoutQuery q ("select cell_index+'#'+cell_name from instances of ..* sorted by cell_name"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "data"); EXPECT_EQ (s, "0#c1,0#c1,0#c1,0#c1,0#c1,0#c1,0#c1,0#c1,0#c1,0#c1,0#c1,0#c1,0#c1,0#c1,0#c1,0#c1,0#c1,0#c1,0#c1,0#c1,0#c1,0#c1,0#c1,0#c1,1#c2x,2#c3,2#c3,3#c4,3#c4,4#c5x,4#c5x,4#c5x,4#c5x,4#c5x,4#c5x,4#c5x,4#c5x"); } { db::LayoutQuery q ("select cell_index+'#'+cell_name from instances of ..* sorted by cell_name unique"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "data"); EXPECT_EQ (s, "0#c1,1#c2x,2#c3,3#c4,4#c5x"); } } TEST(51a) { if (! db::default_editable_mode ()) { return; } db::Layout g; init_layout (g); { db::LayoutQuery ("delete cell *x").execute (g); db::LayoutQuery q ("select cell_name+'#'+cell_index from *"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "data"); EXPECT_EQ (s, "c4#3,c1#0,c3#2"); } { db::LayoutQuery ("delete cell *").execute (g); db::LayoutQuery q ("select cell_name+'#'+cell_index from *"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "data"); EXPECT_EQ (s, ""); } } TEST(51b) { if (! db::default_editable_mode ()) { return; } db::Layout g; init_layout (g); { db::LayoutQuery q ("delete cell *x"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, ""); } } TEST(51c) { if (! db::default_editable_mode ()) { return; } db::Layout g; init_layout (g); { db::LayoutQuery q ("delete cell *x pass"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var_skip (iq, "cell_name"); EXPECT_EQ (s, "c2x,c5x"); } { db::LayoutQuery q ("delete cell *x pass"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c2x,c5x"); } { db::LayoutQuery q ("delete cell *x pass"); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, ""); } } TEST(52a) { if (! db::default_editable_mode ()) { return; } db::Layout g; init_layout (g); { db::LayoutQuery q ("shapes of c2x"); db::LayoutQueryIterator iq (q, &g); std::string s; s = q2s_var (iq, "shape"); EXPECT_EQ (s, "box (0,1;2,3),polygon (0,1;0,3;2,3;2,1),edge (0,1;2,3),text ('hallo',r0 10,11)"); s = q2s_var (iq, "layer_info"); EXPECT_EQ (s, "l0,l1,l1,l2"); } { db::LayoutQuery q ("shapes on layer l0,l1 from c2x"); db::LayoutQueryIterator iq (q, &g); std::string s; s = q2s_var (iq, "shape"); EXPECT_EQ (s, "box (0,1;2,3),polygon (0,1;0,3;2,3;2,1),edge (0,1;2,3)"); } { db::LayoutQuery ("delete shapes on layer l1 from *").execute (g); db::LayoutQuery q ("shapes of c2x"); db::LayoutQueryIterator iq (q, &g); std::string s; s = q2s_var (iq, "shape"); EXPECT_EQ (s, "box (0,1;2,3),text ('hallo',r0 10,11)"); } { init_layout (g); db::LayoutQuery ("delete shapes on layer l1 from c4").execute (g); db::LayoutQuery q ("shapes of c2x"); db::LayoutQueryIterator iq (q, &g); std::string s; s = q2s_var (iq, "shape"); EXPECT_EQ (s, "box (0,1;2,3),polygon (0,1;0,3;2,3;2,1),edge (0,1;2,3),text ('hallo',r0 10,11)"); db::LayoutQuery ("delete polygons from *").execute (g); s = q2s_var (iq, "shape"); EXPECT_EQ (s, "box (0,1;2,3),edge (0,1;2,3),text ('hallo',r0 10,11)"); } } TEST(52b) { if (! db::default_editable_mode ()) { return; } db::Layout g; init_layout (g); { db::LayoutQuery q ("delete shapes on layer l1 from * pass"); db::LayoutQueryIterator iq (q, &g); std::string s; s = q2s_var (iq, "shape"); EXPECT_EQ (s, "polygon (0,1;0,3;2,3;2,1),edge (0,1;2,3),box (0,10;10,30)"); } } TEST(53) { if (! db::default_editable_mode ()) { return; } db::Layout g; init_layout (g); { db::LayoutQuery q ("cell ..*"); std::string s; db::LayoutQueryIterator iq (q, &g); s = q2s_var (iq, "path_names", ";"); EXPECT_EQ (s, "c2x;c2x,c1;c2x,c4;c2x,c5x;c2x,c4,c1;c2x,c4,c3;c2x,c4,c3,c5x;c2x,c4,c3,c5x,c1;c2x,c5x,c1"); db::LayoutQuery ("delete instances of *.c1").execute (g); s = q2s_var (iq, "path_names", ";"); EXPECT_EQ (s, "c1;c2x;c2x,c4;c2x,c5x;c2x,c4,c3;c2x,c4,c3,c5x"); } init_layout (g); { std::string s; db::LayoutQuery q ("delete instances of *.c1 pass"); db::LayoutQueryIterator iq (q, &g); s = q2s_var (iq, "path_names", ";"); EXPECT_EQ (s, "c2x,c1;c2x,c1;c4,c1;c4,c1;c5x,c1"); } init_layout (g); { db::LayoutQuery q ("cell ..*"); std::string s; db::LayoutQueryIterator iq (q, &g); s = q2s_var (iq, "path_names", ";"); EXPECT_EQ (s, "c2x;c2x,c1;c2x,c4;c2x,c5x;c2x,c4,c1;c2x,c4,c3;c2x,c4,c3,c5x;c2x,c4,c3,c5x,c1;c2x,c5x,c1"); db::LayoutQuery ("delete instances of c1").execute (g); s = q2s_var (iq, "path_names", ";"); EXPECT_EQ (s, "c1;c2x;c2x,c4;c2x,c5x;c2x,c4,c3;c2x,c4,c3,c5x"); } init_layout (g); { db::LayoutQuery q ("cell ..*"); std::string s; db::LayoutQueryIterator iq (q, &g); s = q2s_var (iq, "path_names", ";"); EXPECT_EQ (s, "c2x;c2x,c1;c2x,c4;c2x,c5x;c2x,c4,c1;c2x,c4,c3;c2x,c4,c3,c5x;c2x,c4,c3,c5x,c1;c2x,c5x,c1"); db::LayoutQuery ("delete instances of *").execute (g); s = q2s_var (iq, "path_names", ";"); EXPECT_EQ (s, "c1;c2x;c3;c4;c5x"); } } TEST(61) { if (! db::default_editable_mode ()) { return; } db::Layout g; init_layout (g); { db::LayoutQuery q ("shapes of c2x"); db::LayoutQueryIterator iq (q, &g); std::string s; s = q2s_var (iq, "shape"); EXPECT_EQ (s, "box (0,1;2,3),polygon (0,1;0,3;2,3;2,1),edge (0,1;2,3),text ('hallo',r0 10,11)"); s = q2s_var (iq, "layer_info"); EXPECT_EQ (s, "l0,l1,l1,l2"); db::LayoutQuery ("with boxes from * do shape.polygon = Polygon.new(shape.bbox)").execute (g); s = q2s_var (iq, "shape"); EXPECT_EQ (s, "polygon (0,1;0,3;2,3;2,1),polygon (0,1;0,3;2,3;2,1),edge (0,1;2,3),text ('hallo',r0 10,11)"); db::LayoutQuery ("with polygons from * do shape.box = shape.bbox").execute (g); s = q2s_var (iq, "shape"); EXPECT_EQ (s, "box (0,1;2,3),edge (0,1;2,3),box (0,1;2,3),text ('hallo',r0 10,11)"); s = q2s_var (iq, "layer_info"); EXPECT_EQ (s, "l0,l1,l1,l2"); db::LayoutQuery ("with texts from * do shape.text_string = shape.text_string + 'xx'").execute (g); s = q2s_var (iq, "shape"); EXPECT_EQ (s, "box (0,1;2,3),edge (0,1;2,3),box (0,1;2,3),text ('halloxx',r0 10,11)"); db::LayoutQuery ("with texts from * where shape.text_string ~ '(*)all(*)' do shape.text_string = $1 + $2").execute (g); s = q2s_var (iq, "shape"); EXPECT_EQ (s, "box (0,1;2,3),edge (0,1;2,3),box (0,1;2,3),text ('hoxx',r0 10,11)"); } init_layout (g); { std::string s; db::LayoutQuery qq ("shapes from *"); db::LayoutQueryIterator iqq (qq, &g); s = q2s_var (iqq, "shape"); EXPECT_EQ (s, "box (0,1;2,3),polygon (0,1;0,3;2,3;2,1),edge (0,1;2,3),text ('hallo',r0 10,11),box (0,10;10,30)"); db::LayoutQuery ("with boxes from * do shape.polygon = Polygon.new(shape.bbox)").execute (g); s = q2s_var (iqq, "shape"); EXPECT_EQ (s, "polygon (0,1;0,3;2,3;2,1),polygon (0,1;0,3;2,3;2,1),edge (0,1;2,3),text ('hallo',r0 10,11),polygon (0,10;0,30;10,30;10,10)"); db::LayoutQuery q ("with polygons from * do shape.box = shape.bbox pass"); db::LayoutQueryIterator iq (q, &g); s = q2s_var (iq, "shape"); EXPECT_EQ (s, "polygon (0,1;0,3;2,3;2,1),polygon (0,1;0,3;2,3;2,1),polygon (0,10;0,30;10,30;10,10)"); s = q2s_var (iqq, "shape"); EXPECT_EQ (s, "box (0,1;2,3),edge (0,1;2,3),box (0,1;2,3),text ('hallo',r0 10,11),box (0,10;10,30)"); } init_layout (g); { std::string s; db::LayoutQuery qq ("shapes from *"); db::LayoutQueryIterator iqq (qq, &g); s = q2s_var (iqq, "shape"); EXPECT_EQ (s, "box (0,1;2,3),polygon (0,1;0,3;2,3;2,1),edge (0,1;2,3),text ('hallo',r0 10,11),box (0,10;10,30)"); db::LayoutQuery ("with boxes from * do shape.polygon = Polygon.new(shape.bbox)").execute (g); s = q2s_var (iqq, "shape"); EXPECT_EQ (s, "polygon (0,1;0,3;2,3;2,1),polygon (0,1;0,3;2,3;2,1),edge (0,1;2,3),text ('hallo',r0 10,11),polygon (0,10;0,30;10,30;10,10)"); db::LayoutQuery q ("with polygons from * do shape.box = shape.bbox"); db::LayoutQueryIterator iq (q, &g); s = q2s_var (iq, "shape"); EXPECT_EQ (s, ""); s = q2s_var (iqq, "shape"); EXPECT_EQ (s, "box (0,1;2,3),edge (0,1;2,3),box (0,1;2,3),text ('hallo',r0 10,11),box (0,10;10,30)"); } init_layout (g); { db::LayoutQuery q ("*"); db::LayoutQueryIterator iq (q, &g); std::string s; s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "c2x,c4,c3,c5x,c1"); db::LayoutQuery ("with * do cell.name = 'i' + cell_index").execute (g); s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "i1,i3,i2,i4,i0"); } init_layout (g); { EXPECT_EQ (q2s_var (g, "shapes on l1 from c2x", "shape"), "polygon (0,1;0,3;2,3;2,1),edge (0,1;2,3)"); EXPECT_EQ (q2s_var (g, "shapes on l1 from c1", "shape"), "box (0,10;10,30)"); db::LayoutQuery ("with shapes from instances of c2x..* do initial_cell.shapes(1).insert(shape).transform(path_trans)").execute (g); db::LayoutQuery ("with shapes from c2x..* do shape.delete").execute (g); EXPECT_EQ (q2s_var (g, "shapes on l1 from c2x", "shape"), "polygon (0,1;0,3;2,3;2,1),edge (0,1;2,3),box (10,-10;20,10),box (0,20;20,30),box (-20,30;0,40),box (10,20;20,40),box (20,10;40,20),box (20,30;30,50),box (20,30;30,50),box (-20,30;0,40),box (10,20;20,40),box (20,10;40,20),box (20,30;30,50),box (20,30;30,50),box (10,0;30,10),box (10,20;20,40)"); EXPECT_EQ (q2s_var (g, "shapes on l1 from c1", "shape"), ""); } init_layout (g); { g.add_cell ("cx"); EXPECT_EQ (q2s_var (g, "instances of ..c4", "inst"), "cell_index=3 m45 -10,20,cell_index=3 m45 -10,20"); db::LayoutQuery ("with instances of ..c4 do inst.cell_index = layout.cell_by_name('cx')").execute (g); EXPECT_EQ (q2s_var (g, "instances of ..c4", "inst"), "nil"); EXPECT_EQ (q2s_var (g, "instances of .*..c4", "inst"), ""); EXPECT_EQ (q2s_var (g, "instances of ..cx", "inst"), "cell_index=5 m45 -10,20,cell_index=5 m45 -10,20"); db::LayoutQuery ("delete instances of .*..c4").execute (g); db::LayoutQuery ("delete instances of .*..cx").execute (g); EXPECT_EQ (q2s_var (g, "instances of .*..c4", "inst"), ""); EXPECT_EQ (q2s_var (g, "instances of .*..cx", "inst"), ""); } init_layout (g); { EXPECT_EQ (q2s_var (g, "instances of ..c4", "inst"), "cell_index=3 m45 -10,20,cell_index=3 m45 -10,20"); db::LayoutQuery ("with instances of ..c4 do inst.cell_index = <>").execute (g); EXPECT_EQ (q2s_var (g, "instances of ..c4", "inst"), "nil"); EXPECT_EQ (q2s_var (g, "instances of .*..c4", "inst"), ""); EXPECT_EQ (q2s_var (g, "instances of ..cy", "inst"), "cell_index=5 m45 -10,20,cell_index=5 m45 -10,20"); } init_layout (g); { EXPECT_EQ (q2s_var (g, "instances of ..c4", "inst"), "cell_index=3 m45 -10,20,cell_index=3 m45 -10,20"); db::LayoutQuery ("with instances of ..c4 do inst.cell_index = <<\"Basic\" + \".\" + \"TEXT\">>").execute (g); EXPECT_EQ (q2s_var (g, "instances of ..c4", "inst"), "nil"); EXPECT_EQ (q2s_var (g, "instances of .*..c4", "inst"), ""); EXPECT_EQ (q2s_var (g, "instances of ..\"Basic.*\"", "inst"), "cell_index=5 m45 -10,20,cell_index=5 m45 -10,20"); } } TEST(62) { if (! db::default_editable_mode ()) { return; } db::Library *basic_lib = db::LibraryManager::instance ().lib_ptr_by_name ("Basic"); EXPECT_EQ (basic_lib != 0, true); if (!basic_lib) { return; } size_t text_id = basic_lib->layout ().pcell_by_name ("TEXT").second; const db::PCellDeclaration *text_decl = basic_lib->layout ().pcell_declaration (text_id); std::vector values; const std::vector &pd = text_decl->get_parameter_declarations (); for (std::vector::const_iterator p = pd.begin (); p != pd.end (); ++p) { if (p->get_name () == "text") { values.push_back (tl::Variant ("T1")); } else { values.push_back (p->get_default ()); } } size_t v1t1 = basic_lib->layout ().get_pcell_variant (text_id, values); values.clear (); for (std::vector::const_iterator p = pd.begin (); p != pd.end (); ++p) { if (p->get_name () == "text") { values.push_back (tl::Variant ("T2")); } else { values.push_back (p->get_default ()); } } size_t v1t2 = basic_lib->layout ().get_pcell_variant (text_id, values); db::Layout g; init_layout (g); size_t c3index = g.get_lib_proxy (basic_lib, v1t1); size_t c4index = g.get_lib_proxy (basic_lib, v1t2); db::Cell &c1 (g.cell (g.add_cell ("c1"))); db::Cell &c2 (g.cell (g.add_cell ("c2"))); db::Cell &c3 (g.cell (c3index)); db::Cell &c4 (g.cell (c4index)); db::FTrans f (1, true); db::Vector p (-10, 20); db::Trans t (f.rot (), p); db::Vector pp (10, -20); db::Trans tt (0, pp); // c1->c3 c1.insert (db::array (db::CellInst (c3.cell_index ()), t)); // c2->c4 c2.insert (db::array (db::CellInst (c4.cell_index ()), t)); // c2->c1 (2x) c2.insert (db::array (db::CellInst (c1.cell_index ()), t)); c2.insert (db::array (db::CellInst (c1.cell_index ()), tt)); { db::LayoutQuery q ("\"Basic.*\""); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "cell_name"); EXPECT_EQ (s, "Basic.TEXT,Basic.TEXT"); } { db::LayoutQuery q ("instances of ...\"Basic.*\""); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_expr (iq, "inst.cell.display_title"); EXPECT_EQ (s, "Basic.TEXT('T2'),Basic.TEXT('T1'),Basic.TEXT('T1')"); } { db::LayoutQuery q ("select inst.pcell_parameters_by_name[\"text\"] from instances of ...* where cell_name ~ \"Basic.*\""); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "data"); EXPECT_EQ (s, "T2,T1,T1"); } { db::LayoutQuery q ("select inst.pcell_parameter(\"text\") from instances of ...* where cell_name ~ \"Basic.*\""); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "data"); EXPECT_EQ (s, "T2,T1,T1"); } { db::LayoutQuery q ("select inst[\"text\"] from instances of ...* where cell_name ~ \"Basic.*\""); db::LayoutQueryIterator iq (q, &g); std::string s = q2s_var (iq, "data"); EXPECT_EQ (s, "T2,T1,T1"); } }