// 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 "ConcreteNetwork.hh"

#include <algorithm>
#include <map>
#include <string_view>

#include "ConcreteLibrary.hh"
#include "Liberty.hh"
#include "Network.hh"
#include "PatternMatch.hh"
#include "PortDirection.hh"
#include "Report.hh"

namespace sta {

static void
makeChildNetwork(Instance *proto,
                 Instance *parent,
                 ConcreteBindingTbl *parent_bindings,
                 NetworkReader *network);
static void
makeClonePins(Instance *proto,
              Instance *clone,
              Instance *clone_view,
              ConcreteBindingTbl *bindings,
              Instance *parent,
              ConcreteBindingTbl *parent_bindings,
              NetworkReader *network);


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

NetworkReader *
makeConcreteNetwork()
{
  return new ConcreteNetwork;
}

class ConcreteInstanceChildIterator : public InstanceChildIterator
{
public:
  ConcreteInstanceChildIterator(ConcreteInstanceChildMap *map);
  bool hasNext() override;
  Instance *next() override;

private:
  ConcreteInstanceChildMap *map_;
  ConcreteInstanceChildMap::const_iterator iter_;
};

ConcreteInstanceChildIterator::
ConcreteInstanceChildIterator(ConcreteInstanceChildMap *map) :
  map_(map)
{
  if (map_)
    iter_ = map_->begin();
}

bool
ConcreteInstanceChildIterator::hasNext()
{
  return map_ && iter_ != map_->end();
}

Instance *
ConcreteInstanceChildIterator::next()
{
  Instance *next = reinterpret_cast<Instance*>(iter_->second);
  iter_++;
  return next;
}

class ConcreteInstanceNetIterator : public InstanceNetIterator
{
public:
  ConcreteInstanceNetIterator(ConcreteInstanceNetMap *nets);
  bool hasNext() override;
  Net *next() override;

private:
  void findNext();

  ConcreteInstanceNetMap *nets_;
  ConcreteInstanceNetMap::iterator iter_;
  ConcreteNet *next_{nullptr};
};

ConcreteInstanceNetIterator::
ConcreteInstanceNetIterator(ConcreteInstanceNetMap *nets):
  nets_(nets)
{
  if (nets) {
    iter_ = nets->begin();
    findNext();
  }
}

bool
ConcreteInstanceNetIterator::hasNext()
{
  return nets_ && next_ != nullptr;
}

// Skip nets that have been merged.
void
ConcreteInstanceNetIterator::findNext()
{
  while (iter_ != nets_->end()) {
    next_ = iter_->second;
    iter_++;
    if (next_->mergedInto() == nullptr)
      return;
  }
  next_ = nullptr;
}

Net *
ConcreteInstanceNetIterator::next()
{
  ConcreteNet *next = next_;
  findNext();
  return reinterpret_cast<Net*>(next);
}

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

class ConcreteInstancePinIterator : public InstancePinIterator
{
public:
  ConcreteInstancePinIterator(const ConcreteInstance *inst,
                              int pin_count);
  bool hasNext() override;
  Pin *next() override;

private:
  void findNext();

  const ConcretePinSeq &pins_;
  int pin_count_;
  int pin_index_{0};
  ConcretePin *next_;
};

ConcreteInstancePinIterator::
ConcreteInstancePinIterator(const ConcreteInstance *inst,
                            int pin_count) :
  pins_(inst->pins_),
  pin_count_(pin_count)
{
  findNext();
}

bool
ConcreteInstancePinIterator::hasNext()
{
  return next_ != nullptr;
}

Pin *
ConcreteInstancePinIterator::next()
{
  ConcretePin *next = next_;
  findNext();
  return reinterpret_cast<Pin*>(next);
}

// Skip over missing pins.
void
ConcreteInstancePinIterator::findNext()
{
  while (pin_index_ < pin_count_) {
    next_ = pins_[pin_index_++];
    if (next_)
      return;
  }
  next_ = nullptr;
}

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

class ConcreteNetPinIterator : public NetPinIterator
{
public:
  ConcreteNetPinIterator(const ConcreteNet *net);
  bool hasNext() override;
  Pin *next() override;

private:
  ConcretePin *next_;
};

ConcreteNetPinIterator::ConcreteNetPinIterator(const ConcreteNet *net) :
  next_(net->pins_)
{
}

bool
ConcreteNetPinIterator::hasNext()
{
  return next_ != nullptr;
}

Pin *
ConcreteNetPinIterator::next()
{
  ConcretePin *next = next_;
  next_ = next_->net_next_;
  return reinterpret_cast<Pin*>(next);
}

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

class ConcreteNetTermIterator : public NetTermIterator
{
public:
  ConcreteNetTermIterator(const ConcreteNet *net);
  bool hasNext() override;
  Term *next() override;

private:
  ConcreteTerm *next_;
};

ConcreteNetTermIterator::ConcreteNetTermIterator(const ConcreteNet *net) :
  next_(net->terms_)
{
}

bool
ConcreteNetTermIterator::hasNext()
{
  return next_ != nullptr;
}

Term *
ConcreteNetTermIterator::next()
{
  ConcreteTerm *next = next_;
  next_ = next_->net_next_;
  return reinterpret_cast<Term*>(next);
}

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

ObjectId ConcreteNetwork::object_id_ = 0;

ConcreteNetwork::ConcreteNetwork() :
  NetworkReader(),
  link_func_(nullptr)
{
}

ConcreteNetwork::~ConcreteNetwork()
{
  // Cannot call virtual functions in destructor.
  clearImpl();
}

void
ConcreteNetwork::clearImpl()
{
  if (top_instance_)
    deleteInstanceImpl(top_instance_);
  top_instance_ = nullptr;
  deleteCellNetworkViewsImpl();
  deleteContents(library_seq_);
  library_map_.clear();
}

void
ConcreteNetwork::clear()
{
  clearImpl();
  Network::clear();
}

void
ConcreteNetwork::deleteTopInstance()
{
  if (top_instance_) {
    deleteInstance(top_instance_);
    top_instance_ = nullptr;
  }
}

void
ConcreteNetwork::deleteCellNetworkViews()
{
  deleteCellNetworkViewsImpl();
}

void
ConcreteNetwork::deleteCellNetworkViewsImpl()
{
  for (auto [cell, view] : cell_network_view_map_) {
    if (view)
      deleteInstance(view);
  }
  cell_network_view_map_.clear();
}

Instance *
ConcreteNetwork::topInstance() const
{
  return top_instance_;
}

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

class ConcreteLibraryIterator1 : public Iterator<Library*>
{
public:
  ConcreteLibraryIterator1(const ConcreteLibrarySeq &libs);
  bool hasNext() override;
  Library *next() override;

private:
  const ConcreteLibrarySeq &libs_;
  ConcreteLibrarySeq::const_iterator iter_;
};

ConcreteLibraryIterator1::ConcreteLibraryIterator1(const ConcreteLibrarySeq &libs):
  libs_(libs),
  iter_(libs.begin())
{
}

bool
ConcreteLibraryIterator1::hasNext()
{
  return iter_ != libs_.end();
}

Library *
ConcreteLibraryIterator1::next()
{
  return reinterpret_cast<Library*>(*iter_++);
}

LibraryIterator *
ConcreteNetwork::libraryIterator() const
{
  return new ConcreteLibraryIterator1(library_seq_);
}

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

class ConcreteLibertyLibraryIterator : public Iterator<LibertyLibrary*>
{
public:
  ConcreteLibertyLibraryIterator(const ConcreteNetwork *network);
  bool hasNext() override;
  LibertyLibrary *next() override;

private:
  void findNext();

  const ConcreteLibrarySeq &libs_;
  ConcreteLibrarySeq::const_iterator iter_;
  LibertyLibrary *next_{nullptr};
};

ConcreteLibertyLibraryIterator::
ConcreteLibertyLibraryIterator(const ConcreteNetwork *network):
  libs_(network->library_seq_),
  iter_(libs_.begin())
{
  findNext();
}

bool
ConcreteLibertyLibraryIterator::hasNext()
{
  return next_ != nullptr;
}

LibertyLibrary *
ConcreteLibertyLibraryIterator::next()
{
  LibertyLibrary *next = next_;
  findNext();
  return next;
}

void
ConcreteLibertyLibraryIterator::findNext()
{
  next_ = nullptr;
  while (iter_ != libs_.end()) {
    ConcreteLibrary *lib = *iter_++;
    if (lib->isLiberty()) {
      LibertyLibrary *liberty = static_cast<LibertyLibrary*>(lib);
      if (liberty) {
        next_ = liberty;
        break;
      }
    }
  }
}

LibertyLibraryIterator *
ConcreteNetwork::libertyLibraryIterator() const
{
  return new ConcreteLibertyLibraryIterator(this);
}

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

Library *
ConcreteNetwork::makeLibrary(std::string_view name,
                             std::string_view filename)
{
  ConcreteLibrary *library = new ConcreteLibrary(std::string(name),
                                                 std::string(filename), false);
  addLibrary(library);
  return reinterpret_cast<Library*>(library);
}

LibertyLibrary *
ConcreteNetwork::makeLibertyLibrary(std::string_view name,
                                    std::string_view filename)
{
  LibertyLibrary *library = new LibertyLibrary(std::string(name),
                                               std::string(filename));
  addLibrary(library);
  return library;
}

void
ConcreteNetwork::addLibrary(ConcreteLibrary *library)
{
  library_seq_.push_back(library);
  library_map_[library->name()] = library;
}

Library *
ConcreteNetwork::findLibrary(std::string_view name)
{
  return reinterpret_cast<Library*>(findStringKey(library_map_, name));
}

void
ConcreteNetwork::deleteLibrary(Library *library)
{
  ConcreteLibrary *clib = reinterpret_cast<ConcreteLibrary*>(library);
  library_map_.erase(clib->name());
  library_seq_.erase(std::ranges::find(library_seq_, clib));
  delete clib;
}

std::string
ConcreteNetwork::name(const Library *library) const
{
  const ConcreteLibrary *clib =
    reinterpret_cast<const ConcreteLibrary*>(library);
  return clib->name();
}

ObjectId
ConcreteNetwork::id(const Library *library) const
{
  const ConcreteLibrary *clib =
    reinterpret_cast<const ConcreteLibrary*>(library);
  return clib->id();
}

LibertyLibrary *
ConcreteNetwork::findLiberty(std::string_view name)
{
  ConcreteLibrary *lib = findStringKey(library_map_, name);
  if (lib) {
    if (lib->isLiberty())
      return static_cast<LibertyLibrary*>(lib);
    // Potential name conflict
    else {
      for (ConcreteLibrary *lib : library_seq_) {
        if (lib->name() == name
            && lib->isLiberty())
          return static_cast<LibertyLibrary*>(lib);
      }
    }
  }
  return nullptr;
}

Cell *
ConcreteNetwork::makeCell(Library *library,
                          std::string_view name,
                          bool is_leaf,
                          std::string_view filename)
{
  ConcreteLibrary *clib = reinterpret_cast<ConcreteLibrary*>(library);
  return reinterpret_cast<Cell*>(clib->makeCell(name, is_leaf, filename));
}

Cell *
ConcreteNetwork::findCell(const Library *library,
                          std::string_view name) const
{
  const ConcreteLibrary *clib =
    reinterpret_cast<const ConcreteLibrary*>(library);
  return reinterpret_cast<Cell*>(clib->findCell(name));
}

Cell *
ConcreteNetwork::findAnyCell(std::string_view name)
{
  for (ConcreteLibrary *lib : library_seq_) {
    ConcreteCell *cell = lib->findCell(name);
    if (cell)
      return reinterpret_cast<Cell*>(cell);
  }
  return nullptr;
}

CellSeq
ConcreteNetwork::findCellsMatching(const Library *library,
                                   const PatternMatch *pattern) const
{
  const ConcreteLibrary *clib =
    reinterpret_cast<const ConcreteLibrary*>(library);
  return clib->findCellsMatching(pattern);
}

void
ConcreteNetwork::deleteCell(Cell *cell)
{
  ConcreteCell *ccell = reinterpret_cast<ConcreteCell*>(cell);
  ConcreteLibrary *clib = ccell->library();
  clib->deleteCell(ccell);
}

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

std::string
ConcreteNetwork::name(const Cell *cell) const
{
  const ConcreteCell *ccell = reinterpret_cast<const ConcreteCell*>(cell);
  return ccell->name();
}

ObjectId
ConcreteNetwork::id(const Cell *cell) const
{
  const ConcreteCell *ccell = reinterpret_cast<const ConcreteCell*>(cell);
  return ccell->id();
}

void
ConcreteNetwork::setName(Cell *cell,
                         std::string_view name)
{
  ConcreteCell *ccell = reinterpret_cast<ConcreteCell*>(cell);
  ccell->setName(name);
}

void
ConcreteNetwork::setIsLeaf(Cell *cell,
                           bool is_leaf)
{
  ConcreteCell *ccell = reinterpret_cast<ConcreteCell*>(cell);
  ccell->setIsLeaf(is_leaf);
}

void
ConcreteNetwork::setAttribute(Cell *cell,
                              std::string_view key,
                              std::string_view value)
{
  ConcreteCell *ccell = reinterpret_cast<ConcreteCell*>(cell);
  ccell->setAttribute(key, value);
}

Library *
ConcreteNetwork::library(const Cell *cell) const
{
  const ConcreteCell *ccell = reinterpret_cast<const ConcreteCell*>(cell);
  return reinterpret_cast<Library*>(ccell->library());
}

LibertyCell *
ConcreteNetwork::libertyCell(Cell *cell) const
{
  ConcreteCell *ccell = reinterpret_cast<ConcreteCell*>(cell);
  return ccell->libertyCell();
}

const LibertyCell *
ConcreteNetwork::libertyCell(const Cell *cell) const
{
  const ConcreteCell *ccell = reinterpret_cast<const ConcreteCell*>(cell);
  return ccell->libertyCell();
}

Cell *
ConcreteNetwork::cell(LibertyCell *cell) const
{
  return reinterpret_cast<Cell*>(cell);
}

const Cell *
ConcreteNetwork::cell(const LibertyCell *cell) const
{
  return reinterpret_cast<const Cell*>(cell);
}

std::string_view
ConcreteNetwork::filename(const Cell *cell) const
{
  const ConcreteCell *ccell = reinterpret_cast<const ConcreteCell*>(cell);
  return ccell->filename();
}

std::string
ConcreteNetwork::getAttribute(const Cell *cell,
                              std::string_view key) const
{
  const ConcreteCell *ccell = reinterpret_cast<const ConcreteCell*>(cell);
  return ccell->getAttribute(key);
}

const AttributeMap &
ConcreteNetwork::attributeMap(const Cell *cell) const
{
  const ConcreteCell *ccell = reinterpret_cast<const ConcreteCell*>(cell);
  return ccell->attributeMap();
}

Port *
ConcreteNetwork::findPort(const Cell *cell,
                          std::string_view name) const
{
  const ConcreteCell *ccell = reinterpret_cast<const ConcreteCell*>(cell);
  return reinterpret_cast<Port*>(ccell->findPort(name));
}

bool
ConcreteNetwork::isLeaf(const Cell *cell) const
{
  const ConcreteCell *ccell = reinterpret_cast<const ConcreteCell*>(cell);
  return ccell->isLeaf();
}

Port *
ConcreteNetwork::makePort(Cell *cell,
                          std::string_view name)
{
  ConcreteCell *ccell = reinterpret_cast<ConcreteCell*>(cell);
  ConcretePort *port = ccell->makePort(name);
  return reinterpret_cast<Port*>(port);
}

Port *
ConcreteNetwork::makeBusPort(Cell *cell,
                             std::string_view name,
                             int from_index,
                             int to_index)
{
  ConcreteCell *ccell = reinterpret_cast<ConcreteCell*>(cell);
  ConcretePort *port = ccell->makeBusPort(name, from_index, to_index);
  return reinterpret_cast<Port*>(port);
}

void
ConcreteNetwork::groupBusPorts(Cell *cell,
                               std::function<bool(std::string_view)> port_msb_first)
{
  Library *lib = library(cell);
  ConcreteLibrary *clib = reinterpret_cast<ConcreteLibrary*>(lib);
  ConcreteCell *ccell = reinterpret_cast<ConcreteCell*>(cell);
  ccell->groupBusPorts(clib->busBrktLeft(), clib->busBrktRight(),
                       port_msb_first);
}

Port *
ConcreteNetwork::makeBundlePort(Cell *cell,
                                std::string_view name,
                                PortSeq *members)
{
  ConcreteCell *ccell = reinterpret_cast<ConcreteCell*>(cell);
  ConcretePortSeq *cmembers = reinterpret_cast<ConcretePortSeq*>(members);
  ConcretePort *port = ccell->makeBundlePort(name, cmembers);
  return reinterpret_cast<Port*>(port);
}

void
ConcreteNetwork::setDirection(Port *port,
                              PortDirection *dir)
{
  ConcretePort *cport = reinterpret_cast<ConcretePort*>(port);
  cport->setDirection(dir);
}

ObjectId
ConcreteNetwork::nextObjectId()
{
  return object_id_++;
}

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

class ConcreteCellPortIterator1 : public CellPortIterator
{
public:
  ConcreteCellPortIterator1(const ConcreteCell *cell);
  ~ConcreteCellPortIterator1() override;
  bool hasNext() override { return iter_->hasNext(); }
  Port *next() override;

private:
  ConcreteCellPortIterator *iter_;
};

ConcreteCellPortIterator1::ConcreteCellPortIterator1(const ConcreteCell *cell):
  iter_(cell->portIterator())
{
}

ConcreteCellPortIterator1::~ConcreteCellPortIterator1()
{
  delete iter_;
}

Port *
ConcreteCellPortIterator1::next()
{
  return reinterpret_cast<Port*>(iter_->next());
}

CellPortIterator *
ConcreteNetwork::portIterator(const Cell *cell) const
{
  const ConcreteCell *ccell = reinterpret_cast<const ConcreteCell*>(cell);
  return new ConcreteCellPortIterator1(ccell);
}

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

class ConcreteCellPortBitIterator1 : public CellPortIterator
{
public:
  ConcreteCellPortBitIterator1(const ConcreteCell *cell);
  ~ConcreteCellPortBitIterator1() override;
  bool hasNext() override { return iter_->hasNext(); }
  Port *next() override;

private:
  ConcreteCellPortBitIterator *iter_;
};

ConcreteCellPortBitIterator1::ConcreteCellPortBitIterator1(const ConcreteCell *cell):
  iter_(cell->portBitIterator())
{
}

ConcreteCellPortBitIterator1::~ConcreteCellPortBitIterator1()
{
  delete iter_;
}

Port *
ConcreteCellPortBitIterator1::next()
{
  return reinterpret_cast<Port*>(iter_->next());
}

CellPortBitIterator *
ConcreteNetwork::portBitIterator(const Cell *cell) const
{
  const ConcreteCell *ccell = reinterpret_cast<const ConcreteCell*>(cell);
  return new ConcreteCellPortBitIterator1(ccell);
}

int
ConcreteNetwork::portBitCount(const Cell *cell) const
{
  const ConcreteCell *ccell = reinterpret_cast<const ConcreteCell*>(cell);
  return ccell->portBitCount();
}

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

std::string
ConcreteNetwork::name(const Port *port) const
{
  const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port);
  return cport->name();
}

ObjectId
ConcreteNetwork::id(const Port *port) const
{
  const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port);
  return cport->id();
}

Cell *
ConcreteNetwork::cell(const Port *port) const
{
  const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port);
  return cport->cell();
}

LibertyPort *
ConcreteNetwork::libertyPort(const Port *port) const
{
  const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port);
  return cport->libertyPort();
}

PortDirection *
ConcreteNetwork::direction(const Port *port) const
{
  const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port);
  return cport->direction();
}

bool
ConcreteNetwork::isBundle(const Port *port) const
{
  const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port);
  return cport->isBundle();
}

bool
ConcreteNetwork::isBus(const Port *port) const
{
  const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port);
  return cport->isBus();
}

std::string
ConcreteNetwork::busName(const Port *port) const
{
  const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port);
  return cport->busName();
}

int
ConcreteNetwork::size(const Port *port) const
{
  const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port);
  return cport->size();
}

int
ConcreteNetwork::fromIndex(const Port *port) const
{
  const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port);
  return cport->fromIndex();
}

int
ConcreteNetwork::toIndex(const Port *port) const
{
  const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port);
  return cport->toIndex();
}

Port *
ConcreteNetwork::findBusBit(const Port *port,
                            int index) const
{
  const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port);
  return reinterpret_cast<Port*>(cport->findBusBit(index));
}

Port *
ConcreteNetwork::findMember(const Port *port,
                            int index) const
{
  const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port);
  return reinterpret_cast<Port*>(cport->findMember(index));
}

bool
ConcreteNetwork::hasMembers(const Port *port) const
{
  const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port);
  return cport->hasMembers();
}

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

// This has to skip over missing bus bits in the members.
class ConcretePortMemberIterator1 : public PortMemberIterator
{
public:
  ConcretePortMemberIterator1(const ConcretePort *port);
  ~ConcretePortMemberIterator1() override;
  bool hasNext() override;
  Port *next() override;

private:
  ConcretePortMemberIterator *iter_;
  ConcretePort *next_{nullptr};
};

ConcretePortMemberIterator1::ConcretePortMemberIterator1(const ConcretePort *
                                                         port) :
  iter_(port->memberIterator())
{
}

ConcretePortMemberIterator1::~ConcretePortMemberIterator1()
{
  delete iter_;
}

bool
ConcretePortMemberIterator1::hasNext()
{
  while (next_ == nullptr
         && iter_->hasNext())
    next_ = iter_->next();
  return next_ != nullptr;
}

Port *
ConcretePortMemberIterator1::next()
{
  ConcretePort *next = next_;
  next_ = nullptr;
  return reinterpret_cast<Port*>(next);
}

PortMemberIterator *
ConcreteNetwork::memberIterator(const Port *port) const
{
  const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port);
  return new ConcretePortMemberIterator1(cport);
}

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

std::string
ConcreteNetwork::name(const Instance *instance) const
{
  const ConcreteInstance *inst =
    reinterpret_cast<const ConcreteInstance*>(instance);
  return std::string(inst->name());
}

ObjectId
ConcreteNetwork::id(const Instance *instance) const
{
  const ConcreteInstance *inst =
    reinterpret_cast<const ConcreteInstance*>(instance);
  return inst->id();
}

std::string
ConcreteNetwork::getAttribute(const Instance *inst,
                              std::string_view key) const
{
  const ConcreteInstance *cinst = reinterpret_cast<const ConcreteInstance*>(inst);
  return cinst->getAttribute(key);
}

const AttributeMap &
ConcreteNetwork::attributeMap(const Instance *inst) const
{
  const ConcreteInstance *cinst = reinterpret_cast<const ConcreteInstance*>(inst);
  return cinst->attributeMap();
}

Cell *
ConcreteNetwork::cell(const Instance *instance) const
{
  const ConcreteInstance *inst =
    reinterpret_cast<const ConcreteInstance*>(instance);
  return inst->cell();
}

Instance *
ConcreteNetwork::parent(const Instance *instance) const
{
  const ConcreteInstance *inst =
    reinterpret_cast<const ConcreteInstance*>(instance);
  return reinterpret_cast<Instance*>(inst->parent());
}

bool
ConcreteNetwork::isLeaf(const Instance *instance) const
{
  const ConcreteInstance *inst =
    reinterpret_cast<const ConcreteInstance*>(instance);
  ConcreteCell *ccell = reinterpret_cast<ConcreteCell*>(inst->cell());
  return ccell->isLeaf();
}

Instance *
ConcreteNetwork::findChild(const Instance *parent,
                           std::string_view name) const
{
  const ConcreteInstance *inst =
    reinterpret_cast<const ConcreteInstance*>(parent);
  return inst->findChild(name);
}

Pin *
ConcreteNetwork::findPin(const Instance *instance,
                         std::string_view port_name) const
{
  const ConcreteInstance *inst =
    reinterpret_cast<const ConcreteInstance*>(instance);
  return reinterpret_cast<Pin*>(inst->findPin(port_name));
}

Pin *
ConcreteNetwork::findPin(const Instance *instance,
                         const Port *port) const
{
  const ConcreteInstance *inst =
    reinterpret_cast<const ConcreteInstance*>(instance);
  return reinterpret_cast<Pin*>(inst->findPin(port));
}

Net *
ConcreteNetwork::findNet(const Instance *instance,
                         std::string_view net_name) const
{
  const ConcreteInstance *inst =
    reinterpret_cast<const ConcreteInstance*>(instance);
  return reinterpret_cast<Net*>(inst->findNet(net_name));
}

void
ConcreteNetwork::findInstNetsMatching(const Instance *instance,
                                      const PatternMatch *pattern,
                                      NetSeq &matches) const
{
  const ConcreteInstance *inst =
    reinterpret_cast<const ConcreteInstance*>(instance);
  inst->findNetsMatching(pattern, matches);
}

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

InstanceChildIterator *
ConcreteNetwork::childIterator(const Instance *instance) const
{
  const ConcreteInstance *inst =
    reinterpret_cast<const ConcreteInstance*>(instance);
  return inst->childIterator();
}

InstancePinIterator *
ConcreteNetwork::pinIterator(const Instance *instance) const
{
  const ConcreteInstance *inst =
    reinterpret_cast<const ConcreteInstance*>(instance);
  ConcreteCell *cell = reinterpret_cast<ConcreteCell*>(inst->cell());
  int pin_count = cell->portBitCount();
  return new ConcreteInstancePinIterator(inst, pin_count);
}

InstanceNetIterator *
ConcreteNetwork::netIterator(const Instance *instance) const
{
  const ConcreteInstance *inst =
    reinterpret_cast<const ConcreteInstance*>(instance);
  return inst->netIterator();
}

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

ObjectId
ConcreteNetwork::id(const Pin *pin) const
{
  const ConcretePin *cpin = reinterpret_cast<const ConcretePin*>(pin);
  return cpin->id();
}

Instance *
ConcreteNetwork::instance(const Pin *pin) const
{
  const ConcretePin *cpin = reinterpret_cast<const ConcretePin*>(pin);
  return reinterpret_cast<Instance*>(cpin->instance());
}

Net *
ConcreteNetwork::net(const Pin *pin) const
{
  const ConcretePin *cpin = reinterpret_cast<const ConcretePin*>(pin);
  return reinterpret_cast<Net*>(cpin->net());
}

Term *
ConcreteNetwork::term(const Pin *pin) const
{
  const ConcretePin *cpin = reinterpret_cast<const ConcretePin*>(pin);
  return reinterpret_cast<Term*>(cpin->term());
}

Port *
ConcreteNetwork::port(const Pin *pin) const
{
  const ConcretePin *cpin = reinterpret_cast<const ConcretePin*>(pin);
  return reinterpret_cast<Port*>(cpin->port());
}

PortDirection *
ConcreteNetwork::direction(const Pin *pin) const
{
  const ConcretePin *cpin = reinterpret_cast<const ConcretePin*>(pin);
  const ConcretePort *cport = cpin->port();
  return cport->direction();
}

VertexId
ConcreteNetwork::vertexId(const Pin *pin) const
{
  const ConcretePin *cpin = reinterpret_cast<const ConcretePin*>(pin);
  return cpin->vertexId();
}

void
ConcreteNetwork::setVertexId(Pin *pin,
                             VertexId id)
{
  ConcretePin *cpin = reinterpret_cast<ConcretePin*>(pin);
  cpin->setVertexId(id);
}

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

ObjectId
ConcreteNetwork::id(const Term *term) const
{
  const ConcreteTerm *cterm = reinterpret_cast<const ConcreteTerm*>(term);
  return cterm->id();
}

Net *
ConcreteNetwork::net(const Term *term) const
{
  const ConcreteTerm *cterm = reinterpret_cast<const ConcreteTerm*>(term);
  return reinterpret_cast<Net*>(cterm->net());
}

Pin *
ConcreteNetwork::pin(const Term *term) const
{
  const ConcreteTerm *cterm = reinterpret_cast<const ConcreteTerm*>(term);
  return reinterpret_cast<Pin*>(cterm->pin());
}

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

std::string
ConcreteNetwork::name(const Net *net) const
{
  const ConcreteNet *cnet = reinterpret_cast<const ConcreteNet*>(net);
  return std::string(cnet->name());
}

ObjectId
ConcreteNetwork::id(const Net *net) const
{
  const ConcreteNet *cnet = reinterpret_cast<const ConcreteNet*>(net);
  return cnet->id();
}

Instance *
ConcreteNetwork::instance(const Net *net) const
{
  const ConcreteNet *cnet = reinterpret_cast<const ConcreteNet*>(net);
  return reinterpret_cast<Instance*>(cnet->instance());
}

bool
ConcreteNetwork::isPower(const Net *net) const
{
  return constant_nets_[static_cast<int>(LogicValue::one)].contains(const_cast<Net*>(net));
}

bool
ConcreteNetwork::isGround(const Net *net) const
{
  return constant_nets_[static_cast<int>(LogicValue::zero)].contains(const_cast<Net*>(net));
}

NetPinIterator *
ConcreteNetwork::pinIterator(const Net *net) const
{
  const ConcreteNet *cnet = reinterpret_cast<const ConcreteNet*>(net);
  return new ConcreteNetPinIterator(cnet);
}

NetTermIterator *
ConcreteNetwork::termIterator(const Net *net) const
{
  const ConcreteNet *cnet = reinterpret_cast<const ConcreteNet*>(net);
  return new ConcreteNetTermIterator(cnet);
}

void
ConcreteNetwork::mergeInto(Net *net,
                           Net *into_net)
{
  ConcreteNet *cnet = reinterpret_cast<ConcreteNet*>(net);
  ConcreteNet *cinto_net = reinterpret_cast<ConcreteNet*>(into_net);
  cnet->mergeInto(cinto_net);
  clearNetDrvrPinMap();
}

Net *
ConcreteNetwork::mergedInto(Net *net)
{
  ConcreteNet *cnet = reinterpret_cast<ConcreteNet*>(net);
  return reinterpret_cast<Net*>(cnet->mergedInto());
}

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

Cell *
ConcreteInstance::cell() const
{
  return reinterpret_cast<Cell*>(cell_);
}

Instance *
ConcreteNetwork::makeInstance(Cell *cell,
                              std::string_view name,
                              Instance *parent)
{
  ConcreteCell *ccell = reinterpret_cast<ConcreteCell*>(cell);
  return makeConcreteInstance(ccell, name, parent);
}

Instance *
ConcreteNetwork::makeInstance(LibertyCell *cell,
                              std::string_view name,
                              Instance *parent)
{
  return makeConcreteInstance(cell, name, parent);
}

Instance *
ConcreteNetwork::makeConcreteInstance(ConcreteCell *cell,
                                      std::string_view name,
                                      Instance *parent)
{
  ConcreteInstance *cparent =
    reinterpret_cast<ConcreteInstance*>(parent);
  ConcreteInstance *inst = new ConcreteInstance(name, cell, cparent);
  if (parent)
    cparent->addChild(inst);
  return reinterpret_cast<Instance*>(inst);
}

void
ConcreteNetwork::makePins(Instance *inst)
{
  CellPortBitIterator *port_iterator = portBitIterator(cell(inst));
  while (port_iterator->hasNext()) {
    Port *port = port_iterator->next();
    makePin(inst, port, nullptr);
  }
  delete port_iterator;
}

void
ConcreteNetwork::replaceCell(Instance *inst,
                             Cell *cell)
{
  ConcreteCell *ccell = reinterpret_cast<ConcreteCell*>(cell);
  int port_count = ccell->portBitCount();
  ConcreteInstance *cinst = reinterpret_cast<ConcreteInstance*>(inst);
  ConcretePinSeq &pins = cinst->pins_;
  ConcretePinSeq rpins(port_count);
  for (int i = 0; i < port_count; i++)
    rpins[i] = nullptr;
  for (int i = 0; i < port_count; i++) {
    ConcretePin *cpin = pins[i];
    if (cpin) {
      ConcretePort *pin_cport = reinterpret_cast<ConcretePort*>(cpin->port());
      ConcretePort *cport = ccell->findPort(pin_cport->name());
      if (cport) {
        rpins[cport->pinIndex()] = cpin;
        cpin->port_ = cport;
      }
    }
  }
  cinst->pins_ = rpins;
  cinst->setCell(ccell);
}

void
ConcreteNetwork::deleteInstance(Instance *inst)
{
  deleteInstanceImpl(inst);
}

void
ConcreteNetwork::deleteInstanceImpl(Instance *inst)
{
  ConcreteInstance *cinst = reinterpret_cast<ConcreteInstance*>(inst);
  ConcreteInstanceNetMap *nets = cinst->nets_;
  if (nets) {
    // Delete nets first (so children pin deletes are not required).
    for (auto itr = nets->begin(); itr != nets->end(); /*no incr*/) {
      auto [name, cnet] = *itr;
      Net *net = reinterpret_cast<Net*>(cnet);
      // Delete terminals connected to net.
      NetTermIterator *term_iter = termIterator(net);
      while (term_iter->hasNext()) {
        ConcreteTerm *term = reinterpret_cast<ConcreteTerm*>(term_iter->next());
        delete term;
      }
      delete term_iter;
      itr = nets->erase(itr);
      deleteNet(net);
    }
  }

  // Delete children.
  InstanceChildIterator *child_iter = childIterator(inst);
  while (child_iter->hasNext()) {
    Instance *child = child_iter->next();
    deleteInstance(child);
  }
  delete child_iter;

  InstancePinIterator *pin_iter = pinIterator(inst);
  while (pin_iter->hasNext()) {
    Pin *pin = pin_iter->next();
    deletePin(pin);
  }
  delete pin_iter;

  Instance *parent_inst = parent(inst);
  if (parent_inst) {
    ConcreteInstance *cparent =
      reinterpret_cast<ConcreteInstance*>(parent_inst);
    cparent->deleteChild(cinst);
  }
  delete cinst;
}

Pin *
ConcreteNetwork::makePin(Instance *inst,
                         Port *port,
                         Net *net)
{
  ConcreteInstance *cinst = reinterpret_cast<ConcreteInstance*>(inst);
  ConcretePort *cport = reinterpret_cast<ConcretePort*>(port);
  ConcreteNet *cnet = reinterpret_cast<ConcreteNet*>(net);
  ConcretePin *cpin = new ConcretePin(cinst, cport, cnet);
  cinst->addPin(cpin);
  if (cnet)
    connectNetPin(cnet, cpin);
  return reinterpret_cast<Pin*>(cpin);
}

Term *
ConcreteNetwork::makeTerm(Pin *pin,
                          Net *net)
{
  ConcretePin *cpin = reinterpret_cast<ConcretePin*>(pin);
  ConcreteNet *cnet = reinterpret_cast<ConcreteNet*>(net);
  ConcreteTerm *cterm = new ConcreteTerm(cpin, cnet);
  if (cnet)
    cnet->addTerm(cterm);
  cpin->term_ = cterm;
  return reinterpret_cast<Term*>(cterm);
}

Pin *
ConcreteNetwork::connect(Instance *inst,
                         LibertyPort *port,
                         Net *net)
{
  return connect(inst, reinterpret_cast<Port*>(port), net);
}

void
ConcreteNetwork::setAttribute(Instance *inst,
                              std::string_view key,
                              std::string_view value)
{
  ConcreteInstance *cinst = reinterpret_cast<ConcreteInstance*>(inst);
  cinst->setAttribute(key, value);
}

Pin *
ConcreteNetwork::connect(Instance *inst,
                         Port *port,
                         Net *net)
{
  ConcreteNet *cnet = reinterpret_cast<ConcreteNet*>(net);
  ConcreteInstance *cinst = reinterpret_cast<ConcreteInstance*>(inst);
  ConcretePort *cport = reinterpret_cast<ConcretePort*>(port);
  ConcretePin *cpin = cinst->findPin(port);
  if (cpin) {
    ConcreteNet *prev_net = cpin->net_;
    if (prev_net)
      disconnectNetPin(prev_net, cpin);
  }
  else {
    cpin = new ConcretePin(cinst, cport, cnet);
    cinst->addPin(cpin);
  }
  if (inst == top_instance_) {
    // makeTerm
    ConcreteTerm *cterm = new ConcreteTerm(cpin, cnet);
    if (cnet)
      cnet->addTerm(cterm);
    cpin->term_ = cterm;
    cpin->net_ = nullptr;
  }
  else {
    cpin->net_ = cnet;
    connectNetPin(cnet, cpin);
  }
  return reinterpret_cast<Pin*>(cpin);
}

void
ConcreteNetwork::connectNetPin(ConcreteNet *cnet,
                               ConcretePin *cpin)
{
  cnet->addPin(cpin);

  // If there are no terminals the net does not span hierarchy levels
  // and it is safe to incrementally update the drivers.
  Pin *pin = reinterpret_cast<Pin*>(cpin);
  if (isDriver(pin)) {
    if (cnet->terms_ == nullptr) {
      Net *net = reinterpret_cast<Net*>(cnet);
      PinSet *drvrs = findKey(net_drvr_pin_map_, net);
      if (drvrs)
        drvrs->insert(pin);
    }
    else
      clearNetDrvrPinMap();
  }
}

void
ConcreteNetwork::disconnectPin(Pin *pin)
{
  ConcretePin *cpin = reinterpret_cast<ConcretePin*>(pin);
  if (reinterpret_cast<Instance*>(cpin->instance()) == top_instance_) {
    ConcreteTerm *cterm = cpin->term_;
    if (cterm) {
      ConcreteNet *cnet = cterm->net_;
      if (cnet) {
        cnet->deleteTerm(cterm);
        clearNetDrvrPinMap();
      }
      cpin->term_ = nullptr;
      delete cterm;
    }
  }
  else {
    ConcreteNet *cnet = cpin->net();
    if (cnet)
      disconnectNetPin(cnet, cpin);
    cpin->net_ = nullptr;
  }
}

void
ConcreteNetwork::disconnectNetPin(ConcreteNet *cnet,
                                  ConcretePin *cpin)
{
  cnet->deletePin(cpin);

  Pin *pin = reinterpret_cast<Pin*>(cpin);
  if (isDriver(pin)) {
    ConcreteNet *cnet = cpin->net();
    // If there are no terminals the net does not span hierarchy levels
    // and it is safe to incrementally update the drivers.
    if (cnet->terms_ == nullptr) {
      Net *net = reinterpret_cast<Net*>(cnet);
      PinSet *drvrs = findKey(net_drvr_pin_map_, net);
      if (drvrs)
        drvrs->erase(pin);
    }
    else
      clearNetDrvrPinMap();
  }
}

void
ConcreteNetwork::deletePin(Pin *pin)
{
  ConcretePin *cpin = reinterpret_cast<ConcretePin*>(pin);
  ConcreteNet *cnet = cpin->net();
  if (cnet)
    disconnectNetPin(cnet, cpin);
  ConcreteInstance *cinst = cpin->instance();
  if (cinst)
    cinst->deletePin(cpin);
  delete cpin;
}

Net *
ConcreteNetwork::makeNet(std::string_view name,
                         Instance *parent)
{
  ConcreteInstance *cparent = reinterpret_cast<ConcreteInstance*>(parent);
  ConcreteNet *net = new ConcreteNet(name, cparent);
  cparent->addNet(net);
  return reinterpret_cast<Net*>(net);
}

void
ConcreteNetwork::deleteNet(Net *net)
{
  ConcreteNet *cnet = reinterpret_cast<ConcreteNet*>(net);
  ConcreteNetPinIterator pin_iter(cnet);
  while (pin_iter.hasNext()) {
    ConcretePin *pin = reinterpret_cast<ConcretePin*>(pin_iter.next());
    // Do NOT use net->disconnectPin because it would be N^2
    // to delete all of the pins from the net.
    pin->net_ = nullptr;
  }

  constant_nets_[static_cast<int>(LogicValue::zero)].erase(net);
  constant_nets_[static_cast<int>(LogicValue::one)].erase(net);
  PinSet *drvrs = findKey(net_drvr_pin_map_, net);
  if (drvrs) {
    delete drvrs;
    net_drvr_pin_map_.erase(net);
  }

  ConcreteInstance *cinst = cnet->instance();
  cinst->deleteNet(cnet);
  delete cnet;
}

void
ConcreteNetwork::clearConstantNets()
{
  constant_nets_[static_cast<int>(LogicValue::zero)].clear();
  constant_nets_[static_cast<int>(LogicValue::one)].clear();
}

void
ConcreteNetwork::addConstantNet(Net *net,
                                LogicValue value)
{
  if (value == LogicValue::zero
      || value == LogicValue::one)
    constant_nets_[static_cast<int>(value)].insert(net);
}

ConstantPinIterator *
ConcreteNetwork::constantPinIterator()
{
  return new NetworkConstantPinIterator(this,
                                        constant_nets_[static_cast<int>(LogicValue::zero)],
                                        constant_nets_[static_cast<int>(LogicValue::one)]);
}

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

// Optimized version of Network::visitConnectedPins.
void
ConcreteNetwork::visitConnectedPins(const Net *net,
                                    PinVisitor &visitor,
                                    NetSet &visited_nets) const
{
  if (!visited_nets.contains(net)) {
    visited_nets.insert(net);
    // Search up from net terminals.
    const ConcreteNet *cnet = reinterpret_cast<const ConcreteNet*>(net);
    for (ConcreteTerm *term = cnet->terms_; term; term = term->net_next_) {
      ConcretePin *above_pin = term->pin_;
      if (above_pin) {
        ConcreteNet *above_net = above_pin->net_;
        if (above_net)
          visitConnectedPins(reinterpret_cast<Net*>(above_net),
                             visitor, visited_nets);
        else
          visitor(reinterpret_cast<Pin*>(above_pin));
      }
    }

    // Search down from net pins.
    for (ConcretePin *pin = cnet->pins_; pin; pin = pin->net_next_) {
      visitor(reinterpret_cast<Pin*>(pin));
      ConcreteTerm *below_term = pin->term_;
      if (below_term) {
        ConcreteNet *below_net = below_term->net_;
        if (below_net)
          visitConnectedPins(reinterpret_cast<Net*>(below_net),
                             visitor, visited_nets);
      }
    }
  }
}

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

ConcreteInstance::ConcreteInstance(std::string_view name,
                                   ConcreteCell *cell,
                                   ConcreteInstance *parent) :
  name_(name),
  id_(ConcreteNetwork::nextObjectId()),
  cell_(cell),
  parent_(parent)
{
  initPins();
}

void
ConcreteInstance::initPins()
{
  ConcreteCell *ccell = reinterpret_cast<ConcreteCell*>(cell_);
  pins_.resize(ccell->portBitCount());
}

ConcreteInstance::~ConcreteInstance()
{
  delete children_;
  delete nets_;
}

Instance *
ConcreteInstance::findChild(std::string_view name) const
{
  if (children_)
    return reinterpret_cast<Instance*>(findStringKey(*children_, name));
  else
    return nullptr;
}

ConcretePin *
ConcreteInstance::findPin(std::string_view port_name) const
{
  ConcreteCell *ccell = reinterpret_cast<ConcreteCell*>(cell_);
  const ConcretePort *cport =
    reinterpret_cast<const ConcretePort*>(ccell->findPort(port_name));
  if (cport
      && !cport->isBus())
    return pins_[cport->pinIndex()];
  else
    return nullptr;
}

ConcretePin *
ConcreteInstance::findPin(const Port *port) const
{
  const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port);
  size_t port_index = cport->pinIndex();
  if (port_index < pins_.size())
    return pins_[port_index];
  else
    return nullptr;
}

ConcreteNet *
ConcreteInstance::findNet(std::string_view net_name) const
{
  ConcreteNet *net = nullptr;
  if (nets_) {
    net = findStringKey(*nets_, net_name);
    // Follow merge pointer to surviving net.
    if (net) {
      while (net->mergedInto())
        net = net->mergedInto();
    }
  }
  return net;
}

void
ConcreteInstance::findNetsMatching(const PatternMatch *pattern,
                                   NetSeq &matches) const
{
  if (nets_) {
    if (pattern->hasWildcards()) {
      for (auto [net_name, cnet] : *nets_) {
        if (pattern->match(net_name))
          matches.push_back(reinterpret_cast<Net*>(cnet));
      }
    }
    else {
      ConcreteNet *cnet = findNet(pattern->pattern());
      if (cnet)
        matches.push_back(reinterpret_cast<Net*>(cnet));
    }
  }
}

InstanceNetIterator *
ConcreteInstance::netIterator() const
{
  return reinterpret_cast<InstanceNetIterator*>
    (new ConcreteInstanceNetIterator(nets_));
}

InstanceChildIterator *
ConcreteInstance::childIterator() const
{
  return new ConcreteInstanceChildIterator(children_);
}

void
ConcreteInstance::setAttribute(std::string_view key,
                               std::string_view value)
{
  attribute_map_[std::string(key)] = value;
}

std::string
ConcreteInstance::getAttribute(std::string_view key) const
{
  const auto &itr = attribute_map_.find(key);
  if (itr != attribute_map_.end())
    return itr->second;
  return "";
}

void
ConcreteInstance::addChild(ConcreteInstance *child)
{
  if (children_ == nullptr)
    children_ = new ConcreteInstanceChildMap;
  (*children_)[child->name()] = child;
}

void
ConcreteInstance::deleteChild(ConcreteInstance *child)
{
  children_->erase(child->name());
}

void
ConcreteInstance::addPin(ConcretePin *pin)
{
  ConcretePort *cport = reinterpret_cast<ConcretePort *>(pin->port());
  size_t pin_index = cport->pinIndex();
  if (pin_index >= pins_.size())
    pins_.resize(pin_index + 1);
  pins_[pin_index] = pin;
}

void
ConcreteInstance::deletePin(ConcretePin *pin)
{
  ConcretePort *cport = reinterpret_cast<ConcretePort *>(pin->port());
  pins_[cport->pinIndex()] = nullptr;
}

void
ConcreteInstance::addNet(ConcreteNet *net)
{
  if (nets_ == nullptr)
    nets_ = new ConcreteInstanceNetMap;
  (*nets_)[net->name()] = net;
}

void
ConcreteInstance::addNet(std::string_view,
                         ConcreteNet *net)
{
  if (nets_ == nullptr)
    nets_ = new ConcreteInstanceNetMap;
  (*nets_)[net->name()] = net;
}

void
ConcreteInstance::deleteNet(ConcreteNet *net)
{
  nets_->erase(net->name());
}

void
ConcreteInstance::setCell(ConcreteCell *cell)
{
  cell_ = cell;
}

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

ConcretePin::ConcretePin(ConcreteInstance *instance,
                         ConcretePort *port,
                         ConcreteNet *net) :
  instance_(instance),
  port_(port),
  net_(net),
  id_(ConcreteNetwork::nextObjectId())
{
}

const std::string&
ConcretePin::name() const
{
  return port_->name();
}

void
ConcretePin::setVertexId(VertexId id)
{
  vertex_id_ = id;
}

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

const std::string &
ConcreteTerm::name() const
{
  ConcretePin *cpin = reinterpret_cast<ConcretePin*>(pin_);
  const ConcretePort *cport = cpin->port();
  return cport->name();
}

ConcreteTerm::ConcreteTerm(ConcretePin *pin,
                           ConcreteNet *net) :
  pin_(pin),
  net_(net),
  id_(ConcreteNetwork::nextObjectId())
{
}

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

ConcreteNet::ConcreteNet(std::string_view name,
                         ConcreteInstance *instance) :
  name_(name),
  id_(ConcreteNetwork::nextObjectId()),
  instance_(instance)
{
}

// Merged nets are kept around to serve as name aliases.
// Only Instance::findNet and InstanceNetIterator need to know
// the net has been merged.
void
ConcreteNet::mergeInto(ConcreteNet *net)
{
  ConcreteNetPinIterator pin_iter(this);
  while (pin_iter.hasNext()) {
    Pin *pin = pin_iter.next();
    ConcretePin *cpin = reinterpret_cast<ConcretePin*>(pin);
    net->addPin(cpin);
    cpin->net_ = net;
  }
  pins_ = nullptr;
  ConcreteNetTermIterator term_iter(this);
  while (term_iter.hasNext()) {
    Term *term = term_iter.next();
    ConcreteTerm *cterm = reinterpret_cast<ConcreteTerm*>(term);
    net->addTerm(cterm);
    cterm->net_ = net;
  }
  terms_ = nullptr;
  // Leave name map pointing to merged net because otherwise a top
  // level merged net has no pointer to it and it is leaked.
  merged_into_ = net;
}

void
ConcreteNet::addPin(ConcretePin *pin)
{
  if (pins_)
    pins_->net_prev_ = pin;
  pin->net_next_ = pins_;
  pin->net_prev_ = nullptr;
  pins_ = pin;
}

void
ConcreteNet::deletePin(ConcretePin *pin)
{
  ConcretePin *prev = pin->net_prev_;
  ConcretePin *next = pin->net_next_;
  if (prev)
    prev->net_next_ = next;
  if (next)
    next->net_prev_ = prev;
  if (pins_ == pin)
    pins_ = next;
}

void
ConcreteNet::addTerm(ConcreteTerm *term)
{
  ConcreteTerm *next = terms_;
  terms_ = term;
  term->net_next_ = next;
}

void
ConcreteNet::deleteTerm(ConcreteTerm *term)
{
  ConcreteTerm *net_prev_term = nullptr;
  for (ConcreteTerm *net_term=terms_;net_term;net_term=net_term->net_next_) {
    if (net_term == term) {
      if (net_prev_term)
        net_prev_term->net_next_ = term->net_next_;
      else
        terms_ = term->net_next_;
      break;
    }
    net_prev_term = net_term;
  }
}

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

using BindingMap = std::map<Net*, Net*> ;

// Binding table used for linking/expanding network.
class ConcreteBindingTbl
{
public:
  ConcreteBindingTbl(NetworkEdit *network);
  Net *ensureBinding(Net *proto_net,
                     Instance *parent);
  Net *find(Net *net);
  void bind(Net *proto_net,
            Net *clone_net);

private:
  BindingMap map_;
  NetworkEdit *network_;
};

void
ConcreteNetwork::setCellNetworkView(Cell *cell,
                                    Instance *inst)
{
  cell_network_view_map_[cell] = inst;
}

Instance *
ConcreteNetwork::cellNetworkView(Cell *cell)
{
  return findKey(cell_network_view_map_, cell);
}

void
ConcreteNetwork::readNetlistBefore()
{
  clearConstantNets();
  deleteTopInstance();
  clearNetDrvrPinMap();
}

void
ConcreteNetwork::setTopInstance(Instance *top_inst)
{
  if (top_instance_) {
    deleteInstance(top_instance_);
    clearConstantNets();
    clearNetDrvrPinMap();
  }
  top_instance_ = top_inst;
}

void
ConcreteNetwork::setLinkFunc(LinkNetworkFunc link)
{
  link_func_ = link;
}

bool
ConcreteNetwork::linkNetwork(std::string_view top_cell_name,
                             bool make_black_boxes,
                             Report *report)
{
  if (link_func_) {
    clearConstantNets();
    deleteTopInstance();
    top_instance_ = link_func_(top_cell_name,
                               make_black_boxes);
    if (top_instance_)
      checkNetworkLibertyScenes();
    return top_instance_ != nullptr;
  }
  else {
    report->error(1000, "cell type {} can not be linked.", top_cell_name);
    return false;
  }
}

Instance *
linkReaderNetwork(Cell *top_cell,
                  bool, Report *,
                  NetworkReader *network)
{
  Instance *view = network->cellNetworkView(top_cell);
  if (view) {
    // Seed the recursion for expansion with the top level instance.
    Instance *top_instance = network->makeInstance(top_cell, "", nullptr);
    ConcreteBindingTbl bindings(network);
    makeClonePins(view, top_instance, view, &bindings, nullptr, nullptr, network);
    InstanceChildIterator *child_iter = network->childIterator(view);
    while (child_iter->hasNext()) {
      Instance *child = child_iter->next();
      makeChildNetwork(child, top_instance, &bindings, network);
    }
    delete child_iter;
    network->deleteCellNetworkViews();
    return top_instance;
  }
  return nullptr;
}

static void
makeChildNetwork(Instance *proto,
                 Instance *parent,
                 ConcreteBindingTbl *parent_bindings,
                 NetworkReader *network)
{
  Cell *proto_cell = network->cell(proto);
  Instance *clone = network->makeInstance(proto_cell, network->name(proto),
                                          parent);
  if (network->isLeaf(proto_cell))
    makeClonePins(proto, clone, nullptr, nullptr, parent, parent_bindings, network);
  else {
    // Recurse if this isn't a leaf cell.
    ConcreteBindingTbl bindings(network);
    Instance *clone_view = network->cellNetworkView(proto_cell);
    makeClonePins(proto, clone, clone_view, &bindings, parent,
                  parent_bindings, network);
    if (clone_view) {
      InstanceChildIterator *child_iter = network->childIterator(clone_view);
      while (child_iter->hasNext()) {
        Instance *child = child_iter->next();
        makeChildNetwork(child, clone, &bindings, network);
      }
      delete child_iter;
    }
  }
}

static void
makeClonePins(Instance *proto,
              Instance *clone,
              Instance *clone_view,
              ConcreteBindingTbl *bindings,
              Instance *parent,
              ConcreteBindingTbl *parent_bindings,
              NetworkReader *network)
{
  InstancePinIterator *proto_pin_iter = network->pinIterator(proto);
  while (proto_pin_iter->hasNext()) {
    Pin *proto_pin = proto_pin_iter->next();
    Net *proto_net = network->net(proto_pin);
    Port *proto_port = network->port(proto_pin);
    Net *clone_net = nullptr;
    if (proto_net && parent_bindings)
      clone_net = parent_bindings->ensureBinding(proto_net, parent);
    Pin *clone_pin = network->connect(clone, proto_port, clone_net);
    if (clone_view) {
      Pin *clone_proto_pin = network->findPin(clone_view, proto_port);
      Net *clone_proto_net = network->net(clone_proto_pin);
      Net *clone_child_net = nullptr;
      if (clone_proto_net)
        clone_child_net = bindings->ensureBinding(clone_proto_net, clone);
      network->makeTerm(clone_pin, clone_child_net);
    }
  }
  delete proto_pin_iter;
}

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

ConcreteBindingTbl::ConcreteBindingTbl(NetworkEdit *network) :
  network_(network)
{
}

// Follow the merged_into pointers rather than update the
// binding tables up the call tree when nodes are merged
// because the name changes up the hierarchy.
Net *
ConcreteBindingTbl::find(Net *proto_net)
{
  ConcreteNet *net = reinterpret_cast<ConcreteNet*>(findKey(map_, proto_net));
  while (net && net->mergedInto())
    net = net->mergedInto();
  return reinterpret_cast<Net*>(net);
}

void
ConcreteBindingTbl::bind(Net *proto_net,
                         Net *net)
{
  map_[proto_net] = net;
}

Net *
ConcreteBindingTbl::ensureBinding(Net *proto_net,
                                  Instance *parent)
{
  Net *net = find(proto_net);
  if (net == nullptr) {
    net = network_->makeNet(network_->name(proto_net), parent);
    map_[proto_net] = net;
  }
  return net;
}

} // namespace sta
