-- Copyright 1994 Grady Booch
-- Copyright 1998-2002 Simon Wright <simon@pushface.org>
-- This package is free software; you can redistribute it and/or
-- modify it under terms of the GNU General Public License as
-- published by the Free Software Foundation; either version 2, or
-- (at your option) any later version. This package 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 distributed with this package; see file COPYING. If not,
-- write to the Free Software Foundation, 59 Temple Place - Suite
-- 330, Boston, MA 02111-1307, USA.
-- As a special exception, if other files instantiate generics from
-- this unit, or you link this unit with other files to produce an
-- executable, this unit does not by itself cause the resulting
-- executable to be covered by the GNU General Public License. This
-- exception does not however invalidate any other reasons why the
-- executable file might be covered by the GNU Public License.
-- $RCSfile: bc-graphs-undirected.adb,v $
-- $Revision: 1.9.2.1 $
-- $Date: 2002/12/29 16:42:26 $
-- $Author: simon $
with BC.Support.Exceptions;
with System.Address_To_Access_Conversions;
package body BC.Graphs.Undirected is
package BSE renames BC.Support.Exceptions;
procedure Assert
is new BSE.Assert ("BC.Graphs.Undirected");
----------------------
-- Graph operations --
----------------------
procedure Create_Arc (G : in out Graph;
A : in out Arc'Class;
I : Arc_Item;
First : in out Vertex'Class;
Second : in out Vertex'Class) is
begin
Clear (A);
A.Rep := new Arc_Node'(Ada.Finalization.Controlled with
Item => I,
Enclosing => G'Unchecked_Access,
From => First.Rep,
To => Second.Rep,
Next_Incoming => null,
Next_Outgoing => null,
Count => 1);
if Second.Rep /= null then
A.Rep.Next_Incoming := Second.Rep.Incoming;
Second.Rep.Incoming := A.Rep;
A.Rep.Count := A.Rep.Count + 1;
Second.Rep.Count := Second.Rep.Count + 1;
end if;
if First.Rep /= null then
A.Rep.Next_Outgoing := First.Rep.Outgoing;
First.Rep.Outgoing := A.Rep;
A.Rep.Count := A.Rep.Count + 1;
First.Rep.Count := First.Rep.Count + 1;
end if;
end Create_Arc;
-----------------------
-- Vertex operations --
-----------------------
function Arity (V : Vertex) return Natural is
Count : Natural := 0;
Curr : Arc_Node_Ptr;
begin
Assert (V.Rep /= null,
BC.Is_Null'Identity,
"Arity",
BSE.Is_Null);
Curr := V.Rep.Incoming;
while Curr /= null loop
Count := Count + 1;
Curr := Curr.Next_Incoming;
end loop;
Curr := V.Rep.Outgoing;
while Curr /= null loop
if Curr.From /= Curr.To then
Count := Count + 1;
end if;
Curr := Curr.Next_Outgoing;
end loop;
return Count;
end Arity;
--------------------
-- Arc operations --
--------------------
procedure Set_First_Vertex (A : in out Arc;
V : access Vertex'Class) is
Prev, Curr : Arc_Node_Ptr;
begin
Assert (A.Rep /= null,
BC.Is_Null'Identity,
"Set_First_Vertex",
BSE.Is_Null);
if A.Rep.From /= null then
Prev := null;
Curr := A.Rep.From.Outgoing;
while Curr /= A.Rep loop
Prev := Curr;
Curr := Curr.Next_Outgoing;
end loop;
if Prev = null then
A.Rep.From.Outgoing := Curr.Next_Outgoing;
else
Prev.Next_Outgoing := Curr.Next_Outgoing;
end if;
A.Rep.From.Count := A.Rep.From.Count - 1;
A.Rep.Count := A.Rep.Count - 1;
end if;
if V.Rep /= null then
A.Rep.Next_Outgoing := V.Rep.Outgoing;
V.Rep.Outgoing := A.Rep;
A.Rep.Count := A.Rep.Count + 1;
V.Rep.Count := V.Rep.Count + 1;
end if;
A.Rep.From := V.Rep;
end Set_First_Vertex;
procedure Set_Second_Vertex (A : in out Arc;
V : access Vertex'Class) is
Prev, Curr : Arc_Node_Ptr;
begin
Assert (A.Rep /= null,
BC.Is_Null'Identity,
"Set_From_Vertex",
BSE.Is_Null);
if A.Rep.To /= null then
Prev := null;
Curr := A.Rep.To.Incoming;
while Curr /= A.Rep loop
Prev := Curr;
Curr := Curr.Next_Incoming;
end loop;
if Prev = null then
A.Rep.To.Incoming := Curr.Next_Incoming;
else
Prev.Next_Incoming := Curr.Next_Incoming;
end if;
A.Rep.To.Count := A.Rep.To.Count - 1;
A.Rep.Count := A.Rep.Count - 1;
end if;
if V.Rep /= null then
A.Rep.Next_Incoming := V.Rep.Incoming;
V.Rep.Incoming := A.Rep;
A.Rep.Count := A.Rep.Count + 1;
V.Rep.Count := V.Rep.Count + 1;
end if;
A.Rep.To := V.Rep;
end Set_Second_Vertex;
procedure First_Vertex (A : Arc;
V : in out Vertex'Class) is
begin
Assert (A.Rep /= null,
BC.Is_Null'Identity,
"First_Vertex",
BSE.Is_Null);
Clear (V);
V.Rep := A.Rep.From;
if V.Rep /= null then
V.Rep.Count := V.Rep.Count + 1;
end if;
end First_Vertex;
procedure Second_Vertex (A : Arc;
V : in out Vertex'Class) is
begin
Assert (A.Rep /= null,
BC.Is_Null'Identity,
"Second_Vertex",
BSE.Is_Null);
Clear (V);
V.Rep := A.Rep.To;
if V.Rep /= null then
V.Rep.Count := V.Rep.Count + 1;
end if;
end Second_Vertex;
---------------------
-- Graph iterators --
---------------------
package Graph_Address_Conversions
is new System.Address_To_Access_Conversions (Graph);
function New_Graph_Iterator
(For_The_Graph : Graph) return Graph_Iterator'Class is
Result : Undirected_Graph_Iterator
:= (For_The_Graph => Graph_Address_Conversions.To_Pointer
(For_The_Graph'Address).all'Access,
Index => For_The_Graph.Rep);
begin
return Result;
end New_Graph_Iterator;
package Vertex_Address_Conversions
is new System.Address_To_Access_Conversions (Vertex);
function New_Vertex_Iterator
(For_The_Vertex : Vertex) return Vertex_Iterator'Class is
Result : Undirected_Vertex_Iterator;
begin
Result.For_The_Vertex :=
Vertex_Address_Conversions.To_Pointer
(For_The_Vertex'Address).all'Access;
Reset (Result);
return Result;
end New_Vertex_Iterator;
-------------------------------
-- Private iteration support --
-------------------------------
procedure Reset (It : in out Undirected_Graph_Iterator) is
begin
It.Index := It.For_The_Graph.Rep;
end Reset;
procedure Next (It : in out Undirected_Graph_Iterator) is
begin
if It.Index /= null then
It.Index := It.Index.Next;
end if;
end Next;
function Is_Done (It : Undirected_Graph_Iterator) return Boolean is
begin
return It.Index = null;
end Is_Done;
function Current_Vertex
(It : Undirected_Graph_Iterator) return Abstract_Vertex'Class is
begin
Assert (It.Index /= null,
BC.Is_Null'Identity,
"Current_Vertex(Graph_Iterator)",
BSE.Is_Null);
It.Index.Count := It.Index.Count + 1;
return Vertex'
(Ada.Finalization.Controlled with Rep => It.Index);
end Current_Vertex;
----------------------
-- Vertex iterators --
----------------------
procedure Reset (It : in out Undirected_Vertex_Iterator) is
begin
It.Do_Outgoing := True;
if It.For_The_Vertex.Rep /= null then
It.Index := It.For_The_Vertex.Rep.Outgoing;
if It.Index = null then
It.Do_Outgoing := False;
It.Index := It.For_The_Vertex.Rep.Incoming;
-- skip self-directed arcs, already seen in outgoing side
-- XXX hmm, wouldn't .Outgoing have been non-null?
while It.Index /= null and then It.Index.From = It.Index.To loop
pragma Assert (False);
It.Index := It.Index.Next_Incoming;
end loop;
end if;
else
It.Index := null;
end if;
end Reset;
procedure Next (It : in out Undirected_Vertex_Iterator) is
begin
-- XXX I think we ought to check here that there is an Index!
if It.Do_Outgoing then
It.Index := It.Index.Next_Outgoing;
if It.Index = null then
It.Do_Outgoing := False;
It.Index := It.For_The_Vertex.Rep.Incoming;
-- skip self-directed arcs, already seen in outgoing side
while It.Index /= null and then It.Index.From = It.Index.To loop
It.Index := It.Index.Next_Incoming;
end loop;
end if;
elsif It.Index /= null then
It.Index := It.Index.Next_Incoming;
-- skip self-directed arcs, already seen in outgoing side
while It.Index /= null and then It.Index.From = It.Index.To loop
It.Index := It.Index.Next_Incoming;
end loop;
end if;
end Next;
function Is_Done (It : Undirected_Vertex_Iterator) return Boolean is
begin
return It.Index = null;
end Is_Done;
function Current_Arc (It : Undirected_Vertex_Iterator)
return Abstract_Arc'Class is
begin
Assert (It.Index /= null,
BC.Is_Null'Identity,
"Current_Arc(Arc_Iterator)",
BSE.Is_Null);
It.Index.Count := It.Index.Count + 1;
return Arc'(Ada.Finalization.Controlled with Rep => It.Index);
end Current_Arc;
end BC.Graphs.Undirected;
syntax highlighted by Code2HTML, v. 0.9.1