// 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 <https://www.gnu.org/licenses/>.
// 
// 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 "ParseBus.hh"
#include "PatternMatch.hh"
#include "StringUtil.hh"

namespace sta {

NetworkNameAdapter::NetworkNameAdapter(Network *network) :
  network_(network),
  network_edit_(dynamic_cast<NetworkEdit*>(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);
}

Port *
NetworkNameAdapter::makePort(Cell *cell,
                             std::string_view name)
{
  return network_edit_->makePort(cell, name);
}

////////////////////////////////////////////////////////////////

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));
}

Port *
SdcNetwork::makePort(Cell *cell,
                     std::string_view name)
{
  std::string escaped_name = escapeDividerBrackets(name, network_edit_);
  return network_edit_->makePort(cell, escaped_name);
}

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 = escapeDividerBrackets(name, this);
  return network_edit_->makeInstance(cell, escaped_name, parent);
}

Net *
SdcNetwork::makeNet(std::string_view name,
                    Instance *parent)
{
  std::string escaped_name = escapeDividerBrackets(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 &divider_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<bool (const Instance *instance,
                                                   const PatternMatch *tail)>
                         &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
escapeDividerBrackets(std::string_view name,
                      const Network *network)
{
  return escapeChars(name, network->pathDivider(), '[', ']',
                     network->pathEscape());
}

std::string
escapeDividers(std::string_view name,
               const Network *network)
{
  return escapeChars(name, network->pathDivider(), '\0', '\0',
                     network->pathEscape());
}

std::string
escapeBrackets(std::string_view name,
               const Network *network)
{
  return escapeChars(name, '[', ']', '\0', network->pathEscape());
}

} // namespace sta
