Merge pull request #1426 from KLayout/issue_1425

Fixed issue #1425: enhancement - allow searching for layers in layout…
This commit is contained in:
Matthias Köfferlein 2023-07-30 12:52:42 +02:00 committed by GitHub
commit dc5d2f3238
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 132 additions and 18 deletions

View File

@ -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<db::LayerProperties> decl_LayerInfo ("db", "LayerInfo",
gsi::constructor ("new", &ctor_layer_info_default,
@ -194,14 +207,31 @@ Class<db::LayerProperties> 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<unsigned int> layer_indices (const db::Layout *l)
static std::vector<unsigned int> layer_indexes (const db::Layout *l)
{
std::vector<unsigned int> layers;
for (unsigned int i = 0; i < l->layers (); ++i) {
@ -1555,7 +1591,19 @@ Class<db::Layout> 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<db::Layout> 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<db::Layout> 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"

View File

@ -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)