diff --git a/src/db/db/dbLayerProperties.cc b/src/db/db/dbLayerProperties.cc index 4252ed361..bced3f25e 100644 --- a/src/db/db/dbLayerProperties.cc +++ b/src/db/db/dbLayerProperties.cc @@ -22,6 +22,7 @@ #include "dbLayerProperties.h" +#include "dbStreamLayers.h" namespace db { @@ -30,7 +31,7 @@ namespace db // Implementation of the LayerProperties class LayerProperties::LayerProperties () - : name (), layer (-1), datatype (-1) + : name (), layer (db::any_ld ()), datatype (db::any_ld ()) { } LayerProperties::LayerProperties (int l, int d) @@ -38,7 +39,7 @@ LayerProperties::LayerProperties (int l, int d) { } LayerProperties::LayerProperties (const std::string &n) - : name (n), layer (-1), datatype (-1) + : name (n), layer (db::any_ld ()), datatype (db::any_ld ()) { } LayerProperties::LayerProperties (int l, int d, const std::string &n) @@ -48,7 +49,13 @@ LayerProperties::LayerProperties (int l, int d, const std::string &n) bool LayerProperties::is_named () const { - return (layer < 0 || datatype < 0) && ! name.empty (); + return db::is_any_ld (layer) && db::is_any_ld (datatype) && ! name.empty (); +} + +bool +LayerProperties::is_null () const +{ + return db::is_any_ld (layer) && db::is_any_ld (datatype) && name.empty (); } bool @@ -122,34 +129,79 @@ LayerProperties::operator< (const LayerProperties &b) const return name < b.name; } +static std::string format_ld (db::ld_type ld) +{ + if (db::is_static_ld (ld)) { + return tl::to_string (ld); + } else if (db::is_any_ld (ld)) { + return "*"; + } else if (db::is_relative_ld (ld)) { + db::ld_type offset = db::ld_offset (ld); + if (offset < 0) { + return "*-" + tl::to_string (-offset); + } else { + return "*+" + tl::to_string (offset); + } + } else { + return tl::to_string (ld); + } +} + std::string -LayerProperties::to_string () const +LayerProperties::to_string (bool as_target) const { std::string r; if (! name.empty ()) { if (is_named ()) { r = tl::to_word_or_quoted_string (name); } else { - r = tl::to_word_or_quoted_string (name) + tl::sprintf (" (%d/%d)", layer, datatype); + r = tl::to_word_or_quoted_string (name) + " (" + format_ld (layer) + "/" + format_ld (datatype) + ")"; } - } else if (! is_null ()) { - r = tl::sprintf ("%d/%d", layer, datatype); + } else if (! is_null () || as_target) { + r = format_ld (layer) + "/" + format_ld (datatype); } return r; } -void -LayerProperties::read (tl::Extractor &ex) +static bool read_ld (tl::Extractor &ex, ld_type &l, bool with_relative) { - layer = -1; - datatype = -1; + if (ex.test ("*")) { + + int offset = 0; + + tl::Extractor eex = ex; + if (with_relative && eex.test ("+") && eex.try_read (offset)) { + l = db::relative_ld (offset); + ex = eex; + } else { + eex = ex; + if (with_relative && eex.test ("-") && eex.try_read (offset)) { + l = db::relative_ld (-offset); + ex = eex; + } else { + l = db::any_ld (); + } + } + + return true; + + } else { + return ex.try_read (l); + } +} + +void +LayerProperties::read (tl::Extractor &ex, bool as_target) +{ + layer = db::any_ld (); + datatype = db::any_ld (); name.clear (); int l = 0, d = 0; - if (ex.try_read (l)) { + if (read_ld (ex, l, as_target)) { if (ex.test ("/")) { - ex.read (d); + read_ld (ex, d, as_target); } layer = l; @@ -159,10 +211,11 @@ LayerProperties::read (tl::Extractor &ex) if (ex.test ("(")) { - ex.read (l); + read_ld (ex, l, as_target); if (ex.test ("/")) { - ex.read (d); + read_ld (ex, d, as_target); } + ex.expect (")"); layer = l; diff --git a/src/db/db/dbLayerProperties.h b/src/db/db/dbLayerProperties.h index 56022a985..b08e33712 100644 --- a/src/db/db/dbLayerProperties.h +++ b/src/db/db/dbLayerProperties.h @@ -39,6 +39,10 @@ namespace db * * The layer properties are basically to be used for storing of layer name and * layer/datatype information. + * + * A special use case is for the target of a layer mapping specification. + * In this case, the layer properties can make use of the relative + * layer/datatype specifications. */ struct DB_PUBLIC LayerProperties { @@ -68,10 +72,7 @@ struct DB_PUBLIC LayerProperties * A null specification is one created by the default constructor. It does not have * a layer, datatype or name assigned. */ - bool is_null () const - { - return layer < 0 && datatype < 0 && name.empty (); - } + bool is_null () const; /** * @brief Return true, if the layer is specified by name only @@ -81,12 +82,17 @@ struct DB_PUBLIC LayerProperties /** * @brief Convert to a string */ - std::string to_string () const; + std::string to_string (bool as_target = false) const; /** * @brief Extract from a tl::Extractor + * + * With "with_relative" true, the extractor allows giving + * relative layer/datatype specifications in the format "*+1" or "*-100". + * "*" for layer or datatype is for "don't care" (on input) or "leave as is" + * (for output). */ - void read (tl::Extractor &ex); + void read (tl::Extractor &ex, bool as_target = false); /** * @brief "Logical" equality diff --git a/src/db/db/dbNamedLayerReader.cc b/src/db/db/dbNamedLayerReader.cc index 53cdef1ff..497fad153 100644 --- a/src/db/db/dbNamedLayerReader.cc +++ b/src/db/db/dbNamedLayerReader.cc @@ -128,7 +128,7 @@ NamedLayerReader::open_layer (db::Layout &layout, const std::string &n) std::pair ll (false, 0); - ll = m_layer_map.logical (n); + ll = m_layer_map.logical (n, layout); if (! ll.first && !m_keep_layer_names) { if (extract_plain_layer (n.c_str (), l)) { @@ -136,7 +136,7 @@ NamedLayerReader::open_layer (db::Layout &layout, const std::string &n) db::LayerProperties lp; lp.layer = l; lp.datatype = 0; - ll = m_layer_map.logical (lp); + ll = m_layer_map.logical (lp, layout); } else if (extract_ld (n.c_str (), l, d, on)) { @@ -144,7 +144,7 @@ NamedLayerReader::open_layer (db::Layout &layout, const std::string &n) lp.layer = l; lp.datatype = d; lp.name = on; - ll = m_layer_map.logical (lp); + ll = m_layer_map.logical (lp, layout); } diff --git a/src/db/db/dbStreamLayers.cc b/src/db/db/dbStreamLayers.cc index f664265d0..37c4dfcce 100644 --- a/src/db/db/dbStreamLayers.cc +++ b/src/db/db/dbStreamLayers.cc @@ -71,13 +71,31 @@ LayerMap::LayerMap () // .. nothing yet .. } -std::pair +std::pair LayerMap::logical (const LDPair &p) const +{ + return logical_internal (p, false); +} + +std::pair +LayerMap::logical (const std::string &n) const +{ + return logical_internal (n, false); +} + +std::pair +LayerMap::logical (const db::LayerProperties &p) const +{ + return logical_internal (p, false); +} + +std::pair +LayerMap::logical_internal (const LDPair &p, bool allow_placeholder) const { const datatype_map *dm = m_ld_map.mapped (p.layer); if (dm) { const unsigned int *l = dm->mapped (p.datatype); - if (l) { + if (l && (allow_placeholder || ! is_placeholder (*l))) { return std::make_pair (true, *l); } } @@ -85,10 +103,10 @@ LayerMap::logical (const LDPair &p) const } std::pair -LayerMap::logical (const std::string &n) const +LayerMap::logical_internal (const std::string &n, bool allow_placeholder) const { std::map::const_iterator m = m_name_map.find (n); - if (m != m_name_map.end ()) { + if (m != m_name_map.end () && (allow_placeholder || ! is_placeholder (m->second))) { return std::make_pair (true, m->second); } else { return std::make_pair (false, 0); @@ -96,16 +114,16 @@ LayerMap::logical (const std::string &n) const } std::pair -LayerMap::logical (const db::LayerProperties &p) const +LayerMap::logical_internal (const db::LayerProperties &p, bool allow_placeholder) const { if (p.layer >= 0 && p.datatype >= 0) { - std::pair m = logical (db::LDPair (p.layer, p.datatype)); + std::pair m = logical_internal (db::LDPair (p.layer, p.datatype), allow_placeholder); if (m.first) { return m; } } if (! p.name.empty ()) { - std::pair m = logical (p.name); + std::pair m = logical_internal (p.name, allow_placeholder); if (m.first) { return m; } @@ -113,6 +131,60 @@ LayerMap::logical (const db::LayerProperties &p) const return std::make_pair (false, 0); } +bool +LayerMap::is_placeholder (unsigned int l) const +{ + return (m_placeholders.size () > std::numeric_limits::max () - l); +} + +std::pair +LayerMap::logical (const db::LayerProperties &p, db::Layout &layout) const +{ + std::pair l = logical_internal (p, true); + if (l.first && is_placeholder (l.second)) { + return const_cast (this)->substitute_placeholder (p, l.second, layout); + } else { + return l; + } +} + +std::pair +LayerMap::logical (const db::LDPair &p, db::Layout &layout) const +{ + std::pair l = logical_internal (p, true); + if (l.first && is_placeholder (l.second)) { + return const_cast (this)->substitute_placeholder (db::LayerProperties (p.layer, p.datatype), l.second, layout); + } else { + return l; + } +} + +std::pair +LayerMap::substitute_placeholder (const db::LayerProperties &p, unsigned int ph, db::Layout &layout) +{ + const db::LayerProperties &lp_ph = m_placeholders [std::numeric_limits::max () - ph]; + db::LayerProperties lp_new = p; + lp_new.layer = db::ld_combine (p.layer, lp_ph.layer); + lp_new.datatype = db::ld_combine (p.datatype, lp_ph.datatype); + + unsigned int l_new = layout.insert_layer (lp_new); + map (p, l_new, lp_new); + return std::make_pair (true, l_new); +} + +static std::string format_interval (ld_type l1, ld_type l2) +{ + if (l1 == 0 && l2 == std::numeric_limits::max ()) { + return "*"; + } else if (l2 == std::numeric_limits::max ()) { + return tl::to_string (l1) + "-*"; + } else if (l1 + 1 < l2) { + return tl::to_string (l1) + "-" + tl::to_string (l2 - 1); + } else { + return tl::to_string (l1); + } +} + std::string LayerMap::mapping_str (unsigned int ll) const { @@ -135,21 +207,13 @@ LayerMap::mapping_str (unsigned int ll) const } f1 = false; - s += tl::to_string (l->first.first); - if (l->first.first < l->first.second - 1) { - s += "-"; - s += tl::to_string (l->first.second - 1); - } + s += format_interval (l->first.first, l->first.second); s += "/"; } f2 = false; - s += tl::to_string (d->first.first); - if (d->first.first < d->first.second - 1) { - s += "-"; - s += tl::to_string (d->first.second - 1); - } + s += format_interval (d->first.first, d->first.second); } @@ -173,7 +237,7 @@ LayerMap::mapping_str (unsigned int ll) const std::map::const_iterator t = m_target_layers.find (ll); if (t != m_target_layers.end ()) { s += " : "; - s += t->second.to_string (); + s += t->second.to_string (true); } return s; @@ -182,6 +246,9 @@ LayerMap::mapping_str (unsigned int ll) const void LayerMap::prepare (db::Layout &layout) { + m_placeholders.clear (); + unsigned int ph = std::numeric_limits::max (); + std::map real_layers; std::set mapped_layers; @@ -190,16 +257,33 @@ LayerMap::prepare (db::Layout &layout) std::vector old_layers = get_layers (); for (std::vector::const_iterator l = old_layers.begin (); l != old_layers.end (); ++l) { + if (layout.is_valid_layer (*l)) { + real_layers.insert (std::make_pair (*l, *l)); mapped_layers.insert (*l); + } else { - std::pair lm = layer_mapping.map_layer (mapping (*l)); - if (lm.first) { - real_layers.insert (std::make_pair (*l, lm.second)); - mapped_layers.insert (lm.second); + + db::LayerProperties lp = mapping (*l); + if (lp.is_named () || (db::is_static_ld (lp.layer) && db::is_static_ld (lp.datatype))) { + + std::pair lm = layer_mapping.map_layer (lp); + if (lm.first) { + real_layers.insert (std::make_pair (*l, lm.second)); + mapped_layers.insert (lm.second); + } + + } else { + + // install a placeholder index + m_placeholders.push_back (lp); + real_layers.insert (std::make_pair (*l, ph--)); + } + } + } // Now remap the indexes @@ -253,10 +337,29 @@ LayerMap::mapping (unsigned int ll) const std::map::const_iterator t = m_target_layers.find (ll); if (t != m_target_layers.end ()) { - p = t->second; - } - if (p.layer < 0 || p.datatype < 0) { + // a mapping is given. Use it. + p = t->second; + + // special case: if it is a name mapping, add the layer mapping (for backward compatibility) + if (p.is_named ()) { + + // no mapping is given. Use the lowest layer and datatype + for (ld_map::const_iterator l = m_ld_map.begin (); l != m_ld_map.end (); ++l) { + for (datatype_map::const_iterator d = l->second.begin (); d != l->second.end (); ++d) { + if (d->second == ll) { + p.layer = l->first.first; + p.datatype = d->first.first; + break; + } + } + } + + } + + } else { + + // no mapping is given. Use the lowest layer and datatype for (ld_map::const_iterator l = m_ld_map.begin (); l != m_ld_map.end (); ++l) { for (datatype_map::const_iterator d = l->second.begin (); d != l->second.end (); ++d) { if (d->second == ll) { @@ -266,6 +369,7 @@ LayerMap::mapping (unsigned int ll) const } } } + } if (p.name.empty ()) { @@ -284,19 +388,19 @@ LayerMap::mapping (unsigned int ll) const void LayerMap::map (const LDPair &p, unsigned int l) { - insert (p, p, l, LayerProperties ()); + insert (p, p, l, (const LayerProperties *) 0); } void LayerMap::map (const std::string &name, unsigned int l) { - insert (name, l, LayerProperties ()); + insert (name, l, (const LayerProperties *) 0); } void LayerMap::map (const LayerProperties &f, unsigned int l) { - if (f.layer >= 0 && f.datatype >= 0) { + if (f.name.empty () || is_static_ld (f.layer) || is_static_ld (f.datatype)) { map (db::LDPair (f.layer, f.datatype), l); } if (! f.name.empty ()) { @@ -307,19 +411,19 @@ LayerMap::map (const LayerProperties &f, unsigned int l) void LayerMap::map (const LDPair &p, unsigned int l, const LayerProperties &t) { - insert (p, p, l, t); + insert (p, p, l, &t); } void LayerMap::map (const std::string &name, unsigned int l, const LayerProperties &t) { - insert (name, l, t); + insert (name, l, &t); } void LayerMap::map (const LayerProperties &f, unsigned int l, const LayerProperties &t) { - if (f.layer >= 0 && f.datatype >= 0) { + if (f.name.empty () || is_static_ld (f.layer) || is_static_ld (f.datatype)) { map (db::LDPair (f.layer, f.datatype), l, t); } if (! f.name.empty ()) { @@ -330,13 +434,13 @@ LayerMap::map (const LayerProperties &f, unsigned int l, const LayerProperties & void LayerMap::map (const LDPair &p1, const LDPair &p2, unsigned int l) { - insert (p1, p2, l, LayerProperties ()); + insert (p1, p2, l, (const LayerProperties *) 0); } void LayerMap::map (const LDPair &p1, const LDPair &p2, unsigned int l, const LayerProperties &lp) { - insert (p1, p2, l, lp); + insert (p1, p2, l, &lp); } /// Utility function for the expression parser: @@ -346,11 +450,22 @@ parse_interval (tl::Extractor &ex, ld_interval &p) { ld_type n1 = 0, n2 = 0; - ex.try_read (n1); - if (ex.test ("-")) { - ex.try_read (n2); + if (ex.test ("*")) { + n1 = 0; + // NOTE: as the upper limit is stored as n2 + 1, this will map to max(): + n2 = std::numeric_limits::max () - 1; } else { - n2 = n1; + ex.try_read (n1); + if (ex.test ("-")) { + if (ex.test ("*")) { + // NOTE: as the upper limit is stored as n2 + 1, this will map to max(): + n2 = std::numeric_limits::max () - 1; + } else { + ex.try_read (n2); + } + } else { + n2 = n1; + } } p.first = n1; @@ -420,7 +535,7 @@ LayerMap::map_expr (tl::Extractor &ex, unsigned int l) if (ex.test (":")) { LayerProperties lp; - lp.read (ex); + lp.read (ex, true); m_target_layers[l] = lp; } @@ -434,10 +549,10 @@ LayerMap::map_expr (tl::Extractor &ex, unsigned int l) } void -LayerMap::insert (const std::string &name, unsigned int l, const LayerProperties &target) +LayerMap::insert (const std::string &name, unsigned int l, const LayerProperties *target) { - if (! (target == LayerProperties ())) { - m_target_layers[l] = target; + if (target) { + m_target_layers[l] = *target; } m_name_map.insert (std::make_pair (name, l)); @@ -448,21 +563,29 @@ LayerMap::insert (const std::string &name, unsigned int l, const LayerProperties } void -LayerMap::insert (const LDPair &p1, const LDPair &p2, unsigned int l, const LayerProperties &target) +LayerMap::insert (const LDPair &p1, const LDPair &p2, unsigned int l, const LayerProperties *target) { - if (! (target == LayerProperties ())) { - m_target_layers[l] = target; + if (target) { + m_target_layers[l] = *target; } // create a single-interval list for the datatype range LayerMap::datatype_map dt; LmapJoinOp1 op1; - dt.add (p1.datatype, p2.datatype + 1, l, op1); + if (db::is_static_ld (p1.datatype) && db::is_static_ld (p2.datatype)) { + dt.add (p1.datatype, p2.datatype + 1, l, op1); + } else { + dt.add (0, std::numeric_limits::max (), l, op1); + } // add this to the layers using the special join operator that // combines the datatype intervals LmapJoinOp2 op2; - m_ld_map.add (p1.layer, p2.layer + 1, dt, op2); + if (db::is_static_ld (p1.layer) && db::is_static_ld (p2.layer)) { + m_ld_map.add (p1.layer, p2.layer + 1, dt, op2); + } else { + m_ld_map.add (0, std::numeric_limits::max (), dt, op2); + } if (l >= m_next_index) { m_next_index = l + 1; diff --git a/src/db/db/dbStreamLayers.h b/src/db/db/dbStreamLayers.h index c9e048464..efc80b45b 100644 --- a/src/db/db/dbStreamLayers.h +++ b/src/db/db/dbStreamLayers.h @@ -34,6 +34,7 @@ #include "gsiObject.h" #include +#include namespace db { @@ -57,6 +58,58 @@ public: */ typedef int ld_type; +/** + * @brief Some definitions to declare wildcard and relative datatypes or layers + */ +inline ld_type any_ld () +{ + return -1; +} + +inline bool is_any_ld (ld_type ld) +{ + return ld == -1; +} + +inline bool is_static_ld (ld_type ld) +{ + return ld >= 0; +} + +inline ld_type relative_ld (ld_type ld) +{ + if (ld < 0) { + return std::numeric_limits::min() - ld; + } else { + // NOTE: this way "any_ld" is equivalent to "relative_ld(0)" + return -ld - 1; + } +} + +inline ld_type is_relative_ld (ld_type ld) +{ + return ld < 0; +} + +inline ld_type ld_offset (ld_type ld) +{ + if (ld < 0) { + ld_type neg = ld - std::numeric_limits::min(); + ld_type pos = -(ld + 1); + return neg < pos ? -neg : pos; + } else { + return ld; + } +} + +/** + * @brief With a relative b, b is added to a. Otherwise b replaces a. + */ +inline ld_type ld_combine (ld_type a, ld_type b) +{ + return is_relative_ld (b) ? a + ld_offset (b) : b; +} + /** * @brief A struct for a layer/datatype pair) */ @@ -162,7 +215,28 @@ public: */ std::pair logical (const db::LayerProperties &p) const; - /** + /** + * @brief Query or install a layer mapping from a name or LDPair + * + * @return A pair telling if the layer is mapped (first=true) and + * the logical layer mapped (second) if this is the case. + * + * @param p The layer that is looked for + * + * This version is used for wildcard and relative mapping. In this case, + * the logical layers are placeholder values which will be replaced by + * true layers during this method if a new layer is requested. + */ + std::pair logical (const db::LayerProperties &p, db::Layout &layout) const; + + /** + * @brief Query or install a layer mapping from a LDPair + * + * See the version for LayerProperties about details. + */ + std::pair logical (const db::LDPair &p, db::Layout &layout) const; + + /** * @brief String description for the mapping of a logical layer * * @return A string describing the mapping (an empty string if @@ -263,12 +337,23 @@ public: * sequence of numbers, separated by comma values or a range * separated by a hyphen. Examples are: "1/2", "1-5/0", "1,2,5/0", * "1/5;5/6". + * + * layer/datatype wildcards can be specified with "*". When "*" is used + * for the upper limit, it is equivalent to "all layer above". When used + * alone, it is equivalent to "all layers". Examples: "1 / *", "* / 10-*". + * * Named layers are specified simply by specifying the name, if * necessary in single or double quotes (if the name begins with a digit or * contains non-word characters). layer/datatype and name descriptions can * be mixed, i.e. "AA;1/5" (meaning: name "AA" or layer 1/datatype 5). + * * A target layer can be specified with the ":" notation, where * target is a valid string for a LayerProperties() object. + * + * A target can include relative layer/datatype specifications and wildcards. + * For example, "1-10/0: *+1/0" will add 1 to the original layer number. + * "1-10/0-50: * / *" will use the original layers. + * * This method will throw a LayerSpecFormatException if * something is wrong with the format string */ @@ -282,8 +367,10 @@ public: /** * @brief Prepares a layer mapping object for reading * - * This replaces all layer indexes by ones either in the layout or it will create new layers - * in the layout + * This replaces all layer indexes by ones from the layout or it will create new layers + * if required. Note that for relative and wildcard targets (except '* / *'), the layer + * indexes will not be the true indexes but placeholders. They will be replaced later + * when calling logical with a layout argument. */ void prepare (db::Layout &layout); @@ -362,10 +449,18 @@ private: ld_map m_ld_map; std::map m_name_map; std::map m_target_layers; + std::vector m_placeholders; unsigned int m_next_index; - void insert (const LDPair &p1, const LDPair &p2, unsigned int l, const LayerProperties &t); - void insert (const std::string &name, unsigned int l, const LayerProperties &t); + void insert (const LDPair &p1, const LDPair &p2, unsigned int l, const LayerProperties *t); + void insert (const std::string &name, unsigned int l, const LayerProperties *t); + + std::pair logical_internal (const LDPair &p, bool allow_placeholder) const; + std::pair logical_internal (const std::string &name, bool allow_placeholder) const; + std::pair logical_internal (const db::LayerProperties &p, bool allow_placeholder) const; + + std::pair substitute_placeholder (const db::LayerProperties &p, unsigned int ph, db::Layout &layout); + bool is_placeholder (unsigned int l) const; }; } diff --git a/src/db/db/gsiDeclDbLayout.cc b/src/db/db/gsiDeclDbLayout.cc index 732ad8be0..685dfbd22 100644 --- a/src/db/db/gsiDeclDbLayout.cc +++ b/src/db/db/gsiDeclDbLayout.cc @@ -106,11 +106,11 @@ db::LayerProperties *ctor_layer_info_name (const std::string &name) } static -db::LayerProperties li_from_string (const char *s) +db::LayerProperties li_from_string (const char *s, bool as_target) { tl::Extractor ex (s); db::LayerProperties lp; - lp.read (ex); + lp.read (ex, as_target); return lp; } @@ -152,21 +152,27 @@ Class decl_LayerInfo ("db", "LayerInfo", "\n" "This method was added in version 0.18.\n" ) + - gsi::method ("from_string", &li_from_string, gsi::arg ("s"), + gsi::method ("from_string", &li_from_string, gsi::arg ("s"), gsi::arg ("as_target", false), "@brief Create a layer info object from a string\n" "@param The string\n" "@return The LayerInfo object\n" "\n" + "If 'as_target' is true, relative specifications such as '*+1' for layer or datatype are permitted.\n" + "\n" "This method will take strings as produced by \\to_s and create a \\LayerInfo object from them. " "The format is either \"layer\", \"layer/datatype\", \"name\" or \"name (layer/datatype)\".\n" "\n" "This method was added in version 0.23.\n" + "The 'as_target' argument has been added in version 0.26.5.\n" ) + - gsi::method ("to_s", &db::LayerProperties::to_string, + gsi::method ("to_s", &db::LayerProperties::to_string, gsi::arg ("as_target", false), "@brief Convert the layer info object to a string\n" "@return The string\n" "\n" + "If 'as_target' is true, wildcard and relative specifications are formatted such such.\n" + "\n" "This method was added in version 0.18.\n" + "The 'as_target' argument has been added in version 0.26.5.\n" ) + gsi::method ("==", &db::LayerProperties::operator==, gsi::arg ("b"), "@brief Compares two layer info objects\n" diff --git a/src/db/unit_tests/dbStreamLayerTests.cc b/src/db/unit_tests/dbStreamLayerTests.cc new file mode 100644 index 000000000..4143bd927 --- /dev/null +++ b/src/db/unit_tests/dbStreamLayerTests.cc @@ -0,0 +1,409 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 "dbStreamLayers.h" +#include "dbLayout.h" +#include "tlUnitTest.h" + +TEST(1) +{ + db::LayerMap lm; + + lm.map (db::LDPair (1, 5), 17); + EXPECT_EQ (lm.logical (db::LDPair (1, 6)).first, false); + EXPECT_EQ (lm.logical (db::LDPair (1, 5)).first, true); + EXPECT_EQ (lm.logical (db::LDPair (1, 5)).second, (unsigned int) 17); + + lm.map (db::LDPair (1, 0), db::LDPair (5,0), 18); + EXPECT_EQ (lm.logical (db::LDPair (2, 0)).first, true); + EXPECT_EQ (lm.logical (db::LDPair (2, 0)).second, (unsigned int) 18); + EXPECT_EQ (lm.logical (db::LDPair (0, 0)).first, false); + + EXPECT_EQ (lm.mapping_str (18), "1/0;2-5/0"); + EXPECT_EQ (lm.mapping_str (17), "1/5"); + + lm.map (db::LDPair (2, 2), 18); + EXPECT_EQ (lm.mapping_str (18), "1/0;2/0,2;3-5/0"); + EXPECT_EQ (lm.mapping (18).to_string (), "3/0"); // any of those above! + + lm.map (db::LDPair (2, 3), 15, db::LayerProperties (17, 18)); + EXPECT_EQ (lm.mapping_str (15), "2/3 : 17/18"); + + lm.map ("WN", 22); + EXPECT_EQ (lm.mapping_str (22), "WN"); + EXPECT_EQ (lm.mapping (22).to_string (), "WN"); + lm.map (db::LDPair (2, 8), 22); + EXPECT_EQ (lm.mapping (22).to_string (), "WN (2/8)"); + + lm.map ("AA", 14, db::LayerProperties ("GC")); + EXPECT_EQ (lm.mapping_str (14), "AA : GC"); + EXPECT_EQ (lm.mapping (14).to_string (), "GC"); + lm.map (db::LDPair (7, 8), 14); + EXPECT_EQ (lm.mapping (14).to_string (), "GC (7/8)"); + + lm.map_expr ("XP;10/7-8 : XN", 13); + EXPECT_EQ (lm.mapping_str (13), "10/7-8;XP : XN"); + EXPECT_EQ (lm.logical ("XP").second, (unsigned int) 13); + EXPECT_EQ (lm.logical ("XP").first, true); + EXPECT_EQ (lm.logical (db::LDPair(10, 6)).first, false); + EXPECT_EQ (lm.logical (db::LDPair(10, 7)).first, true); + EXPECT_EQ (lm.logical (db::LDPair(10, 7)).second, (unsigned int) 13); + + EXPECT_EQ (lm.mapping (13).to_string (), "XN (10/7)"); + + lm.clear (); + EXPECT_EQ (lm.logical (db::LDPair(10, 7)).first, false); + lm.map_expr ("'XP';10/7-8 : XN", 13); + EXPECT_EQ (lm.mapping_str (13), "10/7-8;XP : XN"); +} + +TEST(2) +{ + db::LayerMap lm; + + lm.map (db::LDPair (1, 5), 17); + lm.map (db::LDPair (1, 0), db::LDPair (5,0), 18); + lm.map (db::LDPair (2, 2), 18); + lm.map (db::LDPair (2, 3), 15, db::LayerProperties (17, 18)); + lm.map ("WN", 22); + lm.map ("AA", 14, db::LayerProperties ("GC")); + lm.map_expr ("XP;10/7-8 : XN", 13); + + EXPECT_EQ (lm.to_string (), "layer_map('10/7-8;XP : XN';'AA : GC';'2/3 : 17/18';'1/5';'1/0;2/0,2;3-5/0';'WN')"); + EXPECT_EQ (lm.to_string_file_format (), "10/7-8;XP : XN\nAA : GC\n2/3 : 17/18\n1/5\n1/0;2/0,2;3-5/0\nWN\n"); + + db::LayerMap lm2; + db::LayerMap lm2read; + lm2 = db::LayerMap::from_string_file_format (lm2.to_string_file_format ()); + EXPECT_EQ (lm2.to_string (), "layer_map()"); + tl::Extractor (lm2.to_string ()).read (lm2read); + EXPECT_EQ (lm2read.to_string (), "layer_map()"); + lm2 = db::LayerMap::from_string_file_format (lm.to_string_file_format ()); + EXPECT_EQ (lm2.to_string (), "layer_map('10/7-8;XP : XN';'AA : GC';'2/3 : 17/18';'1/5';'1/0;2/0,2;3-5/0';'WN')"); + tl::Extractor (lm2.to_string ()).read (lm2read); + EXPECT_EQ (lm2read.to_string (), "layer_map('10/7-8;XP : XN';'AA : GC';'2/3 : 17/18';'1/5';'1/0;2/0,2;3-5/0';'WN')"); + + std::string ff = + "\n" + "\t // a comment\n" + "10/7-8;XP:XN \t # another comment\n" + "\n" + " AA\t: GC\n" + " 2/3 : 17/18\n" + " 1 / 5 \n" + "\t\t1/0;2/0,2;3-5/0\n" + "# commented out: 1/0;2/0,2;3-5/0\n" + "WN"; + + lm2 = db::LayerMap::from_string_file_format (ff); + EXPECT_EQ (lm2.to_string (), "layer_map('10/7-8;XP : XN';'AA : GC';'2/3 : 17/18';'1/5';'1/0;2/0,2;3-5/0';'WN')"); +} + +TEST(3) +{ + EXPECT_EQ (db::is_relative_ld (1), false); + EXPECT_EQ (db::is_relative_ld (0), false); + EXPECT_EQ (db::is_static_ld (0), true); + EXPECT_EQ (db::is_relative_ld (db::relative_ld (0)), true); + EXPECT_EQ (db::is_relative_ld (db::any_ld ()), true); + EXPECT_EQ (db::is_relative_ld (db::relative_ld (1)), true); + EXPECT_EQ (db::is_relative_ld (db::relative_ld (-1)), true); + EXPECT_EQ (db::is_static_ld (db::relative_ld (-1)), false); + EXPECT_EQ (db::is_any_ld (db::any_ld ()), true); + EXPECT_EQ (db::is_any_ld (1), false); + EXPECT_EQ (db::is_any_ld (db::relative_ld (-1)), false); + EXPECT_EQ (db::ld_offset (db::relative_ld (-1)), -1); + EXPECT_EQ (db::ld_offset (db::relative_ld (-100)), -100); + EXPECT_EQ (db::ld_offset (db::relative_ld (0)), 0); + EXPECT_EQ (db::ld_offset (db::relative_ld (1)), 1); + EXPECT_EQ (db::ld_offset (db::relative_ld (100)), 100); + EXPECT_EQ (db::ld_offset (100), 100); + EXPECT_EQ (db::ld_combine (1, db::relative_ld (100)), 101); + EXPECT_EQ (db::ld_combine (1, 100), 100); + EXPECT_EQ (db::ld_combine (100, db::relative_ld (-1)), 99); +} + +TEST(4) +{ + db::LayerMap lm; + + unsigned int n = 0; + + // named, no catch-all + lm.map (db::LayerProperties ("NAME"), n++); + + EXPECT_EQ (lm.to_string (), + "layer_map('NAME')" + ); + EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ()); + + lm.clear (); + n = 0; + + // single layer + lm.map (db::LayerProperties (1, 2), n++); + // single layer, wildcard target + lm.map (db::LayerProperties (1, 3), n++, db::LayerProperties (db::any_ld (), db::any_ld ())); + lm.map (db::LayerProperties (1, 4), n++, db::LayerProperties (2, db::any_ld ())); + lm.map (db::LayerProperties (1, 5), n++, db::LayerProperties (db::any_ld (), 15)); + // single layer, relative target + lm.map (db::LayerProperties (1, 6), n++, db::LayerProperties (db::any_ld (), db::relative_ld (3))); + + EXPECT_EQ (lm.to_string (), + "layer_map('1/2';'1/3 : */*';'1/4 : 2/*';'1/5 : */15';'1/6 : */*+3')" + ); + EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ()); + + lm.clear (); + n = 0; + + // datatype catch-all + lm.map (db::LayerProperties (1, db::any_ld ()), n++); + // datatype catch-all, fixed targets + lm.map (db::LayerProperties (2, db::any_ld ()), n++, db::LayerProperties (12, 2)); + // datatype catch-all, wildcard targets + lm.map (db::LayerProperties (3, db::any_ld ()), n++, db::LayerProperties (db::any_ld (), 2)); + lm.map (db::LayerProperties (4, db::any_ld ()), n++, db::LayerProperties (db::any_ld (), db::any_ld ())); + // datatype catch-all, relative targets + lm.map (db::LayerProperties (5, db::any_ld ()), n++, db::LayerProperties (15, db::relative_ld (0))); + lm.map (db::LayerProperties (6, db::any_ld ()), n++, db::LayerProperties (16, db::relative_ld (-1))); + lm.map (db::LayerProperties (7, db::any_ld ()), n++, db::LayerProperties (17, db::relative_ld (1))); + + EXPECT_EQ (lm.to_string (), + "layer_map('1/*';'2/* : 12/2';'3/* : */2';'4/* : */*';'5/* : 15/*';'6/* : 16/*-1';'7/* : 17/*+1')" + ); + EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ()); + + lm.clear (); + n = 0; + + // layer catch-all + lm.map (db::LayerProperties (db::any_ld (), 1), n++); + // layer catch-all, fixed targets + lm.map (db::LayerProperties (db::any_ld (), 2), n++, db::LayerProperties (1, 12)); + // layer catch-all, wildcard targets + lm.map (db::LayerProperties (db::any_ld (), 3), n++, db::LayerProperties (db::any_ld (), 2)); + lm.map (db::LayerProperties (db::any_ld (), 4), n++, db::LayerProperties (db::any_ld (), db::any_ld ())); + // layer catch-all, relative targets + lm.map (db::LayerProperties (db::any_ld (), 5), n++, db::LayerProperties (2, db::relative_ld (0))); + lm.map (db::LayerProperties (db::any_ld (), 6), n++, db::LayerProperties (2, db::relative_ld (-1))); + lm.map (db::LayerProperties (db::any_ld (), 7), n++, db::LayerProperties (2, db::relative_ld (1))); + + EXPECT_EQ (lm.to_string (), + "layer_map('*/1';'*/2 : 1/12';'*/3 : */2';'*/4 : */*';'*/5 : 2/*';'*/6 : 2/*-1';'*/7 : 2/*+1')" + ); + EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ()); + + lm.clear (); + n = 0; + + // layer and datatype catch-all + lm.map (db::LayerProperties (db::any_ld (), db::any_ld ()), n++); + + EXPECT_EQ (lm.to_string (), + "layer_map('*/*')" + ); + EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ()); + + lm.clear (); + n = 0; + + // layer and datatype catch-all, fixed targets + lm.map (db::LayerProperties (db::any_ld (), db::any_ld ()), n++, db::LayerProperties (1, 2)); + + EXPECT_EQ (lm.to_string (), + "layer_map('*/* : 1/2')" + ); + EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ()); + + lm.clear (); + n = 0; + + // layer and datatype catch-all, wildcard targets + lm.map (db::LayerProperties (db::any_ld (), db::any_ld ()), n++, db::LayerProperties (db::any_ld (), 2)); + + EXPECT_EQ (lm.to_string (), + "layer_map('*/* : */2')" + ); + EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ()); + + lm.clear (); + n = 0; + + lm.map (db::LayerProperties (db::any_ld (), db::any_ld ()), n++, db::LayerProperties (db::any_ld (), db::any_ld ())); + + EXPECT_EQ (lm.to_string (), + "layer_map('*/* : */*')" + ); + EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ()); + + lm.clear (); + n = 0; + + // layer and datatype catch-all, relative targets + lm.map (db::LayerProperties (db::any_ld (), db::any_ld ()), n++, db::LayerProperties (2, db::relative_ld (0))); + + EXPECT_EQ (lm.to_string (), + "layer_map('*/* : 2/*')" + ); + EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ()); + + lm.clear (); + n = 0; + + lm.map (db::LayerProperties (db::any_ld (), db::any_ld ()), n++, db::LayerProperties (2, db::relative_ld (-1))); + + EXPECT_EQ (lm.to_string (), + "layer_map('*/* : 2/*-1')" + ); + EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ()); + + lm.clear (); + n = 0; + + lm.map (db::LayerProperties (db::any_ld (), db::any_ld ()), n++, db::LayerProperties (2, db::relative_ld (1))); + + EXPECT_EQ (lm.to_string (), + "layer_map('*/* : 2/*+1')" + ); + EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ()); +} + +TEST(5) +{ + db::LayerMap lm; + + unsigned int n = 0; + + // refinement + // all + lm.map_expr ("*/*", n++); + // some + lm.map_expr ("*/1-10", n++); + // others + lm.map_expr ("*/5,15", n++); + + EXPECT_EQ (lm.to_string (), + "layer_map('*/0,11-14,16-*';'*/1-4,6-10';'*/5,15')" + ); + EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ()); + + // orthogonal layer refinement + lm.map_expr ("17/*", n++); + + EXPECT_EQ (lm.to_string (), + "layer_map('0-16/0,11-14,16-*;18-*/0,11-14,16-*';'0-16/1-4,6-10;18-*/1-4,6-10';'0-16/5,15;18-*/5,15';'17/*')" + ); + EXPECT_EQ (db::LayerMap::from_string_file_format (lm.to_string_file_format ()).to_string (), lm.to_string ()); +} + +static std::string layers_to_string (const db::Layout &ly) +{ + std::string s; + + for (unsigned int i = 0; i < ly.layers (); ++i) { + if (ly.is_valid_layer (i)) { + if (! s.empty ()) { + s += ","; + } + s += ly.get_properties (i).to_string (); + } + } + + return s; +} + +TEST(6) +{ + db::Layout ly; + db::LayerMap lm; + + EXPECT_EQ (layers_to_string (ly), ""); + + unsigned int n = 0; + lm.map_expr ("1/0", n++); + lm.map_expr ("2/* : */*", n++); + lm.map_expr ("3/10-*", n++); // all layers are mapped to 3/10 + + lm.prepare (ly); + + EXPECT_EQ (layers_to_string (ly), "1/0,3/10"); + + std::pair p; + p = lm.logical (db::LayerProperties (1, 0)); + EXPECT_EQ (p.first, true); + EXPECT_EQ (p.second, (unsigned int) 0); + + p = lm.logical (db::LayerProperties (2, 0)); + EXPECT_EQ (p.first, false); + + p = lm.logical (db::LayerProperties (3, 0)); + EXPECT_EQ (p.first, false); + + p = lm.logical (db::LayerProperties (3, 10)); + EXPECT_EQ (p.first, true); + EXPECT_EQ (p.second, (unsigned int) 1); + + p = lm.logical (db::LayerProperties (3, 99)); + EXPECT_EQ (p.first, true); + EXPECT_EQ (p.second, (unsigned int) 1); + + EXPECT_EQ (layers_to_string (ly), "1/0,3/10"); + + // this will create layer 2/0 in the layout + p = lm.logical (db::LayerProperties (2, 0), ly); + EXPECT_EQ (p.first, true); + EXPECT_EQ (p.second, (unsigned int) 2); + + EXPECT_EQ (layers_to_string (ly), "1/0,3/10,2/0"); + + p = lm.logical (db::LayerProperties (2, 0)); + EXPECT_EQ (p.first, true); + EXPECT_EQ (p.second, (unsigned int) 2); + + p = lm.logical (db::LayerProperties (2, 0), ly); + EXPECT_EQ (p.first, true); + EXPECT_EQ (p.second, (unsigned int) 2); + + EXPECT_EQ (layers_to_string (ly), "1/0,3/10,2/0"); + + // this will create layer 2/0 in the layout + p = lm.logical (db::LayerProperties (2, 42), ly); + EXPECT_EQ (p.first, true); + EXPECT_EQ (p.second, (unsigned int) 3); + + EXPECT_EQ (layers_to_string (ly), "1/0,3/10,2/0,2/42"); + + p = lm.logical (db::LayerProperties (2, 42)); + EXPECT_EQ (p.first, true); + EXPECT_EQ (p.second, (unsigned int) 3); + + p = lm.logical (db::LayerProperties (2, 42), ly); + EXPECT_EQ (p.first, true); + EXPECT_EQ (p.second, (unsigned int) 3); + + EXPECT_EQ (layers_to_string (ly), "1/0,3/10,2/0,2/42"); + + EXPECT_EQ (lm.to_string (), + "layer_map('1/0';'3/10-*';'2/0';'2/42';'2/1-41,43-* : */*')" + ); +} diff --git a/src/db/unit_tests/dbStreamLayers.cc b/src/db/unit_tests/dbStreamLayers.cc deleted file mode 100644 index e13ca5813..000000000 --- a/src/db/unit_tests/dbStreamLayers.cc +++ /dev/null @@ -1,121 +0,0 @@ - -/* - - KLayout Layout Viewer - Copyright (C) 2006-2020 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 "dbStreamLayers.h" -#include "tlUnitTest.h" - -TEST(1) -{ - db::LayerMap lm; - - lm.map (db::LDPair (1, 5), 17); - EXPECT_EQ (lm.logical (db::LDPair (1, 6)).first, false); - EXPECT_EQ (lm.logical (db::LDPair (1, 5)).first, true); - EXPECT_EQ (lm.logical (db::LDPair (1, 5)).second, (unsigned int) 17); - - lm.map (db::LDPair (1, 0), db::LDPair (5,0), 18); - EXPECT_EQ (lm.logical (db::LDPair (2, 0)).first, true); - EXPECT_EQ (lm.logical (db::LDPair (2, 0)).second, (unsigned int) 18); - EXPECT_EQ (lm.logical (db::LDPair (0, 0)).first, false); - - EXPECT_EQ (lm.mapping_str (18), "1/0;2-5/0"); - EXPECT_EQ (lm.mapping_str (17), "1/5"); - - lm.map (db::LDPair (2, 2), 18); - EXPECT_EQ (lm.mapping_str (18), "1/0;2/0,2;3-5/0"); - EXPECT_EQ (lm.mapping (18).to_string (), "3/0"); // any of those above! - - lm.map (db::LDPair (2, 3), 15, db::LayerProperties (17, 18)); - EXPECT_EQ (lm.mapping_str (15), "2/3 : 17/18"); - - lm.map ("WN", 22); - EXPECT_EQ (lm.mapping_str (22), "WN"); - EXPECT_EQ (lm.mapping (22).to_string (), "WN"); - lm.map (db::LDPair (2, 8), 22); - EXPECT_EQ (lm.mapping (22).to_string (), "WN (2/8)"); - - lm.map ("AA", 14, db::LayerProperties ("GC")); - EXPECT_EQ (lm.mapping_str (14), "AA : GC"); - EXPECT_EQ (lm.mapping (14).to_string (), "GC"); - lm.map (db::LDPair (7, 8), 14); - EXPECT_EQ (lm.mapping (14).to_string (), "GC (7/8)"); - - lm.map_expr ("XP;10/7-8 : XN", 13); - EXPECT_EQ (lm.mapping_str (13), "10/7-8;XP : XN"); - EXPECT_EQ (lm.logical ("XP").second, (unsigned int) 13); - EXPECT_EQ (lm.logical ("XP").first, true); - EXPECT_EQ (lm.logical (db::LDPair(10, 6)).first, false); - EXPECT_EQ (lm.logical (db::LDPair(10, 7)).first, true); - EXPECT_EQ (lm.logical (db::LDPair(10, 7)).second, (unsigned int) 13); - - EXPECT_EQ (lm.mapping (13).to_string (), "XN (10/7)"); - - lm.clear (); - EXPECT_EQ (lm.logical (db::LDPair(10, 7)).first, false); - lm.map_expr ("'XP';10/7-8 : XN", 13); - EXPECT_EQ (lm.mapping_str (13), "10/7-8;XP : XN"); -} - -TEST(2) -{ - db::LayerMap lm; - - lm.map (db::LDPair (1, 5), 17); - lm.map (db::LDPair (1, 0), db::LDPair (5,0), 18); - lm.map (db::LDPair (2, 2), 18); - lm.map (db::LDPair (2, 3), 15, db::LayerProperties (17, 18)); - lm.map ("WN", 22); - lm.map ("AA", 14, db::LayerProperties ("GC")); - lm.map_expr ("XP;10/7-8 : XN", 13); - - EXPECT_EQ (lm.to_string (), "layer_map('10/7-8;XP : XN';'AA : GC';'2/3 : 17/18';'1/5';'1/0;2/0,2;3-5/0';'WN')"); - EXPECT_EQ (lm.to_string_file_format (), "10/7-8;XP : XN\nAA : GC\n2/3 : 17/18\n1/5\n1/0;2/0,2;3-5/0\nWN\n"); - - db::LayerMap lm2; - db::LayerMap lm2read; - lm2 = db::LayerMap::from_string_file_format (lm2.to_string_file_format ()); - EXPECT_EQ (lm2.to_string (), "layer_map()"); - tl::Extractor (lm2.to_string ()).read (lm2read); - EXPECT_EQ (lm2read.to_string (), "layer_map()"); - lm2 = db::LayerMap::from_string_file_format (lm.to_string_file_format ()); - EXPECT_EQ (lm2.to_string (), "layer_map('10/7-8;XP : XN';'AA : GC';'2/3 : 17/18';'1/5';'1/0;2/0,2;3-5/0';'WN')"); - tl::Extractor (lm2.to_string ()).read (lm2read); - EXPECT_EQ (lm2read.to_string (), "layer_map('10/7-8;XP : XN';'AA : GC';'2/3 : 17/18';'1/5';'1/0;2/0,2;3-5/0';'WN')"); - - std::string ff = - "\n" - "\t // a comment\n" - "10/7-8;XP:XN \t # another comment\n" - "\n" - " AA\t: GC\n" - " 2/3 : 17/18\n" - " 1 / 5 \n" - "\t\t1/0;2/0,2;3-5/0\n" - "# commented out: 1/0;2/0,2;3-5/0\n" - "WN"; - - lm2 = db::LayerMap::from_string_file_format (ff); - EXPECT_EQ (lm2.to_string (), "layer_map('10/7-8;XP : XN';'AA : GC';'2/3 : 17/18';'1/5';'1/0;2/0,2;3-5/0';'WN')"); -} - diff --git a/src/db/unit_tests/unit_tests.pro b/src/db/unit_tests/unit_tests.pro index aee620228..5aa37d85e 100644 --- a/src/db/unit_tests/unit_tests.pro +++ b/src/db/unit_tests/unit_tests.pro @@ -42,7 +42,6 @@ SOURCES = \ dbShape.cc \ dbShapeRepository.cc \ dbShapes.cc \ - dbStreamLayers.cc \ dbText.cc \ dbTilingProcessor.cc \ dbTrans.cc \ @@ -73,7 +72,8 @@ SOURCES = \ dbLayoutVsSchematicTests.cc \ dbLayoutQueryTests.cc \ dbPolygonToolsTests.cc \ - dbTechnologyTests.cc + dbTechnologyTests.cc \ + dbStreamLayerTests.cc INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC DEPENDPATH += $$TL_INC $$DB_INC $$GSI_INC diff --git a/src/lay/lay/doc/about/layer_mapping.xml b/src/lay/lay/doc/about/layer_mapping.xml index fb10bd08c..b9209e016 100644 --- a/src/lay/lay/doc/about/layer_mapping.xml +++ b/src/lay/lay/doc/about/layer_mapping.xml @@ -93,5 +93,85 @@ are empty lines. Comments can be inserted using the "#" character in front of the comment.

+

Wildcards

+ +

+ Source layers can be specified using wildcards. A wildcard is a "*" character + matching "any layer". + Examples for such expressions are: +

+ + + + + + + + + + + + + + +
10-*/0Matching layer 10 and above, datatype 0
*/10Matching datatype 10 of every layer
0-5,10-*/*Matching layer 0 to 5 (inclusive) and above 10, all datatypes.
+ +

+ When ranges or wildcards are used as match expressions, the specified + layers will be lumped together into a single layer. This layer will have + the least permitted layer and datatype number. For example, with a + match expression of "1-10/*", all these layers will be mapped to "1/0". + This behavior can be modified using a target layer specification with + wildcards. +

+ +

Wildcard expansion and relative layer mapping

+ +

+ If the match expression includes a numerical range or wildcards + for the layer or datatype number, by default all these layers + will be combined into a single one, where it's layer or datatype number is derived + from the least permitted number. +

+ +

+ This behavior can be modified using wildcard expansion. This is a target layer + which includes a "*" wildcard. This wildcard is substituted by the actual + layer or datatype number: +

+ + + + + + + + + + + + + + +
10-*/0 : */10Maintain layers for layer 10 and above and map datatype to 10
10-*/0 : */*Select layers 10 and above, datatype 0 and maintain these as individual layers
1/* : 2/*Map layer number 1 to 2, maintain all datatypes
+ +

+ Relative layer mapping allows adding an offset to the layer or datatype numbers. + This offset can be negative with undefined behavior when the resulting number goes below + zero: +

+ + + + + + + + + + +
10-20/*: *+1000/*Selects all layers between 10 and 20, all datatypes. These layers will be + read into the original layers plus 1000 for the layer number.
10/10-*: */*-10Selects layer 10, datatypes 10 plus. The resulting datatypes will be 10 less starting from 0.
+ diff --git a/src/plugins/streamers/dxf/db_plugin/dbDXFReader.cc b/src/plugins/streamers/dxf/db_plugin/dbDXFReader.cc index bc496f762..85fe87027 100644 --- a/src/plugins/streamers/dxf/db_plugin/dbDXFReader.cc +++ b/src/plugins/streamers/dxf/db_plugin/dbDXFReader.cc @@ -383,7 +383,7 @@ DXFReader::do_read (db::Layout &layout, db::cell_index_type top) // create the zero layer - this is not mapped to GDS but can be specified in the layer mapping as // a layer named "0". - std::pair ll = layer_map ().logical (zero_layer_name); + std::pair ll = layer_map ().logical (zero_layer_name, layout); if (ll.first) { // create the layer if it is not part of the layout yet. diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc b/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc index 8006de403..4d6695891 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc @@ -176,7 +176,7 @@ GDS2ReaderBase::finish_element (db::PropertiesRepository &rep) std::pair GDS2ReaderBase::open_dl (db::Layout &layout, const LDPair &dl, bool create) { - std::pair ll = m_layer_map.logical (dl); + std::pair ll = m_layer_map.logical (dl, layout); if (ll.first) { return ll; diff --git a/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc b/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc index 6b738f6bc..b1971b0e4 100644 --- a/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc +++ b/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc @@ -391,3 +391,46 @@ TEST(Bug_121_2) db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1); } +TEST(3_AdvancedMapping) +{ + db::Manager m (false); + db::Layout layout (&m); + + db::LoadLayoutOptions options; + db::LayerMap lm, lm_read; + + unsigned int n = 0; + lm.map_expr ("*/*: *+100/*", n++); + lm.map_expr ("1/*: */*", n++); + lm.map_expr ("1/10: 1/0", n++); + lm.map_expr ("1/20-30: 1/*+1000", n++); + lm.map_expr ("2/*", n++); + lm.map_expr ("2/10-20: */*", n++); + options.get_options ().layer_map = lm; + + { + tl::InputStream file (tl::testsrc () + "/testdata/gds/alm.gds"); + db::Reader reader (file); + lm_read = reader.read (layout, options); + } + + EXPECT_EQ (lm_read.to_string_file_format (), + "1/10 : 1/0\n" + "2/0-9,21-*\n" + "1/0 : 1/0\n" + "1/1 : 1/1\n" + "1/20 : 1/1020\n" + "1/21 : 1/1021\n" + "2/10 : 2/10\n" + "2/11 : 2/11\n" + "42/42 : 142/42\n" + "100/0 : 200/0\n" + "2/12-20 : */*\n" + "1/22-30 : 1/*+1000\n" + "1/2-9,11-19,31-* : */*\n" + "0/*;3-41/*;42/0-41,43-*;43-99/*;100/1-*;101-*/* : *+100/*\n" + ); + + std::string fn_au (tl::testsrc () + "/testdata/gds/alm_au.gds"); + db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1); +} diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc index a60e37a89..430a31f25 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc @@ -174,7 +174,7 @@ LEFDEFLayerDelegate::open_layer (db::Layout &layout, const std::string &n, Layer lp.datatype = 0; } - std::pair ll = m_layer_map.logical (lp); + std::pair ll = m_layer_map.logical (lp, layout); if (ll.first) { @@ -243,7 +243,7 @@ LEFDEFLayerDelegate::open_layer (db::Layout &layout, const std::string &n, Layer return std::make_pair (false, 0); } - std::pair ll = m_layer_map.logical (name); + std::pair ll = m_layer_map.logical (name, layout); if (ll.first) { @@ -256,14 +256,14 @@ LEFDEFLayerDelegate::open_layer (db::Layout &layout, const std::string &n, Layer } else { - std::pair ll_raw = m_layer_map.logical (n); + std::pair ll_raw = m_layer_map.logical (n, layout); int ln = -1; if (ll_raw.first && (ln = layout.get_properties (ll_raw.second).layer) >= 0) { m_layer_map.map (db::LayerProperties (name), layout.layers (), db::LayerProperties (ln, dt, name)); m_layer_map.prepare (layout); - return m_layer_map.logical (name); + return m_layer_map.logical (name, layout); } else if (! m_create_layers) { diff --git a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc index d3cc00511..2d084c313 100644 --- a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc +++ b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc @@ -554,7 +554,7 @@ OASISReader::warn (const std::string &msg) std::pair OASISReader::open_dl (db::Layout &layout, const LDPair &dl, bool create) { - std::pair ll = m_layer_map.logical (dl); + std::pair ll = m_layer_map.logical (dl, layout); if (ll.first) { return ll; diff --git a/testdata/gds/alm_au.gds b/testdata/gds/alm_au.gds new file mode 100644 index 000000000..513fcb589 Binary files /dev/null and b/testdata/gds/alm_au.gds differ