|
Packit |
bd2e5d |
(***********************************************************************)
|
|
Packit |
bd2e5d |
(* *)
|
|
Packit |
bd2e5d |
(* MLTk, Tcl/Tk interface of OCaml *)
|
|
Packit |
bd2e5d |
(* *)
|
|
Packit |
bd2e5d |
(* Francois Rouaix, Francois Pessaux, Jun Furuse and Pierre Weis *)
|
|
Packit |
bd2e5d |
(* projet Cristal, INRIA Rocquencourt *)
|
|
Packit |
bd2e5d |
(* Jacques Garrigue, Kyoto University RIMS *)
|
|
Packit |
bd2e5d |
(* *)
|
|
Packit |
bd2e5d |
(* Copyright 2002 Institut National de Recherche en Informatique et *)
|
|
Packit |
bd2e5d |
(* en Automatique and Kyoto University. All rights reserved. *)
|
|
Packit |
bd2e5d |
(* This file is distributed under the terms of the GNU Library *)
|
|
Packit |
bd2e5d |
(* General Public License, with the special exception on linking *)
|
|
Packit |
bd2e5d |
(* described in file LICENSE found in the OCaml source tree. *)
|
|
Packit |
bd2e5d |
(* *)
|
|
Packit |
bd2e5d |
(***********************************************************************)
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* $Id$ *)
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
open StdLabels
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* Topological Sort.list *)
|
|
Packit |
bd2e5d |
(* d'apres More Programming Pearls *)
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* node * pred count * successors *)
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
type 'a entry =
|
|
Packit |
bd2e5d |
{node : 'a;
|
|
Packit |
bd2e5d |
mutable pred_count : int;
|
|
Packit |
bd2e5d |
mutable successors : 'a entry list
|
|
Packit |
bd2e5d |
}
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
type 'a porder = 'a entry list ref
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
exception Cyclic
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let find_entry order node =
|
|
Packit |
bd2e5d |
let rec search_entry =
|
|
Packit |
bd2e5d |
function
|
|
Packit |
bd2e5d |
[] -> raise Not_found
|
|
Packit |
bd2e5d |
| x::l -> if x.node = node then x else search_entry l
|
|
Packit |
bd2e5d |
in
|
|
Packit |
bd2e5d |
try
|
|
Packit |
bd2e5d |
search_entry !order
|
|
Packit |
bd2e5d |
with
|
|
Packit |
bd2e5d |
Not_found -> let entry = {node = node;
|
|
Packit |
bd2e5d |
pred_count = 0;
|
|
Packit |
bd2e5d |
successors = []} in
|
|
Packit |
bd2e5d |
order := entry::!order;
|
|
Packit |
bd2e5d |
entry
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let create () = ref []
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* Inverted args because Sort.list builds list in reverse order *)
|
|
Packit |
bd2e5d |
let add_relation order (succ,pred) =
|
|
Packit |
bd2e5d |
let pred_entry = find_entry order pred
|
|
Packit |
bd2e5d |
and succ_entry = find_entry order succ in
|
|
Packit |
bd2e5d |
succ_entry.pred_count <- succ_entry.pred_count + 1;
|
|
Packit |
bd2e5d |
pred_entry.successors <- succ_entry::pred_entry.successors
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
(* Just add it *)
|
|
Packit |
bd2e5d |
let add_element order e =
|
|
Packit |
bd2e5d |
ignore (find_entry order e)
|
|
Packit |
bd2e5d |
|
|
Packit |
bd2e5d |
let sort order =
|
|
Packit |
bd2e5d |
let q = Queue.create ()
|
|
Packit |
bd2e5d |
and result = ref [] in
|
|
Packit |
bd2e5d |
List.iter !order
|
|
Packit |
bd2e5d |
~f:(function {pred_count = n} as node ->
|
|
Packit |
bd2e5d |
if n = 0 then Queue.add node q);
|
|
Packit |
bd2e5d |
begin try
|
|
Packit |
bd2e5d |
while true do
|
|
Packit |
bd2e5d |
let t = Queue.take q in
|
|
Packit |
bd2e5d |
result := t.node :: !result;
|
|
Packit |
bd2e5d |
List.iter t.successors ~f:
|
|
Packit |
bd2e5d |
begin fun s ->
|
|
Packit |
bd2e5d |
let n = s.pred_count - 1 in
|
|
Packit |
bd2e5d |
s.pred_count <- n;
|
|
Packit |
bd2e5d |
if n = 0 then Queue.add s q
|
|
Packit |
bd2e5d |
end
|
|
Packit |
bd2e5d |
done
|
|
Packit |
bd2e5d |
with
|
|
Packit |
bd2e5d |
Queue.Empty ->
|
|
Packit |
bd2e5d |
List.iter !order
|
|
Packit |
bd2e5d |
~f:(fun node -> if node.pred_count <> 0
|
|
Packit |
bd2e5d |
then raise Cyclic)
|
|
Packit |
bd2e5d |
end;
|
|
Packit |
bd2e5d |
!result
|