// OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. // // 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 3 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, see . // // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. // // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. // // This notice may not be removed or altered from any source distribution. #include "SdcNetwork.hh" #include "StringUtil.hh" #include "PatternMatch.hh" #include "ParseBus.hh" namespace sta { NetworkNameAdapter::NetworkNameAdapter(Network *network) : NetworkEdit(), network_(network), network_edit_(dynamic_cast(network)) { } bool NetworkNameAdapter::linkNetwork(std::string_view top_cell_name, bool make_black_boxes, Report *report) { return network_->linkNetwork(top_cell_name, make_black_boxes, report); } Instance * NetworkNameAdapter::topInstance() const { return network_->topInstance(); } LibertyLibrary * NetworkNameAdapter::defaultLibertyLibrary() const { return network_->defaultLibertyLibrary(); } LibraryIterator * NetworkNameAdapter::libraryIterator() const { return network_->libraryIterator(); } LibertyLibraryIterator * NetworkNameAdapter::libertyLibraryIterator() const { return network_->libertyLibraryIterator(); } Library * NetworkNameAdapter::findLibrary(std::string_view name) { return network_->findLibrary(name); } LibertyLibrary * NetworkNameAdapter::findLiberty(std::string_view name) { return network_->findLiberty(name); } LibertyLibrary * NetworkNameAdapter::findLibertyFilename(std::string_view filename) { return network_->findLibertyFilename(filename); } std::string NetworkNameAdapter::name(const Library *library) const { return network_->name(library); } ObjectId NetworkNameAdapter::id(const Library *library) const { return network_->id(library); } Cell * NetworkNameAdapter::findCell(const Library *library, std::string_view name) const { return network_->findCell(library, name); } CellSeq NetworkNameAdapter::findCellsMatching(const Library *library, const PatternMatch *pattern) const { return network_->findCellsMatching(library, pattern); } //////////////////////////////////////////////////////////////// std::string NetworkNameAdapter::name(const Cell *cell) const { return network_->name(cell); } ObjectId NetworkNameAdapter::id(const Cell *cell) const { return network_->id(cell); } std::string NetworkNameAdapter::getAttribute(const Cell *cell, std::string_view key) const { return network_->getAttribute(cell, key); } const AttributeMap & NetworkNameAdapter::attributeMap(const Cell *cell) const { return network_->attributeMap(cell); } Library * NetworkNameAdapter::library(const Cell *cell) const { return network_->library(cell); } std::string_view NetworkNameAdapter::filename(const Cell *cell) const { return network_->filename(cell); } LibertyCell * NetworkNameAdapter::libertyCell(Cell *cell) const { return network_->libertyCell(cell); } const LibertyCell * NetworkNameAdapter::libertyCell(const Cell *cell) const { return network_->libertyCell(cell); } Cell * NetworkNameAdapter::cell(LibertyCell *cell) const { return network_->cell(cell); } const Cell * NetworkNameAdapter::cell(const LibertyCell *cell) const { return network_->cell(cell); } Port * NetworkNameAdapter::findPort(const Cell *cell, std::string_view name) const { return network_->findPort(cell, name); } PortSeq NetworkNameAdapter::findPortsMatching(const Cell *cell, const PatternMatch *pattern) const { return network_->findPortsMatching(cell, pattern); } bool NetworkNameAdapter::isLeaf(const Cell *cell) const { return network_->isLeaf(cell); } CellPortIterator * NetworkNameAdapter::portIterator(const Cell *cell) const { return network_->portIterator(cell); } CellPortBitIterator * NetworkNameAdapter::portBitIterator(const Cell *cell) const { return network_->portBitIterator(cell); } int NetworkNameAdapter::portBitCount(const Cell *cell) const { return network_->portBitCount(cell); } //////////////////////////////////////////////////////////////// std::string NetworkNameAdapter::name(const Port *port) const { return network_->name(port); } ObjectId NetworkNameAdapter::id(const Port *port) const { return network_->id(port); } Cell * NetworkNameAdapter::cell(const Port *port) const { return network_->cell(port); } LibertyPort * NetworkNameAdapter::libertyPort(const Port *port) const { return network_->libertyPort(port); } PortDirection * NetworkNameAdapter::direction(const Port *port) const { return network_->direction(port); } VertexId NetworkNameAdapter::vertexId(const Pin *pin) const { return network_->vertexId(pin); } void NetworkNameAdapter::setVertexId(Pin *pin, VertexId id) { network_->setVertexId(pin, id); } void NetworkNameAdapter::location(const Pin *pin, // Return values. double &x, double &y, bool &exists) const { network_->location(pin, x, y, exists); } bool NetworkNameAdapter::isBundle(const Port *port) const { return network_->isBundle(port); } bool NetworkNameAdapter::isBus(const Port *port) const { return network_->isBus(port); } std::string NetworkNameAdapter::busName(const Port *port) const { return network_->busName(port); } Port * NetworkNameAdapter::findBusBit(const Port *port, int index) const { return network_->findMember(port, index); } int NetworkNameAdapter::size(const Port *port) const { return network_->size(port); } int NetworkNameAdapter::fromIndex(const Port *port) const { return network_->fromIndex(port); } int NetworkNameAdapter::toIndex(const Port *port) const { return network_->toIndex(port); } bool NetworkNameAdapter::hasMembers(const Port *port) const { return network_->hasMembers(port); } Port * NetworkNameAdapter::findMember(const Port *port, int index) const { return network_->findMember(port, index); } PortMemberIterator * NetworkNameAdapter::memberIterator(const Port *port) const { return network_->memberIterator(port); } //////////////////////////////////////////////////////////////// ObjectId NetworkNameAdapter::id(const Instance *instance) const { return network_->id(instance); } Cell * NetworkNameAdapter::cell(const Instance *instance) const { return network_->cell(instance); } std::string NetworkNameAdapter::getAttribute(const Instance *inst, std::string_view key) const { return network_->getAttribute(inst, key); } const AttributeMap & NetworkNameAdapter::attributeMap(const Instance *inst) const { return network_->attributeMap(inst); } Instance * NetworkNameAdapter::parent(const Instance *instance) const { return network_->parent(instance); } bool NetworkNameAdapter::isLeaf(const Instance *instance) const { return network_->isLeaf(instance); } Pin * NetworkNameAdapter::findPin(const Instance *instance, const Port *port) const { return network_->findPin(instance, port); } Pin * NetworkNameAdapter::findPin(const Instance *instance, const LibertyPort *port) const { return network_->findPin(instance, port); } InstanceChildIterator * NetworkNameAdapter::childIterator(const Instance *instance) const { return network_->childIterator(instance); } InstancePinIterator * NetworkNameAdapter::pinIterator(const Instance *instance) const { return network_->pinIterator(instance); } InstanceNetIterator * NetworkNameAdapter::netIterator(const Instance *instance) const { return network_->netIterator(instance); } ObjectId NetworkNameAdapter::id(const Pin *pin) const { return network_->id(pin); } Port * NetworkNameAdapter::port(const Pin *pin) const { return network_->port(pin); } Instance * NetworkNameAdapter::instance(const Pin *pin) const { return network_->instance(pin); } Net * NetworkNameAdapter::net(const Pin *pin) const { return network_->net(pin); } Term * NetworkNameAdapter::term(const Pin *pin) const { return network_->term(pin); } PortDirection * NetworkNameAdapter::direction(const Pin *pin) const { return network_->direction(pin); } ObjectId NetworkNameAdapter::id(const Term *term) const { return network_->id(term); } Net * NetworkNameAdapter::net(const Term *term) const { return network_->net(term); } Pin * NetworkNameAdapter::pin(const Term *term) const { return network_->pin(term); } ObjectId NetworkNameAdapter::id(const Net *net) const { return network_->id(net); } Instance * NetworkNameAdapter::instance(const Net *net) const { return network_->instance(net); } NetPinIterator * NetworkNameAdapter::pinIterator(const Net *net) const { return network_->pinIterator(net); } NetTermIterator * NetworkNameAdapter::termIterator(const Net *net) const { return network_->termIterator(net); } bool NetworkNameAdapter::isPower(const Net *net) const { return network_->isPower(net); } bool NetworkNameAdapter::isGround(const Net *net) const { return network_->isGround(net); } ConstantPinIterator * NetworkNameAdapter::constantPinIterator() { return network_->constantPinIterator(); } char NetworkNameAdapter::pathDivider() const { return network_->pathDivider(); } void NetworkNameAdapter::setPathDivider(char divider) { network_->setPathDivider(divider); } char NetworkNameAdapter::pathEscape() const { return network_->pathEscape(); } void NetworkNameAdapter::setPathEscape(char escape) { network_->setPathEscape(escape); } bool NetworkNameAdapter::isEditable() const { return network_->isEditable(); } LibertyLibrary * NetworkNameAdapter::makeLibertyLibrary(std::string_view name, std::string_view filename) { return network_edit_->makeLibertyLibrary(name, filename); } Instance * NetworkNameAdapter::makeInstance(LibertyCell *cell, std::string_view name, Instance *parent) { return network_edit_->makeInstance(cell, name, parent); } void NetworkNameAdapter::makePins(Instance *inst) { network_edit_->makePins(inst); } void NetworkNameAdapter::mergeInto(Net *net, Net *into_net) { network_edit_->mergeInto(net, into_net); } Net * NetworkNameAdapter::mergedInto(Net *net) { return network_edit_->mergedInto(net); } Net * NetworkNameAdapter::makeNet(std::string_view name, Instance *parent) { return network_edit_->makeNet(name, parent); } void NetworkNameAdapter::replaceCell(Instance *inst, Cell *to_cell) { network_edit_->replaceCell(inst, to_cell); } Pin * NetworkNameAdapter::connect(Instance *inst, Port *port, Net *net) { return network_edit_->connect(inst, port, net); } Pin * NetworkNameAdapter::connect(Instance *inst, LibertyPort *port, Net *net) { return network_edit_->connect(inst, port, net); } void NetworkNameAdapter::disconnectPin(Pin *pin) { network_edit_->disconnectPin(pin); } void NetworkNameAdapter::deleteNet(Net *net) { network_edit_->deleteNet(net); } void NetworkNameAdapter::deletePin(Pin *pin) { network_edit_->deletePin(pin); } void NetworkNameAdapter::deleteInstance(Instance *inst) { network_edit_->deleteInstance(inst); } //////////////////////////////////////////////////////////////// Network * makeSdcNetwork(Network *network) { return new SdcNetwork(network); } SdcNetwork::SdcNetwork(Network *network) : NetworkNameAdapter(network) { } // Translate sta namespace to sdc namespace. // Remove all escapes. std::string SdcNetwork::staToSdc(std::string_view sta_name) const { char escape = pathEscape(); size_t sta_length = sta_name.length(); std::string sdc_name; for (size_t i = 0; i < sta_length; i++) { char ch = sta_name[i]; if (ch == escape) { char next_ch = sta_name[i + 1]; // Escaped escape. if (next_ch == escape) { sdc_name += ch; sdc_name += next_ch; i++; } } else // Non escape. sdc_name += ch; } return sdc_name; } Port * SdcNetwork::findPort(const Cell *cell, std::string_view name) const { Port *port = network_->findPort(cell, name); if (port == nullptr) { // Look for matches after escaping brackets. bool is_bus; std::string bus_name; int index; parseBusName(name, '[', ']', pathEscape(), is_bus, bus_name, index); if (is_bus) { std::string escaped1 = escapeBrackets(std::string(name), this); port = network_->findPort(cell, escaped1); if (port == nullptr) { // Try escaping base foo\[0\][1] std::string escaped_bus_name = escapeBrackets(bus_name, this); std::string escaped2 = escaped_bus_name + '[' + std::to_string(index) + ']'; port = network_->findPort(cell, escaped2); } } else { // Try escaping brackets foo\[0\].bar std::string escaped = escapeBrackets(std::string(name), this); port = network_->findPort(cell, escaped); } } return port; } PortSeq SdcNetwork::findPortsMatching(const Cell *cell, const PatternMatch *pattern) const { PortSeq matches = network_->findPortsMatching(cell, pattern); if (matches.empty()) { // Look for matches after escaping brackets. bool is_bus; std::string bus_name; int index; parseBusName(pattern->pattern(), '[', ']', pathEscape(), is_bus, bus_name, index); if (is_bus) { std::string escaped1 = escapeBrackets(pattern->pattern(), this); PatternMatch escaped_pattern1(escaped1, pattern); matches = network_->findPortsMatching(cell, &escaped_pattern1); if (matches.empty()) { // Try escaping base foo\[0\][1] std::string escaped_name = escapeBrackets(bus_name, this); escaped_name += '['; escaped_name += std::to_string(index); escaped_name += ']'; PatternMatch escaped_pattern2(escaped_name, pattern); matches = network_->findPortsMatching(cell, &escaped_pattern2); } } else { // Try escaping brackets foo\[0\].bar std::string escaped = escapeBrackets(pattern->pattern(), this); PatternMatch escaped_pattern(escaped, pattern); matches = network_->findPortsMatching(cell, &escaped_pattern); } } return matches; } std::string SdcNetwork::name(const Port *port) const { return staToSdc(network_->name(port)); } std::string SdcNetwork::busName(const Port *port) const { return staToSdc(network_->busName(port)); } std::string SdcNetwork::name(const Instance *instance) const { return staToSdc(network_->name(instance)); } std::string SdcNetwork::pathName(const Instance *instance) const { return staToSdc(network_->pathName(instance)); } std::string SdcNetwork::pathName(const Pin *pin) const { return staToSdc(network_->pathName(pin)); } std::string SdcNetwork::portName(const Pin *pin) const { return staToSdc(network_->portName(pin)); } std::string SdcNetwork::name(const Net *net) const { return staToSdc(network_->name(net)); } std::string SdcNetwork::pathName(const Net *net) const { return staToSdc(network_->pathName(net)); } //////////////////////////////////////////////////////////////// Instance * SdcNetwork::findInstance(std::string_view path_name) const { std::string child_name; Instance *parent; parsePath(path_name, parent, child_name); if (parent == nullptr) parent = network_->topInstance(); Instance *child = findChild(parent, child_name); if (child == nullptr) { std::string escaped_name = escapeDividers(child_name, this); child = findChild(parent, escaped_name); } return child; } Instance * SdcNetwork::findInstanceRelative(const Instance *inst, std::string_view path_name) const { Instance *inst1 = network_->findInstanceRelative(inst, path_name); if (inst1 == nullptr) { std::string path_name1 = escapeBrackets(std::string(path_name), this); inst1 = network_->findInstanceRelative(inst, path_name1); if (inst1 == nullptr) { std::string path_name2 = escapeDividers(path_name1, network_); inst1 = network_->findInstanceRelative(inst, path_name2); } } return inst1; } InstanceSeq SdcNetwork::findInstancesMatching(const Instance *context, const PatternMatch *pattern) const { InstanceSeq matches; findInstancesMatching1(context, pattern, matches); return matches; } void SdcNetwork::findInstancesMatching1(const Instance *context, const PatternMatch *pattern, InstanceSeq &matches) const { visitMatches(context, pattern, [&](const Instance *instance, const PatternMatch *tail) { size_t match_count = matches.size(); network_->findChildrenMatching(instance, tail, matches); return matches.size() != match_count; }); } Instance * SdcNetwork::findChild(const Instance *parent, std::string_view name) const { Instance *child = network_->findChild(parent, name); if (child == nullptr) { std::string escaped = escapeBrackets(std::string(name), this); child = network_->findChild(parent, escaped); } return child; } //////////////////////////////////////////////////////////////// Net * SdcNetwork::findNet(std::string_view path_name) const { std::string net_name; Instance *inst; parsePath(path_name, inst, net_name); if (inst == nullptr) inst = network_->topInstance(); return findNetRelative(inst, net_name); } Net * SdcNetwork::findNet(const Instance *instance, std::string_view net_name) const { Net *net = network_->findNet(instance, net_name); if (net == nullptr) { std::string net_name1 = escapeBrackets(std::string(net_name), this); std::string net_name2 = escapeDividers(net_name1, network_); net = network_->findNet(instance, net_name2); } return net; } Net * SdcNetwork::findNetRelative(const Instance *inst, std::string_view path_name) const { Net *net = network_->findNetRelative(inst, path_name); if (net == nullptr) { std::string path_name1 = escapeDividers(std::string(path_name), network_); net = network_->findNetRelative(inst, path_name1); if (net == nullptr) { std::string path_name2 = escapeBrackets(std::string(path_name), network_); net = network_->findNetRelative(inst, path_name2); if (net == nullptr) { std::string path_name3 = escapeDividers(path_name2, network_); net = network_->findNetRelative(inst, path_name3); } } } return net; } NetSeq SdcNetwork::findNetsMatching(const Instance *parent, const PatternMatch *pattern) const { NetSeq matches; visitMatches(parent, pattern, [&](const Instance *instance, const PatternMatch *tail) { size_t match_count = matches.size(); network_->findInstNetsMatching(instance, tail, matches); return matches.size() != match_count; }); return matches; } void SdcNetwork::findInstNetsMatching(const Instance *instance, const PatternMatch *pattern, NetSeq &matches) const { network_->findInstNetsMatching(instance, pattern, matches); if (matches.empty()) { // Look for matches after escaping path dividers. std::string escaped_pattern = escapeDividers(pattern->pattern(), this); const PatternMatch escaped_dividers(escaped_pattern, pattern); network_->findInstNetsMatching(instance, &escaped_dividers, matches); if (matches.empty()) { // Look for matches after escaping brackets. std::string escaped_pattern2 = escapeBrackets(pattern->pattern(),this); const PatternMatch escaped_brkts(escaped_pattern2, pattern); network_->findInstNetsMatching(instance, &escaped_brkts, matches); } } } //////////////////////////////////////////////////////////////// Pin * SdcNetwork::findPin(std::string_view path_name) const { std::string port_name; Instance *inst; parsePath(path_name, inst, port_name); if (inst == nullptr) inst = network_->topInstance(); return findPin(inst, port_name); } Pin * SdcNetwork::findPin(const Instance *instance, std::string_view port_name) const { Pin *pin = network_->findPin(instance, port_name); if (pin == nullptr) { // Look for match after escaping brackets. bool is_bus; std::string bus_name; int index; parseBusName(port_name, '[', ']', pathEscape(), is_bus, bus_name, index); if (is_bus) { std::string escaped1 = escapeBrackets(std::string(port_name), this); pin = network_->findPin(instance, escaped1); if (pin == nullptr) { // Try escaping base foo\[0\][1] std::string escaped_bus_name = escapeBrackets(bus_name, this); std::string escaped2 = escaped_bus_name + '[' + std::to_string(index) + ']'; pin = network_->findPin(instance, escaped2); } } else { // Try escaping port brackets foo\[0\].bar std::string escaped = escapeBrackets(std::string(port_name), this); pin = network_->findPin(instance, escaped); } } return pin; } // Top level ports are not considered pins by get_pins. PinSeq SdcNetwork::findPinsMatching(const Instance *instance, const PatternMatch *pattern) const { PinSeq matches; if (pattern->pattern() == "*") { // Pattern of '*' matches all child instance pins. InstanceChildIterator *child_iter = childIterator(instance); while (child_iter->hasNext()) { Instance *child = child_iter->next(); InstancePinIterator *pin_iter = pinIterator(child); while (pin_iter->hasNext()) { const Pin *pin = pin_iter->next(); matches.push_back(pin); } delete pin_iter; } delete child_iter; } else visitMatches(instance, pattern, [&](const Instance *instance, const PatternMatch *tail) { return visitPinTail(instance, tail, matches); }); return matches; } bool SdcNetwork::visitPinTail(const Instance *instance, const PatternMatch *tail, PinSeq &matches) const { bool found_match = false; if (instance != network_->topInstance()) { Cell *cell = network_->cell(instance); CellPortIterator *port_iter = network_->portIterator(cell); while (port_iter->hasNext()) { Port *port = port_iter->next(); std::string port_name = network_->name(port); if (network_->hasMembers(port)) { bool bus_matches = tail->match(port_name); if (!bus_matches) { std::string escaped_name = escapeDividers(std::string(port_name), network_); bus_matches = tail->match(escaped_name); } PortMemberIterator *member_iter = network_->memberIterator(port); while (member_iter->hasNext()) { Port *member_port = member_iter->next(); const Pin *pin = network_->findPin(instance, member_port); if (pin) { if (bus_matches) { matches.push_back(pin); found_match = true; } else { std::string member_name = network_->name(member_port); bool member_matches = tail->match(member_name); if (!member_matches) { std::string escaped_name = escapeDividers(std::string(member_name), network_); member_matches = tail->match(escaped_name); } if (member_matches) { matches.push_back(pin); found_match = true; } } } } delete member_iter; } else { bool port_matches = tail->match(port_name); if (!port_matches) { std::string escaped_name = escapeDividers(std::string(port_name), network_); port_matches = tail->match(escaped_name); } if (port_matches) { Pin *pin = network_->findPin(instance, port); if (pin) { matches.push_back(pin); found_match = true; } } } } delete port_iter; } return found_match; } Instance * SdcNetwork::makeInstance(LibertyCell *cell, std::string_view name, Instance *parent) { std::string escaped_name = escapeDividers(std::string(name), this); return network_edit_->makeInstance(cell, escaped_name, parent); } Net * SdcNetwork::makeNet(std::string_view name, Instance *parent) { std::string escaped_name = escapeDividers(std::string(name), this); return network_edit_->makeNet(escaped_name, parent); } //////////////////////////////////////////////////////////////// // Helper to parse an instance path (with optional net/port tail). // Since dividers are not escaped in SDC, look for an instance for // each sub-section of the path. If none is found, escape the divider // and keep looking. For the path a/b/c this looks for instances // a // a\/b // a\/b\/c void SdcNetwork::parsePath(std::string_view path, // Return values. Instance *&inst, std::string &path_tail) const { int divider_count, path_length; scanPath(path, divider_count, path_length); if (divider_count > 0) parsePath(path, divider_count, path_length, inst, path_tail); else { inst = nullptr; path_tail = path; } } // Scan the path for unescaped dividers. void SdcNetwork::scanPath(std::string_view path, // Return values. // Unescaped divider count. int ÷r_count, int &path_length) const { divider_count = 0; path_length = 0; for (size_t i = 0; i < path.size(); i++) { char ch = path[i]; if (ch == escape_) { // Make sure we don't skip the null if escape is the last char. if (i != path.size() - 1) { i++; path_length++; } } else if (ch == divider_) divider_count++; path_length++; } } void SdcNetwork::parsePath(std::string_view path, int divider_count, int path_length, // Return values. Instance *&inst, std::string &path_tail) const { Instance *parent = topInstance(); std::string inst_path; // Leave room to escape all the dividers. inst_path.reserve(path_length + divider_count); inst = nullptr; path_tail = path; for (size_t i = 0; i < path.size(); i++) { char ch = path[i]; if (ch == escape_) { // Make sure we don't skip the null if escape is the last char. if (i < path.size() - 1) { inst_path += ch; inst_path += path[i + 1]; i++; } } else if (ch == divider_) { Instance *child = findChild(parent, inst_path); if (child) { // Found an instance for the sub-path up to this divider. parent = inst = child; // Reset the instance path. inst_path.clear(); path_tail = path.substr(i + 1); } else { // No match for sub-path. Escape the divider and keep looking. inst_path += escape_; inst_path += divider_; } } else inst_path += ch; } } // Helper to visit instance path matches. // Since dividers are not escaped in SDC, look for instance matches for // each sub-section of the path. If none are found, escape the divider // and keep looking. For the path a/b/c this looks for instances // a // a\/b // a\/b\/c bool SdcNetwork::visitMatches(const Instance *parent, const PatternMatch *pattern, const std::function visit_tail) const { int divider_count, path_length; scanPath(pattern->pattern(), divider_count, path_length); std::string inst_path; // Leave room to escape all the dividers and '\0'. inst_path.reserve(path_length + divider_count + 1); bool has_brkts = false; bool found_match = false; const std::string &pattern_str = pattern->pattern(); for (size_t i = 0; i < pattern_str.size(); i++) { char ch = pattern_str[i]; if (ch == escape_) { // Make sure we don't skip the null if escape is the last char. if (i < pattern_str.size() - 1) { inst_path += ch; inst_path += pattern_str[i + 1]; i++; } } else if (ch == divider_) { PatternMatch matcher(inst_path, pattern); InstanceSeq matches; network_->findChildrenMatching(parent, &matcher, matches); if (has_brkts && matches.empty()) { // Look for matches after escaping brackets. std::string escaped_brkts = escapeBrackets(inst_path, this); const PatternMatch escaped_pattern(escaped_brkts, pattern); network_->findChildrenMatching(parent, &escaped_pattern, matches); } if (!matches.empty()) { // Found instance matches for the sub-path up to this divider. const PatternMatch tail_pattern(pattern_str.substr(i + 1), pattern); for (const Instance *match : matches) // Recurse to save the iterator state so we can iterate over // multiple nested partial matches. found_match |= visitMatches(match, &tail_pattern, visit_tail); } // Escape the divider and keep looking. inst_path += escape_; inst_path += divider_; } else { if (ch == '[' || ch == ']') has_brkts = true; inst_path += ch; } } if (!found_match) { PatternMatch tail_pattern(inst_path, pattern); found_match |= visit_tail(parent, &tail_pattern); if (!found_match && has_brkts) { // Look for matches after escaping brackets. std::string escaped_path = escapeBrackets(inst_path, this); const PatternMatch escaped_tail(escaped_path, pattern); found_match |= visit_tail(parent, &escaped_tail); } } return found_match; } //////////////////////////////////////////////////////////////// std::string escapeDividers(std::string_view name, const Network *network) { return escapeChars(name, network->pathDivider(), '\0', network->pathEscape()); } std::string escapeBrackets(std::string_view name, const Network *network) { return escapeChars(name, '[', ']', network->pathEscape()); } } // namespace