Skip to content

Commit

Permalink
Merge branch 'mr/pred_update' into 'master'
Browse files Browse the repository at this point in the history
Ensure that update of predecessors are detected during iteration

See merge request eng/toolchain/gnatcoll-core!133
  • Loading branch information
Nikokrock committed Aug 22, 2024
2 parents 26db9d8 + cf457d9 commit 2121d5c
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 3 deletions.
53 changes: 50 additions & 3 deletions core/src/gnatcoll-directed_graph.adb
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ package body GNATCOLL.Directed_Graph is
Node : Node_Id;
Predecessor : Node_Id)
is
Prev_Length : Ada.Containers.Count_Type;
begin
if not Self.Contains (Node) then
raise DG_Error with "Non existing node";
Expand All @@ -115,8 +116,13 @@ package body GNATCOLL.Directed_Graph is
raise DG_Error with "Predecessor cannot be the node itself";
end if;

Prev_Length := Self.Predecessors (Integer (Node)).Length;
Self.Internal_Add_Predecessor (Node, Predecessor);
Self.Is_Cache_Valid := False;

if Self.Predecessors (Integer (Node)).Length > Prev_Length then
Self.Is_Cache_Valid := False;
Self.Update_List.Append (Node);
end if;
end Add_Predecessor;

----------------------
Expand All @@ -128,6 +134,7 @@ package body GNATCOLL.Directed_Graph is
Node : Node_Id;
Predecessors : Node_Set := Empty_Node_Set)
is
Prev_Length : Ada.Containers.Count_Type;
begin
if not Self.Contains (Node) then
raise DG_Error with "Non existing node";
Expand All @@ -141,11 +148,17 @@ package body GNATCOLL.Directed_Graph is
raise DG_Error with "Predecessor cannot be the node itself";
end if;

Prev_Length := Self.Predecessors (Integer (Node)).Length;

for Pred of Predecessors loop
Self.Internal_Add_Predecessor (Node, Pred);
end loop;

Self.Is_Cache_Valid := False;
if Self.Predecessors (Integer (Node)).Length > Prev_Length then
Self.Is_Cache_Valid := False;
Self.Update_List.Append (Node);
end if;

end Add_Predecessors;

--------------------
Expand Down Expand Up @@ -350,13 +363,17 @@ package body GNATCOLL.Directed_Graph is
-- Check if new nodes were added

if Self.Graph_Next_Free_Node < Graph.Next_Free_Node then

for N in Self.Graph_Next_Free_Node .. Graph.Next_Free_Node - 1 loop

-- Add the new node the list of non visited nodes
Self.Non_Visited.Include (N);

declare
Visited_Pred : Integer := 0;
begin
-- Update the number of visited predecessors for the new nodes

-- by checking whether any of the predecessors has been visited
for Pred of Graph.Predecessors (Integer (N)) loop
if not Self.Non_Visited.Contains (Pred) and then
not Self.Visiting.Contains (Pred)
Expand All @@ -365,13 +382,43 @@ package body GNATCOLL.Directed_Graph is
end if;
end loop;

-- Extend the visited predecessor array with the information of
-- the new node
Self.Visited_Predecessors.Append (Visited_Pred);
end;
end loop;

-- Keep track that the new node have been taken into account.
Self.Graph_Next_Free_Node := Graph.Next_Free_Node;
end if;

-- Check if new predecessors were added on existing nodes
if Self.Graph_Update_List_Last < Graph.Update_List.Length then
for Idx in Self.Graph_Update_List_Last + 1 .. Graph.Update_List.Length
loop
declare
N : constant Node_Id := Graph.Update_List (Integer (Idx));
Visited_Pred : Integer := 0;
begin
-- Update the number of visited predecessors for the updated
-- nodes by checking whether any of the predecessors has been
-- visited
for Pred of Graph.Predecessors (Integer (N)) loop
if not Self.Non_Visited.Contains (Pred) and then
not Self.Visiting.Contains (Pred)
then
Visited_Pred := Visited_Pred + 1;
end if;
end loop;

Self.Visited_Predecessors (Integer (N)) := Visited_Pred;
end;
end loop;

-- Update marker
Self.Graph_Update_List_Last := Graph.Update_List.Length;
end if;

-- If all nodes have been visited it means that we have reached the
-- end of the iteration.

Expand Down
7 changes: 7 additions & 0 deletions core/src/gnatcoll-directed_graph.ads
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,9 @@ private
-- Used to detect addition of new nodes in the Graph linked to the
-- iterator.

Graph_Update_List_Last : Ada.Containers.Count_Type := 0;
-- Used to detect addition of predecessors in existing nodes

Enable_Visiting_State : Boolean := False;
-- Indicate if there is an intermediate state "Visiting" between the
-- "Non_Visited" and "Visited" ones.
Expand Down Expand Up @@ -299,6 +302,10 @@ private

Iterator : DAG_Iterator;
-- Internal iterator

Update_List : Node_Vectors.Vector;
-- Keep track of add_predecessor operations. Needed in order to track
-- changes during iterations.
end record;

end GNATCOLL.Directed_Graph;
17 changes: 17 additions & 0 deletions testsuite/tests/directed_graph/test.adb
Original file line number Diff line number Diff line change
Expand Up @@ -423,5 +423,22 @@ begin

A.Assert (G.Shortest_Path (N3, N1) = Empty_Node_Vector);

declare
Node : Node_Id;
begin
G.Clear;
N1 := G.Add_Node;
N2 := G.Add_Node (Predecessors => (1 => N1));
N3 := G.Add_Node (Predecessors => (1 => N2));

G.Start_Iterator (True);
A.Assert (G.Next (Node) and then Node = N1);
G.Complete_Visit (N1);
G.Add_Predecessor (N3, N1);
A.Assert (G.Next (Node) and then Node = N2);
G.Complete_Visit (N2);
A.Assert (G.Next (Node) and then Node = N3);
end;

return A.Report;
end Test;

0 comments on commit 2121d5c

Please sign in to comment.