C++程序  |  179行  |  4.19 KB

//===- ListDigraph.cpp ----------------------------------------------------===//
//
//                     The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <mcld/ADT/GraphLite/ListDigraph.h>

using namespace mcld::graph;

//===----------------------------------------------------------------------===//
// ListDigraph::Node
//===----------------------------------------------------------------------===//
ListDigraph::Node::Node()
  : prev(NULL), next(NULL), first_in(NULL), first_out(NULL) {
}

//===----------------------------------------------------------------------===//
// ListDigraph::Arc
//===----------------------------------------------------------------------===//
ListDigraph::Arc::Arc()
  : target(NULL), source(NULL),
    prev_in(NULL), next_in(NULL), prev_out(NULL), next_out(NULL) {
}

//===----------------------------------------------------------------------===//
// ListDigraph
//===----------------------------------------------------------------------===//
ListDigraph::ListDigraph()
  : m_pNodeHead(NULL), m_pFreeNodeHead(NULL), m_pFreeArcHead(NULL),
    m_NodeList(32), m_ArcList(32) {
}


ListDigraph::Node* ListDigraph::addNode()
{
  // 1. find an available free node
  Node* result = NULL;
  if (NULL == m_pFreeNodeHead) {
    result = m_NodeList.allocate();
    new (result) Node();
  }
  else {
    result = m_pFreeNodeHead;
    m_pFreeNodeHead = m_pFreeNodeHead->next;
  }

  // 2. set up linkages
  result->prev = NULL;
  result->next = m_pNodeHead;

  // 3. reset head node
  if (NULL != m_pNodeHead) {
    m_pNodeHead->prev = result;
  }
  m_pNodeHead = result;

  return result;
}


ListDigraph::Arc* ListDigraph::addArc(Node& pU, Node& pV)
{
  // 1. find an available free arc
  Arc* result = NULL;
  if (NULL == m_pFreeArcHead) {
    result = m_ArcList.allocate();
    new (result) Arc();
  }
  else {
    result = m_pFreeArcHead;
    m_pFreeArcHead = m_pFreeArcHead->next_in;
  }

  // 2. set up arc
  result->source = &pU;
  result->target = &pV;

  // 3. set up fan-out linked list
  result->next_out = pU.first_out;
  if (NULL != pU.first_out) {
    pU.first_out->prev_out = result;
  }
  pU.first_out = result;

  // 4. set up fan-in linked list
  result->next_in = pV.first_in;
  if (NULL != pV.first_in) {
    pV.first_in->prev_in = result;
  }
  pV.first_in = result;

  return result;
}

void ListDigraph::erase(ListDigraph::Node& pNode)
{
  // 1. connect previous node and next node.
  if (NULL != pNode.next) {
    pNode.next->prev = pNode.prev;
  }

  if (NULL != pNode.prev) {
    pNode.prev->next = pNode.next;
  }
  else { // pNode.prev is NULL => pNode is the head
    m_pNodeHead = pNode.next;
  }

  // 2. remove all fan-in arcs
  Arc* fan_in = pNode.first_in;
  while(NULL != fan_in) {
    Arc* next_in = fan_in->next_in;
    erase(*fan_in);
    fan_in = next_in;
  }

  // 3. remove all fan-out arcs
  Arc* fan_out = pNode.first_out;
  while(NULL != fan_out) {
    Arc* next_out = fan_out->next_out;
    erase(*fan_out);
    fan_out = next_out;
  }

  // 4. put pNode in the free node list
  pNode.next = m_pFreeNodeHead;
  pNode.prev = NULL;
  if (NULL != m_pFreeNodeHead)
    m_pFreeNodeHead->prev = &pNode;
  m_pFreeNodeHead = &pNode;
}


void ListDigraph::erase(ListDigraph::Arc& pArc)
{
  // 1. remove from the fan-out list
  if (NULL != pArc.prev_out) {
    pArc.prev_out->next_out = pArc.next_out;
  }
  else { // pArc.prev_out is NULL => pArc is the first_out of the source
    pArc.source->first_out = pArc.next_out;
  }

  if (NULL != pArc.next_out) {
    pArc.next_out->prev_out = pArc.prev_out;
  }

  // 2. remove from the fan-in list
  if (NULL != pArc.prev_in) {
    pArc.prev_in->next_in = pArc.next_in;
  }
  else {
    pArc.target->first_in = pArc.next_in;
  }

  if (NULL != pArc.next_in) {
    pArc.next_in->prev_in = pArc.prev_in;
  }

  // 3. put pArc in the free arc list
  // Use fan-in links to chain the free list
  pArc.next_in = m_pFreeArcHead;
  m_pFreeArcHead = &pArc;
}


void ListDigraph::clear()
{
  m_pNodeHead = NULL;
  m_pFreeNodeHead = NULL;
  m_pFreeArcHead = NULL;
  m_NodeList.clear();
  m_ArcList.clear();
}