diff --git a/src/db/db/gsiDeclDbLayout.cc b/src/db/db/gsiDeclDbLayout.cc index 9da66889d..12fa57e95 100644 --- a/src/db/db/gsiDeclDbLayout.cc +++ b/src/db/db/gsiDeclDbLayout.cc @@ -128,6 +128,19 @@ size_t hash_value (const db::LayerProperties *l) return std::hfunc (*l); } +static bool log_equal_ext (const db::LayerProperties *lp1, const db::LayerProperties &lp2) +{ + if (lp1->log_equal (lp2)) { + return true; + } + // compare by name as fallback if one argument is named and the other is not + // (this gives a way to look up + if ((lp1->is_named () || lp2.is_named()) && ! lp1->name.empty () && ! lp2.name.empty ()) { + return lp1->name == lp2.name; + } + return false; +} + // since there already exists a "LayerProperties" object, we call this one "LayerInfo" Class decl_LayerInfo ("db", "LayerInfo", gsi::constructor ("new", &ctor_layer_info_default, @@ -194,14 +207,31 @@ Class decl_LayerInfo ("db", "LayerInfo", "\n" "This method was added in version 0.18.\n" ) + - gsi::method ("is_equivalent?", &db::LayerProperties::log_equal, gsi::arg ("b"), + gsi::method_ext ("is_equivalent?", &log_equal_ext, gsi::arg ("b"), "@brief Equivalence of two layer info objects\n" "@return True, if both are equivalent\n" "\n" - "First, layer and datatype are compared. The name is of second order and used only if no layer or datatype is given.\n" - "This is basically a weak comparison that reflects the search preferences.\n" + "First, layer and datatype are compared. The name is of second order and used only if no layer or datatype is given " + "for one of the operands.\n" + "This is basically a weak comparison that reflects the search preferences. It is the basis for \\Layout#find_layer.\n" + "Here are some examples:\n" "\n" - "This method was added in version 0.18.\n" + "@code\n" + "# no match as layer/datatypes or names differ:\n" + "RBA::LayerInfo::new(1, 17).is_equivalent?(RBA::LayerInfo::new(1, 18)) -> false\n" + "RBA::LayerInfo::new('metal1').is_equivalent?(RBA::LayerInfo::new('m1')) -> false\n" + "# exact match for numbered or named layers:\n" + "RBA::LayerInfo::new(1, 17).is_equivalent?(RBA::LayerInfo::new(1, 17)) -> true\n" + "RBA::LayerInfo::new('metal1').is_equivalent?(RBA::LayerInfo::new('metal1')) -> true\n" + "# match as names are second priority over layer/datatypes:\n" + "RBA::LayerInfo::new(1, 17, 'metal1').is_equivalent?(RBA::LayerInfo::new(1, 17, 'm1')) -> true\n" + "# match as name matching is fallback:\n" + "RBA::LayerInfo::new(1, 17, 'metal1').is_equivalent?(RBA::LayerInfo::new('metal1')) -> true\n" + "# no match as neither names or layer/datatypes match:\n" + "RBA::LayerInfo::new(1, 17, 'metal1').is_equivalent?(RBA::LayerInfo::new('m1')) -> false\n" + "@/code\n" + "\n" + "This method was added in version 0.18 and modified to compare non-named vs. named layers in version 0.28.11.\n" ) + gsi::method_ext ("hash", &hash_value, "@brief Computes a hash value\n" @@ -504,9 +534,15 @@ static tl::Variant find_layer (db::Layout *l, const db::LayerProperties &lp) // for a null layer info always return nil return tl::Variant (); } else { - // if we have a layer with the requested properties already, return this. + // if we have a layer with the requested properties already, return this one. + // first pass: exact match + int index = l->get_layer_maybe (lp); + if (index >= 0) { + return tl::Variant ((unsigned int) index); + } + // second pass: relaxed match for (db::Layout::layer_iterator li = l->begin_layers (); li != l->end_layers (); ++li) { - if ((*li).second->log_equal (lp)) { + if (log_equal_ext ((*li).second, lp)) { return tl::Variant ((*li).first); } } @@ -530,7 +566,7 @@ static tl::Variant find_layer3 (db::Layout *l, int ln, int dn, const std::string return find_layer (l, db::LayerProperties (ln, dn, name)); } -static std::vector layer_indices (const db::Layout *l) +static std::vector layer_indexes (const db::Layout *l) { std::vector layers; for (unsigned int i = 0; i < l->layers (); ++i) { @@ -1555,7 +1591,19 @@ Class decl_Layout ("db", "Layout", "If a layer with the given properties already exists, this method will return the index of that layer." "If no such layer exists, it will return nil.\n" "\n" - "This method has been introduced in version 0.23.\n" + "In contrast to \\layer, this method will also find layers matching by name only. " + "For example:\n" + "\n" + "@code\n" + "# finds layer '17/0' and 'name (17/0)':\n" + "index = layout.find_layer(RBA::LayerInfo::new(17, 0))\n" + "# finds layer 'name' (first priority), but also 'name (17/0)' (second priority):\n" + "index = layout.find_layer(RBA::LayerInfo::new('name'))\n" + "# note that this will not match layer 'name (17/0)' and create a new name-only layer:\n" + "index = layout.layer(RBA::LayerInfo::new('name'))\n" + "@/code\n" + "\n" + "This method has been introduced in version 0.23 and has been extended to name queries in version 0.28.11.\n" ) + gsi::method_ext ("find_layer", &find_layer1, gsi::arg ("name"), "@brief Finds a layer with the given name\n" @@ -1563,7 +1611,17 @@ Class decl_Layout ("db", "Layout", "If a layer with the given name already exists, this method will return the index of that layer." "If no such layer exists, it will return nil.\n" "\n" - "This method has been introduced in version 0.23.\n" + "In contrast to \\layer, this method will also find numbered layers if the name matches. " + "For example:\n" + "\n" + "@code\n" + "# finds layer 'name' (first priority), but also 'name (17/0)' (second priority):\n" + "index = layout.find_layer('name')\n" + "# note that this will not match layer 'name (17/0)' and create a new name-only layer:\n" + "index = layout.layer('name')\n" + "@/code\n" + "\n" + "This method has been introduced in version 0.23 and has been extended to name queries in version 0.28.11.\n" ) + gsi::method_ext ("find_layer", &find_layer2, gsi::arg ("layer"), gsi::arg ("datatype"), "@brief Finds a layer with the given layer and datatype number\n" @@ -1755,7 +1813,7 @@ Class decl_Layout ("db", "Layout", "\n" "@param layer_index The index of the layer to delete.\n" ) + - gsi::method_ext ("layer_indexes|#layer_indices", &layer_indices, + 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" "\n" diff --git a/testdata/ruby/dbLayoutTests1.rb b/testdata/ruby/dbLayoutTests1.rb index fa7c0ebe6..284e1fea4 100644 --- a/testdata/ruby/dbLayoutTests1.rb +++ b/testdata/ruby/dbLayoutTests1.rb @@ -64,16 +64,38 @@ class DBLayoutTests1_TestClass < TestBase assert_equal(l3.anonymous?, false) assert_equal(l3.is_named?, true) assert_equal(l3.is_equivalent?(l2), false) - l3.layer = 1 - l3.datatype = 100 - assert_equal(l3.is_named?, false) - assert_equal(l3.is_equivalent?(l2), true) + assert_equal(l2.is_equivalent?(l3), false) + l4 = RBA::LayerInfo::new(1, 100, "aber") + assert_equal(l4.to_s, "aber (1/100)") + assert_equal(l4.anonymous?, false) + assert_equal(l4.is_named?, false) + assert_equal(l4.is_equivalent?(l2), true) + assert_equal(l2.is_equivalent?(l4), true) + assert_equal(l4.is_equivalent?(l3), true) + assert_equal(l3.is_equivalent?(l4), true) + assert_equal(l4.is_equivalent?(RBA::LayerInfo::new(1, 100, "xyz")), true) + assert_equal(l4.is_equivalent?(RBA::LayerInfo::new(1, 101, "aber")), false) + + l1.assign(l4) - l1.assign(l3) assert_equal(l1.to_s, "aber (1/100)") assert_equal(l1.is_named?, false) - assert_equal(l1.is_equivalent?(l3), true) - assert_equal(l1 == l3, true) + assert_equal(l1.is_equivalent?(l4), true) + assert_equal(l1 == l4, true) + + l1.layer = -1 + l1.datatype = -1 + assert_equal(l1.is_named?, true) + assert_equal(l1.to_s, "aber") + + l1.name = "xyz" + assert_equal(l1.is_named?, true) + assert_equal(l1.to_s, "xyz") + + l1.layer = 100 + l1.datatype = 0 + assert_equal(l1.is_named?, false) + assert_equal(l1.to_s, "xyz (100/0)") end @@ -164,16 +186,50 @@ class DBLayoutTests1_TestClass < TestBase assert_equal(a, nil) a = ly.find_layer(RBA::LayerInfo.new(2, 0)) assert_equal(a, li) + a = ly.find_layer(3, 0, "hallo") + assert_equal(a, nil) li2 = ly.layer("hallo") a = ly.find_layer("hillo") assert_equal(a, nil) a = ly.find_layer("hallo") assert_equal(a, li2) a = ly.find_layer(3, 0, "hallo") - assert_equal(a, nil) + assert_equal(a, li2) a = ly.find_layer(2, 0, "hallo") assert_equal(a, li) + ly = RBA::Layout.new + li = ly.layer(2, 0, "hallo") + a = ly.find_layer(3, 0) + assert_equal(a, nil) + a = ly.find_layer(2, 0) + assert_equal(a, li) + a = ly.find_layer("hallo") + assert_equal(a, li) + a = ly.find_layer(2, 0, "hillo") + assert_equal(a, li) + a = ly.find_layer(1, 0, "hallo") + assert_equal(a, nil) + + ly = RBA::Layout.new + li0 = ly.layer("hello") + li = ly.layer("hallo") + a = ly.find_layer(3, 0) + assert_equal(a, nil) + a = ly.find_layer(2, 0) + assert_equal(a, nil) + a = ly.find_layer("hallo") + assert_equal(a, li) + a = ly.find_layer(2, 0, "hillo") + assert_equal(a, nil) + a = ly.find_layer(1, 0, "hallo") + assert_equal(a, li) + li2 = ly.layer(1, 0, "hello") + a = ly.find_layer(1, 0, "hello") + assert_equal(a, li2) + a = ly.find_layer("hello") + assert_equal(a, li0) + end def collect(s, l)