Blame compiler/tsort.ml

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