diff options
Diffstat (limited to 'stdlib')
-rw-r--r-- | stdlib/.depend | 8 | ||||
-rw-r--r-- | stdlib/Makefile | 2 | ||||
-rw-r--r-- | stdlib/array.ml | 137 | ||||
-rw-r--r-- | stdlib/array.mli | 26 | ||||
-rw-r--r-- | stdlib/list.ml | 27 | ||||
-rw-r--r-- | stdlib/list.mli | 21 | ||||
-rw-r--r-- | stdlib/sort.mli | 5 |
7 files changed, 208 insertions, 18 deletions
diff --git a/stdlib/.depend b/stdlib/.depend index 88fb5e880..d1a4d2d80 100644 --- a/stdlib/.depend +++ b/stdlib/.depend @@ -4,8 +4,8 @@ parsing.cmi: lexing.cmi obj.cmi printf.cmi: buffer.cmi arg.cmo: array.cmi list.cmi printf.cmi string.cmi sys.cmi arg.cmi arg.cmx: array.cmx list.cmx printf.cmx string.cmx sys.cmx arg.cmi -array.cmo: list.cmi array.cmi -array.cmx: list.cmx array.cmi +array.cmo: array.cmi pervasives.cmi array.cmi +array.cmx: array.cmx pervasives.cmx array.cmi buffer.cmo: string.cmi sys.cmi buffer.cmi buffer.cmx: string.cmx sys.cmx buffer.cmi callback.cmo: obj.cmi callback.cmi @@ -32,8 +32,8 @@ lazy.cmo: lazy.cmi lazy.cmx: lazy.cmi lexing.cmo: string.cmi lexing.cmi lexing.cmx: string.cmx lexing.cmi -list.cmo: list.cmi -list.cmx: list.cmi +list.cmo: array.cmi list.cmi +list.cmx: array.cmx list.cmi map.cmo: map.cmi map.cmx: map.cmi marshal.cmo: string.cmi marshal.cmi diff --git a/stdlib/Makefile b/stdlib/Makefile index bff51bfa4..83a41085b 100644 --- a/stdlib/Makefile +++ b/stdlib/Makefile @@ -23,7 +23,7 @@ CAMLOPT=$(RUNTIME) $(OPTCOMPILER) OPTCOMPFLAGS= CAMLDEP=../boot/ocamlrun ../tools/ocamldep -OBJS=pervasives.cmo list.cmo char.cmo string.cmo array.cmo sys.cmo \ +OBJS=pervasives.cmo array.cmo list.cmo char.cmo string.cmo sys.cmo \ hashtbl.cmo sort.cmo marshal.cmo obj.cmo \ lexing.cmo parsing.cmo \ set.cmo map.cmo stack.cmo queue.cmo stream.cmo \ diff --git a/stdlib/array.ml b/stdlib/array.ml index e3abd2687..af0195128 100644 --- a/stdlib/array.ml +++ b/stdlib/array.ml @@ -59,17 +59,22 @@ let append a1 a2 = end let concat_aux init al = - let size = List.fold_left (fun sz a -> sz + length a) 0 al in - let res = create size init in - let pos = ref 0 in - List.iter - (fun a -> - for i = 0 to length a - 1 do - unsafe_set res !pos (unsafe_get a i); - incr pos - done) - al; + let rec size accu = function + | [] -> accu + | h::t -> size (accu + length h) t + in + let res = create (size 0 al) init in + let rec fill pos = function + | [] -> () + | h::t -> + for i = 0 to length h - 1 do + unsafe_set res (pos + i) (unsafe_get h i); + done; + fill (pos + length h) t; + in + fill 0 al; res +;; let concat al = let rec find_init = function @@ -138,10 +143,15 @@ let to_list a = if i < 0 then res else tolist (i - 1) (unsafe_get a i :: res) in tolist (length a - 1) [] +let rec list_length accu = function + | [] -> accu + | h::t -> list_length (succ accu) t +;; + let of_list = function [] -> [||] - | hd::tl -> - let a = create (List.length tl + 1) hd in + | hd::tl as l -> + let a = create (list_length 0 l) hd in let rec fill i = function [] -> a | hd::tl -> unsafe_set a i hd; fill (i+1) tl in @@ -160,3 +170,106 @@ let fold_right f a x = r := f (unsafe_get a i) !r done; !r + +exception Bottom of int;; +let sort cmp a = + let maxson l i = + let i31 = i+i+i+1 in + let x = ref i31 in + if i31+2 < l then begin + if cmp a.(i31) a.(i31+1) < 0 then x := i31+1; + if cmp a.(!x) a.(i31+2) < 0 then x := i31+2; + !x + end else + if i31+1 < l && cmp a.(i31) a.(i31+1) < 0 + then i31+1 + else if i31 < l then i31 else raise (Bottom i) + in + let rec trickledown l i e = + let j = maxson l i in + if cmp a.(j) e > 0 then begin + a.(i) <- a.(j); + trickledown l j e; + end else begin + a.(i) <- e; + end; + in + let rec trickle l i e = try trickledown l i e with Bottom i -> a.(i) <- e in + let rec bubbledown l i = + let j = maxson l i in + a.(i) <- a.(j); + bubbledown l j; + in + let bubble l i = try bubbledown l i with Bottom i -> i in + let rec trickleup i e = + let father = (i - 1) / 3 in + assert (i <> father); + if cmp a.(father) e < 0 then begin + a.(i) <- a.(father); + if father > 0 then trickleup father e else a.(0) <- e; + end else begin + a.(i) <- e; + end; + in + let l = length a in + for i = (l + 1) / 3 - 1 downto 0 do trickle l i a.(i); done; + for i = l - 1 downto 2 do + let e = a.(i) in + a.(i) <- a.(0); + trickleup (bubble i 0) e; + done; + if l > 1 then (let e = a.(1) in a.(1) <- a.(0); a.(0) <- e); +;; + +let cutoff = 5;; +let stable_sort cmp a = + let merge src1ofs src1len src2 src2ofs src2len dst dstofs = + let src1r = src1ofs + src1len and src2r = src2ofs + src2len in + let rec loop i1 s1 i2 s2 d = + if cmp s1 s2 <= 0 then begin + dst.(d) <- s1; + let i1 = i1 + 1 in + if i1 < src1r then + loop i1 a.(i1) i2 s2 (d + 1) + else + blit src2 i2 dst (d + 1) (src2r - i2) + end else begin + dst.(d) <- s2; + let i2 = i2 + 1 in + if i2 < src2r then + loop i1 s1 i2 src2.(i2) (d + 1) + else + blit a i1 dst (d + 1) (src1r - i1) + end + in loop src1ofs a.(src1ofs) src2ofs src2.(src2ofs) dstofs; + in + let isortto srcofs dst dstofs len = + for i = 0 to len - 1 do + let e = a.(srcofs + i) in + let j = ref (dstofs + i - 1) in + while (!j >= dstofs && cmp dst.(!j) e > 0) do + dst.(!j + 1) <- dst.(!j); + decr j; + done; + dst.(!j + 1) <- e; + done; + in + let rec sortto srcofs dst dstofs len = + if len <= cutoff then isortto srcofs dst dstofs len else begin + let l1 = len / 2 in + let l2 = len - l1 in + sortto (srcofs + l1) dst (dstofs + l1) l2; + sortto srcofs a (srcofs + l2) l1; + merge (srcofs + l2) l1 dst (dstofs + l1) l2 dst dstofs; + end; + in + let l = length a in + if l <= cutoff then isortto 0 a 0 l else begin + let l1 = l / 2 in + let l2 = l - l1 in + let t = make l2 a.(0) in + sortto l1 t 0 l2; + sortto 0 a l2 l1; + merge l2 l1 t 0 l2 a 0; + end; +;; diff --git a/stdlib/array.mli b/stdlib/array.mli index f45cac336..18ae9db2f 100644 --- a/stdlib/array.mli +++ b/stdlib/array.mli @@ -117,8 +117,32 @@ val fold_right: f:('b -> 'a -> 'a) -> 'b array -> init:'a -> 'a (* [Array.fold_right f a x] computes [f a.(0) (f a.(1) ( ... (f a.(n-1) x) ...))], where [n] is the length of the array [a]. *) + +(** Sorting *) +val sort : cmp:('a -> 'a -> int) -> 'a array -> unit;; + (* Sort an array in increasing order according to a comparison + function. The comparison function must return 0 if it arguments + compare as equal, a positive integer if the first is greater, + and a negative integer if the first is smaller. For example, + the [compare] function is a suitable comparison function. + After calling [Array.sort], the array is sorted in place in + increasing order. + [Array.sort] is guaranteed to run in constant heap space + and logarithmic stack space. + + The current implementation uses Heap Sort. It runs in constant + stack space. + *) + +val stable_sort : cmp:('a -> 'a -> int) -> 'a array -> unit;; + (* Same as [Array.sort], but the sorting algorithm is stable and + not guaranteed to use a fixed amount of heap memory. + The current implementation is Merge Sort. It uses [n/2] + words of heap space, where [n] is the length of the array. + It is faster than the current implementation of [Array.sort]. + *) + (*--*) external unsafe_get: 'a array -> int -> 'a = "%array_unsafe_get" external unsafe_set: 'a array -> int -> 'a -> unit = "%array_unsafe_set" - diff --git a/stdlib/list.ml b/stdlib/list.ml index be2e8a22c..021deb572 100644 --- a/stdlib/list.ml +++ b/stdlib/list.ml @@ -191,3 +191,30 @@ let rec combine l1 l2 = ([], []) -> [] | (a1::l1, a2::l2) -> (a1, a2) :: combine l1 l2 | (_, _) -> invalid_arg "List.combine" + +(** sorting *) + +external obj_truncate : 'a array -> int -> unit = "obj_truncate" + +let array_to_list_in_place a = + let l = Array.length a in + let rec loop accu n p = + if p <= 0 then accu else begin + if p = n then begin + obj_truncate a p; + loop (a.(p-1) :: accu) (n-1000) (p-1) + end else begin + loop (a.(p-1) :: accu) n (p-1) + end + end + in + loop [] l l +;; + +let stable_sort cmp l = + let a = Array.of_list l in + Array.stable_sort cmp a; + array_to_list_in_place a +;; + +let sort = stable_sort;; diff --git a/stdlib/list.mli b/stdlib/list.mli index cb2345353..d76c0b7c3 100644 --- a/stdlib/list.mli +++ b/stdlib/list.mli @@ -188,3 +188,24 @@ val combine : 'a list -> 'b list -> ('a * 'b) list [[(a1,b1); ...; (an,bn)]]. Raise [Invalid_argument] if the two lists have different lengths. Not tail-recursive. *) + +(** Sorting *) +val sort : cmp:('a -> 'a -> int) -> 'a list -> 'a list;; + (* Sort a list in increasing order according to a comparison + function. The comparison function must return 0 if it arguments + compare as equal, a positive integer if the first is greater, + and a negative integer if the first is smaller. For example, + the [compare] function is a suitable comparison function. + The resulting list is sorted in increasing order. + [List.sort] is guaranteed to run in constant heap space + (in addition to the size of the result list) and logarithmic + stack space. + + The current implementation uses Merge Sort and is the same as + [List.stable_sort]. + *) +val stable_sort : cmp:('a -> 'a -> int) -> 'a list -> 'a list;; + (* Same as [List.sort], but the sorting algorithm is stable. + The current implementation is Merge Sort. It runs in constant + heap space. + *) diff --git a/stdlib/sort.mli b/stdlib/sort.mli index 413057090..684fb41d0 100644 --- a/stdlib/sort.mli +++ b/stdlib/sort.mli @@ -14,6 +14,11 @@ (* Module [Sort]: sorting and merging lists *) +(* This module is obsolete and exists only for backward compatibility. + The sorting functions in [Array] and [List] should be used instead. + The new functions are faster and use less memory. +*) + val list : order:('a -> 'a -> bool) -> 'a list -> 'a list (* Sort a list in increasing order according to an ordering predicate. The predicate should return [true] if its first argument is |