From bf965a78060b243c84d88a542b13949a9e9dc9c9 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 7 Sep 2024 20:29:43 +0200 Subject: [PATCH] Implemented solution for issue #1836 (Allow the usage of Cell.shapes(LayerInfo(...))) - For Cell#shapes, LayerInfo is an accepted argument now - If the layer does not exist, it is created (non-const version) or an error is raised (const version) - Cell#clear also accepts a LayerInfo object - Layout#clear and Layout#delete_layer also accept a LayerInfo parameter Rationale for supporting the clear and delete_layer methods: These cases do nothing if the layer does not exist, so there is a benefit of using them: it is not required to check first if the layer exists. --- src/db/db/gsiDeclDbCell.cc | 68 ++++++++++++++++++++++++++++++++- src/db/db/gsiDeclDbLayout.cc | 58 +++++++++++++++++++++++++++- testdata/ruby/dbCellTests.rb | 26 +++++++++++++ testdata/ruby/dbLayoutTests1.rb | 37 ++++++++++++++++++ 4 files changed, 185 insertions(+), 4 deletions(-) diff --git a/src/db/db/gsiDeclDbCell.cc b/src/db/db/gsiDeclDbCell.cc index c3c0535502..ef5f5b2db5 100644 --- a/src/db/db/gsiDeclDbCell.cc +++ b/src/db/db/gsiDeclDbCell.cc @@ -1802,6 +1802,39 @@ read_simple (db::Cell *cell, const std::string &path) return read_options (cell, path, db::LoadLayoutOptions ()); } +static db::Shapes &shapes_with_layer_info (db::Cell *cell, const db::LayerProperties &info) +{ + if (! cell->layout ()) { + throw tl::Exception (tl::to_string (tr ("Cell is not associated with a layout"))); + } + + unsigned int li = cell->layout ()->get_layer (info); + return cell->shapes (li); +} + +static const db::Shapes &shapes_with_layer_info_const (const db::Cell *cell, const db::LayerProperties &info) +{ + if (! cell->layout ()) { + throw tl::Exception (tl::to_string (tr ("Cell is not associated with a layout"))); + } + + int li = cell->layout ()->get_layer_maybe (info); + if (li < 0) { + throw tl::Exception (tl::sprintf (tl::to_string (tr ("%s is not a valid layer within the layout of the cell")), info.to_string ())); + } + + return cell->shapes ((unsigned int) li); +} + +static void clear_layer_with_info (db::Cell *cell, const db::LayerProperties &info) +{ + if (cell->layout ()) { + int layer = cell->layout ()->get_layer_maybe (info); + if (layer >= 0) { + cell->clear ((unsigned int) layer); + } + } +} static db::Point default_origin; @@ -1992,22 +2025,46 @@ Class decl_Cell ("db", "Cell", "This method gives access to the shapes list on a certain layer.\n" "If the layer does not exist yet, it is created.\n" "\n" - "@param index The layer index of the shapes list to retrieve\n" + "@param layer_index The layer index of the shapes list to retrieve\n" "\n" "@return A reference to the shapes list\n" ) + + gsi::method_ext ("shapes", shapes_with_layer_info, gsi::arg ("layer"), + "@brief Returns the shapes list of the given layer\n" + "\n" + "This version takes a \\LayerInfo object and will look up the layer index. If no layer exists " + "with these attributes, it will be created.\n" + "\n" + "@param layer The layer attributes\n" + "\n" + "@return A reference to the shapes list\n" + "\n" + "This variant has been introduced in version 0.29.7.\n" + ) + gsi::method_ext ("shapes", &shapes_of_cell_const, gsi::arg ("layer_index"), "@brief Returns the shapes list of the given layer (const version)\n" "\n" "This method gives access to the shapes list on a certain layer. This is the const version - only const (reading) methods " "can be called on the returned object.\n" "\n" - "@param index The layer index of the shapes list to retrieve\n" + "@param layer_index The layer index of the shapes list to retrieve\n" "\n" "@return A reference to the shapes list\n" "\n" "This variant has been introduced in version 0.26.4.\n" ) + + gsi::method_ext ("shapes", shapes_with_layer_info_const, gsi::arg ("layer"), + "@brief Returns the shapes list of the given layer (const version)\n" + "\n" + "This version takes a \\LayerInfo object and will look up the layer index. An error is raised if " + "no layer with these attributes exists.\n" + "\n" + "@param layer The layer attributes\n" + "\n" + "@return A reference to the shapes list\n" + "\n" + "This variant has been introduced in version 0.29.7.\n" + ) + gsi::method ("clear_shapes", &db::Cell::clear_shapes, "@brief Clears all shapes in the cell\n" ) + @@ -2082,6 +2139,13 @@ Class decl_Cell ("db", "Cell", gsi::method ("clear", &db::Cell::clear, gsi::arg ("layer_index"), "@brief Clears the shapes on the given layer\n" ) + + gsi::method_ext ("clear", &clear_layer_with_info, gsi::arg ("layer"), + "@brief Clears the shapes on the given layer\n" + "\n" + "This version takes a \\LayerInfo object for the layer. If no such layer exists, this method does nothing.\n" + "\n" + "This variant has been introduced in version 0.29.7.\n" + ) + gsi::method_ext ("clear", &clear_all, "@brief Clears the cell (deletes shapes and instances)\n" "This method has been introduced in version 0.23.\n" diff --git a/src/db/db/gsiDeclDbLayout.cc b/src/db/db/gsiDeclDbLayout.cc index 3edf80298f..e7b58f3aac 100644 --- a/src/db/db/gsiDeclDbLayout.cc +++ b/src/db/db/gsiDeclDbLayout.cc @@ -1103,6 +1103,30 @@ void break_polygons1 (db::Layout *layout, size_t max_vertex_count, double max_ar db::break_polygons (*layout, max_vertex_count, max_area_ratio); } +void delete_layer_from_info (db::Layout *layout, const db::LayerProperties &info) +{ + int li = layout->get_layer_maybe (info); + if (li >= 0) { + layout->delete_layer ((unsigned int) li); + } +} + +void clear_layer_from_info (db::Layout *layout, const db::LayerProperties &info) +{ + int li = layout->get_layer_maybe (info); + if (li >= 0) { + layout->clear_layer ((unsigned int) li); + } +} + +void clear_layer_from_info_with_flags (db::Layout *layout, const db::LayerProperties &info, unsigned int flags) +{ + int li = layout->get_layer_maybe (info); + if (li >= 0) { + layout->clear_layer ((unsigned int) li, flags); + } +} + Class decl_Layout ("db", "Layout", gsi::constructor ("new", &layout_ctor_with_manager, gsi::arg ("manager"), "@brief Creates a layout object attached to a manager\n" @@ -1963,8 +1987,18 @@ Class decl_Layout ("db", "Layout", "\n" "This method was introduced in version 0.19.\n" "\n" - "@param layer_index The index of the layer to delete.\n" + "@param layer_index The index of the layer to clear.\n" ) + + gsi::method_ext ("clear_layer", &clear_layer_from_info, gsi::arg ("layer"), + "@brief Clears a layer\n" + "\n" + "This variant takes a \\LayerInfo object to address the layer.\n" + "It does nothing if no layer with these attributes exists.\n" + "\n" + "This variant was introduced in version 0.26.7.\n" + "\n" + "@param layer The attributes of the layer to clear.\n" + ) + gsi::method ("clear_layer", static_cast (&db::Layout::clear_layer), gsi::arg ("layer_index"), gsi::arg ("flags"), "@brief Clears a layer (given shape types only)\n" "\n" @@ -1972,9 +2006,19 @@ Class decl_Layout ("db", "Layout", "\n" "This method was introduced in version 0.28.9.\n" "\n" - "@param layer_index The index of the layer to delete.\n" + "@param layer_index The index of the layer to clear.\n" "@param flags The type selector for the shapes to delete (see \\Shapes class, S... constants).\n" ) + + gsi::method_ext ("clear_layer", &clear_layer_from_info_with_flags, gsi::arg ("layer"), gsi::arg ("flags"), + "@brief Clears a layer (given shape types only)\n" + "\n" + "This variant takes a \\LayerInfo object to address the layer.\n" + "It does nothing if no layer with these attributes exists.\n" + "\n" + "This variant was introduced in version 0.26.7.\n" + "\n" + "@param layer The attributes of the layer to clear.\n" + ) + gsi::method ("delete_layer", &db::Layout::delete_layer, gsi::arg ("layer_index"), "@brief Deletes a layer\n" "\n" @@ -1983,6 +2027,16 @@ Class decl_Layout ("db", "Layout", "\n" "@param layer_index The index of the layer to delete.\n" ) + + gsi::method_ext ("delete_layer", &delete_layer_from_info, gsi::arg ("layer"), + "@brief Deletes a layer\n" + "\n" + "This variant takes a \\LayerInfo object to address the layer.\n" + "It does nothing if no layer with these attributes exists.\n" + "\n" + "This variant was introduced in version 0.26.7.\n" + "\n" + "@param layer The attributes of the layer to delete.\n" + ) + gsi::method_ext ("layer_indexes|#layer_indices", &layer_indexes, "@brief Gets a list of valid layer's indices\n" "This method returns an array with layer indices representing valid layers.\n" diff --git a/testdata/ruby/dbCellTests.rb b/testdata/ruby/dbCellTests.rb index 2111ed3888..b0fc91d0f1 100644 --- a/testdata/ruby/dbCellTests.rb +++ b/testdata/ruby/dbCellTests.rb @@ -98,6 +98,32 @@ def test_2 end + # methods with LayerInfo instead layer index + def test_3 + + ly = RBA::Layout::new + top = ly.create_cell("TOP") + + l1 = ly.layer(1, 0) + top.shapes(RBA::LayerInfo::new(1, 0)).insert(RBA::Box::new(0, 0, 100, 200)) + + assert_equal(top.shapes(l1).size, 1) + + # unknown layers are ignored in clear + top.clear(RBA::LayerInfo::new(2, 0)) + assert_equal(top.shapes(l1).size, 1) + + # clear with LayerInfo + top.clear(RBA::LayerInfo::new(1, 0)) + assert_equal(top.shapes(l1).size, 0) + + # layer is created if not there + assert_equal(ly.layer_infos, [ RBA::LayerInfo::new(1, 0) ]) + top.shapes(RBA::LayerInfo::new(2, 0)).insert(RBA::Box::new(0, 0, 100, 200)) + assert_equal(ly.layer_infos, [ RBA::LayerInfo::new(1, 0), RBA::LayerInfo::new(2, 0) ]) + + end + end load("test_epilogue.rb") diff --git a/testdata/ruby/dbLayoutTests1.rb b/testdata/ruby/dbLayoutTests1.rb index 6acbd24741..b0693188d2 100644 --- a/testdata/ruby/dbLayoutTests1.rb +++ b/testdata/ruby/dbLayoutTests1.rb @@ -2144,6 +2144,43 @@ def shapes2str(shapes) end + # Methods taking LayoutInfo instead of layer index + def test_26 + + ly = RBA::Layout::new + top = ly.create_cell("TOP") + l1 = ly.layer(1, 0) + + # ignored + ly.clear_layer(RBA::LayerInfo::new(2, 0)) + + top.shapes(l1).insert(RBA::Box::new(0, 0, 100, 200)) + assert_equal(top.shapes(l1).size, 1) + + ly.clear_layer(RBA::LayerInfo::new(1, 0)) + assert_equal(top.shapes(l1).size, 0) + + top.shapes(l1).insert(RBA::Box::new(0, 0, 100, 200)) + assert_equal(top.shapes(l1).size, 1) + + ly.clear_layer(RBA::LayerInfo::new(1, 0), RBA::Shapes::SPolygons) + assert_equal(top.shapes(l1).size, 1) + + ly.clear_layer(RBA::LayerInfo::new(1, 0), RBA::Shapes::SBoxes) + assert_equal(top.shapes(l1).size, 0) + + assert_equal(ly.layer_infos, [ RBA::LayerInfo::new(1, 0) ]) + + # ignored + ly.delete_layer(RBA::LayerInfo::new(2, 0)) + assert_equal(ly.layer_infos, [ RBA::LayerInfo::new(1, 0) ]) + + ly.delete_layer(RBA::LayerInfo::new(1, 0)) + assert_equal(ly.layer_infos, [ ]) + + end + + # Iterating while flatten def test_issue200