From 4cd8772e70ccf0f4da24216ae998e33761051ee7 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 24 Jul 2024 22:29:09 +0200 Subject: [PATCH] Convenience methods Shape#properties, Layout#properties, Cell#properties, Instance#properties --- src/db/db/gsiDeclDbCell.cc | 58 +++++++++++++++++++++++++++++++-- src/db/db/gsiDeclDbLayout.cc | 23 ++++++++++++- src/db/db/gsiDeclDbShape.cc | 26 +++++++++++++++ testdata/ruby/dbLayoutTests1.rb | 2 ++ testdata/ruby/dbLayoutTests2.rb | 4 +++ testdata/ruby/dbShapesTest.rb | 22 +++++++++++++ 6 files changed, 131 insertions(+), 4 deletions(-) diff --git a/src/db/db/gsiDeclDbCell.cc b/src/db/db/gsiDeclDbCell.cc index fc32fa381..c3c053550 100644 --- a/src/db/db/gsiDeclDbCell.cc +++ b/src/db/db/gsiDeclDbCell.cc @@ -1104,14 +1104,14 @@ static void set_cell_property (db::Cell *c, const tl::Variant &key, const tl::Va c->prop_id (layout->properties_repository ().properties_id (props)); } -static tl::Variant get_cell_property (db::Cell *c, const tl::Variant &key) +static tl::Variant get_cell_property (const db::Cell *c, const tl::Variant &key) { db::properties_id_type id = c->prop_id (); if (id == 0) { return tl::Variant (); } - db::Layout *layout = c->layout (); + const db::Layout *layout = c->layout (); if (! layout) { throw tl::Exception (tl::to_string (tr ("Cell does not reside inside a layout - cannot retrieve properties"))); } @@ -1130,6 +1130,26 @@ static tl::Variant get_cell_property (db::Cell *c, const tl::Variant &key) } } +static tl::Variant get_cell_properties (const db::Cell *c) +{ + db::properties_id_type id = c->prop_id (); + if (id == 0) { + return tl::Variant::empty_array (); + } + + const db::Layout *layout = c->layout (); + if (! layout) { + throw tl::Exception (tl::to_string (tr ("Cell does not reside inside a layout - cannot retrieve properties"))); + } + + tl::Variant res = tl::Variant::empty_array (); + const db::PropertiesRepository::properties_set &props = layout->properties_repository ().properties (id); + for (auto i = props.begin (); i != props.end (); ++i) { + res.insert (layout->properties_repository ().prop_name (i->first), i->second); + } + return res; +} + static bool is_pcell_variant (const db::Cell *cell) { tl_assert (cell->layout () != 0); @@ -1841,10 +1861,16 @@ Class decl_Cell ("db", "Cell", "@brief Gets the user property with the given key\n" "This method is a convenience method that gets the property with the given key. " "If no property with that key exists, it will return nil. Using that method is more " - "convenient than using the layout object and the properties ID to retrieve the property value. " + "convenient than using the layout object and the properties ID to retrieve the property value.\n" "\n" "This method has been introduced in version 0.23." ) + + gsi::method_ext ("properties", &get_cell_properties, + "@brief Gets the user properties as a hash\n" + "This method is a convenience method that gets all user properties as a single hash.\n" + "\n" + "This method has been introduced in version 0.29.5." + ) + gsi::method_ext ("add_meta_info", &cell_add_meta_info, gsi::arg ("info"), "@brief Adds meta information to the cell\n" "See \\LayoutMetaInfo for details about cells and meta information.\n" @@ -3539,6 +3565,26 @@ static tl::Variant get_property (const db::Instance *i, const tl::Variant &key) } } +static tl::Variant get_properties (const db::Instance *i) +{ + db::properties_id_type id = i->prop_id (); + if (id == 0) { + return tl::Variant::empty_array (); + } + + const db::Layout *layout = layout_ptr_const (i); + if (! layout) { + throw tl::Exception (tl::to_string (tr ("Instance does not reside inside a layout - cannot retrieve properties"))); + } + + tl::Variant res = tl::Variant::empty_array (); + const db::PropertiesRepository::properties_set &props = layout->properties_repository ().properties (id); + for (auto i = props.begin (); i != props.end (); ++i) { + res.insert (layout->properties_repository ().prop_name (i->first), i->second); + } + return res; +} + static bool inst_is_valid (const db::Instance *inst) { return inst->instances () && inst->instances ()->is_valid (*inst); @@ -4011,6 +4057,12 @@ Class decl_Instance ("db", "Instance", "\n" "This method has been introduced in version 0.22." ) + + gsi::method_ext ("properties", &get_properties, + "@brief Gets the user properties as a hash\n" + "This method is a convenience method that gets all user properties as a single hash.\n" + "\n" + "This method has been introduced in version 0.29.5." + ) + method_ext ("[]", &inst_index, gsi::arg ("key"), "@brief Gets the user property with the given key or, if available, the PCell parameter with the name given by the key\n" "Getting the PCell parameter has priority over the user property." diff --git a/src/db/db/gsiDeclDbLayout.cc b/src/db/db/gsiDeclDbLayout.cc index 9549fea59..751c4152e 100644 --- a/src/db/db/gsiDeclDbLayout.cc +++ b/src/db/db/gsiDeclDbLayout.cc @@ -344,7 +344,7 @@ static void set_layout_property (db::Layout *l, const tl::Variant &key, const tl l->prop_id (l->properties_repository ().properties_id (props)); } -static tl::Variant get_layout_property (db::Layout *l, const tl::Variant &key) +static tl::Variant get_layout_property (const db::Layout *l, const tl::Variant &key) { // TODO: check if is editable @@ -367,6 +367,21 @@ static tl::Variant get_layout_property (db::Layout *l, const tl::Variant &key) } } +static tl::Variant get_layout_properties (const db::Layout *layout) +{ + db::properties_id_type id = layout->prop_id (); + if (id == 0) { + return tl::Variant::empty_array (); + } + + tl::Variant res = tl::Variant::empty_array (); + const db::PropertiesRepository::properties_set &props = layout->properties_repository ().properties (id); + for (auto i = props.begin (); i != props.end (); ++i) { + res.insert (layout->properties_repository ().prop_name (i->first), i->second); + } + return res; +} + static db::cell_index_type cell_by_name (db::Layout *l, const char *name) { std::pair c = l->cell_by_name (name); @@ -1265,6 +1280,12 @@ Class decl_Layout ("db", "Layout", "\n" "This method has been introduced in version 0.24." ) + + gsi::method_ext ("properties", &get_layout_properties, + "@brief Gets the user properties as a hash\n" + "This method is a convenience method that gets all user properties as a single hash.\n" + "\n" + "This method has been introduced in version 0.29.5." + ) + gsi::method_ext ("properties_id", &properties_id, gsi::arg ("properties"), "@brief Gets the properties ID for a given properties set\n" "\n" diff --git a/src/db/db/gsiDeclDbShape.cc b/src/db/db/gsiDeclDbShape.cc index 708a52f5e..b757703c6 100644 --- a/src/db/db/gsiDeclDbShape.cc +++ b/src/db/db/gsiDeclDbShape.cc @@ -1004,6 +1004,26 @@ static tl::Variant get_property (const db::Shape *s, const tl::Variant &key) } } +static tl::Variant get_properties (const db::Shape *s) +{ + db::properties_id_type id = s->prop_id (); + if (id == 0) { + return tl::Variant::empty_array (); + } + + const db::Layout *layout = layout_ptr_const (s); + if (! layout) { + throw tl::Exception (tl::to_string (tr ("Shape does not reside inside a layout - cannot retrieve properties"))); + } + + tl::Variant res = tl::Variant::empty_array (); + const db::PropertiesRepository::properties_set &props = layout->properties_repository ().properties (id); + for (auto i = props.begin (); i != props.end (); ++i) { + res.insert (layout->properties_repository ().prop_name (i->first), i->second); + } + return res; +} + namespace { @@ -1354,6 +1374,12 @@ Class decl_Shape ("db", "Shape", "\n" "This method has been introduced in version 0.22." ) + + gsi::method_ext ("properties", &get_properties, + "@brief Gets the user properties\n" + "This method is a convenience method that gets the properties of the shape as a hash. " + "\n" + "This method has been introduced in version 0.29.5." + ) + gsi::iterator ("each_point", &db::Shape::begin_point, &db::Shape::end_point, "@brief Iterates over all points of the object\n" "\n" diff --git a/testdata/ruby/dbLayoutTests1.rb b/testdata/ruby/dbLayoutTests1.rb index d1479b2f3..6acbd2474 100644 --- a/testdata/ruby/dbLayoutTests1.rb +++ b/testdata/ruby/dbLayoutTests1.rb @@ -1334,6 +1334,7 @@ class DBLayoutTests1_TestClass < TestBase i0 = nil c0c.each_inst { |i| i.cell_index == l.cell("c1$1").cell_index && i0 = i } assert_equal(i0.property("p"), 18) + assert_equal(i0.properties, {"p" => 18}) assert_equal(l.cell("c1$1").begin_shapes_rec(0).shape.property("p"), 17) assert_equal(collect(c0c.begin_shapes_rec(0), l), "[c0$1](0,100;1000,1200)/[c2$1](100,0;1100,1100)/[c3$1](1200,0;2200,1100)/[c3$1](-1200,0;-100,1000)/[c1$1](0,100;1000,1200)") @@ -1379,6 +1380,7 @@ class DBLayoutTests1_TestClass < TestBase tt = RBA::Trans.new i0 = c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) + assert_equal(i0.properties, {}) i0.set_property("p", 18) c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) diff --git a/testdata/ruby/dbLayoutTests2.rb b/testdata/ruby/dbLayoutTests2.rb index bf5349645..fc1be5ac6 100644 --- a/testdata/ruby/dbLayoutTests2.rb +++ b/testdata/ruby/dbLayoutTests2.rb @@ -674,6 +674,7 @@ class DBLayoutTests2_TestClass < TestBase lindex = ly.insert_layer( linfo ) c1 = ly.cell( ci1 ) + assert_equal( c1.properties, {} ) c2 = ly.cell( ci2 ) tr = RBA::Trans::new inst = c2.insert( RBA::CellInstArray::new( c1.cell_index, tr ) ) @@ -701,6 +702,7 @@ class DBLayoutTests2_TestClass < TestBase c1.prop_id = pid assert_equal( c1.prop_id, pid ) assert_equal( c1.property( 17 ).inspect, "\"a\"" ) + assert_equal( c1.properties, { 17 => "a", "b" => [1, 5, 7] } ) c1.set_property( 5, 23 ) c1.delete_property( 17 ) assert_equal( c1.property( 17 ).inspect, "nil" ) @@ -1027,6 +1029,7 @@ class DBLayoutTests2_TestClass < TestBase def test_11 ly = RBA::Layout::new + assert_equal(ly.properties, {}) assert_equal(ly.prop_id, 0) ly.prop_id = 1 @@ -1037,6 +1040,7 @@ class DBLayoutTests2_TestClass < TestBase ly.set_property("x", 1) assert_equal(ly.prop_id, 1) assert_equal(ly.property("x"), 1) + assert_equal(ly.properties, {"x" => 1}) ly.set_property("x", 17) assert_equal(ly.prop_id, 2) assert_equal(ly.property("x"), 17) diff --git a/testdata/ruby/dbShapesTest.rb b/testdata/ruby/dbShapesTest.rb index 61b8c9243..b77f7f183 100644 --- a/testdata/ruby/dbShapesTest.rb +++ b/testdata/ruby/dbShapesTest.rb @@ -1656,6 +1656,28 @@ class DBShapes_TestClass < TestBase end + # Shape objects and properties + def test_13 + + ly = RBA::Layout::new + l1 = ly.layer(1, 0) + tc = ly.create_cell("TOP") + sh = tc.shapes(l1).insert(RBA::Box::new(0, 0, 100, 200)) + + assert_equal(sh.property("k").inspect, "nil") + assert_equal(sh.properties.inspect, "{}") + + sh.set_property("k", 17) + + assert_equal(sh.property("k").inspect, "17") + assert_equal(sh.property("u").inspect, "nil") + assert_equal(sh.properties.inspect, "{\"k\"=>17}") + + sh.set_property("u", "42") + assert_equal(sh.properties.inspect, "{\"k\"=>17, \"u\"=>\"42\"}") + + end + end load("test_epilogue.rb")