Copyright 1993 Digital Equipment Corporation.                             
 Distributed only by permission.                                           
                                                                           
 Last modified on Fri Jul 30 09:03:31 PDT 1993 by heydon                   
MODULE Graph EXPORTS Graph, GraphRep;
IMPORT Fmt;
REVEAL
  T = TRep BRANDED OBJECT OVERRIDES
    nodeName := NodeName
  END;
PROCEDURE NodeName(<*UNUSED*> g: T; id: CARDINAL): TEXT =
  BEGIN RETURN Fmt.Int(id) END NodeName;
REVEAL
  Sparse = SparseRep BRANDED OBJECT OVERRIDES
    init      := Init;
    newNode   := NewNode;
    numNodes  := NumNodes;
    newEdge   := NewEdge;
    neighbors := Neighbors;
  END;
PROCEDURE Init(g: Sparse; sizeHint: CARDINAL := 10): T =
  BEGIN
    g.adj := NEW(REF ARRAY OF NodeList, sizeHint);
    g.nodeCnt := 0;
    RETURN g
  END Init;
PROCEDURE NewNode(g: Sparse): CARDINAL =
  VAR next := g.nodeCnt; BEGIN
    IF next > LAST(g.adj^) THEN
      VAR new := NEW(REF ARRAY OF NodeList, g.nodeCnt * 2); BEGIN
        SUBARRAY(new^, 0, g.nodeCnt) := g.adj^;
        g.adj := new
      END
    END;
    g.adj[next] := NIL;
    INC(g.nodeCnt);
    RETURN next
  END NewNode;
PROCEDURE NumNodes(g: Sparse): CARDINAL =
  BEGIN RETURN g.nodeCnt END NumNodes;
PROCEDURE NewEdge(g: Sparse; id1, id2: CARDINAL; weight: REAL := 1.0) =
  PROCEDURE AddEdge(adj: REF ARRAY OF NodeList; from, to: CARDINAL) =
    VAR new := NEW(NodeList, node := to, weight := weight); BEGIN
      new.next := adj[from];
      adj[from] := new
    END AddEdge;
  BEGIN
    <* ASSERT weight >= 0.0 *>
    AddEdge(g.adj, id1, id2);
    AddEdge(g.adj, id2, id1)
  END NewEdge;
TYPE
  SparseIt = Iterator BRANDED OBJECT
    curr: NodeList
  OVERRIDES
    next := SparseItNext
  END;
PROCEDURE Neighbors(g: Sparse; id: CARDINAL): Iterator =
  BEGIN
    RETURN NEW(SparseIt, curr := g.adj[id])
  END Neighbors;
PROCEDURE SparseItNext(
    it: SparseIt;
    VAR (*OUT*) id: CARDINAL;
    VAR (*OUT*) weight: REAL):
    BOOLEAN =
  BEGIN
    WITH curr = it.curr DO
      IF curr = NIL THEN RETURN FALSE END;
      id := curr.node;
      weight := curr.weight;
      curr := curr.next
    END;
    RETURN TRUE
  END SparseItNext;
BEGIN
END Graph.