1 (***********************************************************************)
5 (* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
7 (* Copyright 1996 Institut National de Recherche en Informatique et *)
8 (* en Automatique. All rights reserved. This file is distributed *)
9 (* under the terms of the GNU Library General Public License, with *)
10 (* the special exception on linking described in file ../LICENSE. *)
12 (***********************************************************************)
14 (* $Id: array.ml 6834 2005-04-11 16:44:26Z doligez $ *)
16 (* Array operations *)
18 external length : 'a array -> int = "%array_length"
19 external get: 'a array -> int -> 'a = "%array_safe_get"
20 external set: 'a array -> int -> 'a -> unit = "%array_safe_set"
21 external unsafe_get: 'a array -> int -> 'a = "%array_unsafe_get"
22 external unsafe_set: 'a array -> int -> 'a -> unit = "%array_unsafe_set"
23 external make: int -> 'a -> 'a array = "caml_make_vect"
24 external create: int -> 'a -> 'a array = "caml_make_vect"
27 if l = 0 then [||] else
28 let res = create l (f 0) in
29 for i = 1 to pred l do
30 unsafe_set res i (f i)
34 let make_matrix sx sy init =
35 let res = create sx [||] in
36 for x = 0 to pred sx do
37 unsafe_set res x (create sy init)
41 let create_matrix = make_matrix
45 if l = 0 then [||] else begin
46 let res = create l (unsafe_get a 0) in
47 for i = 1 to pred l do
48 unsafe_set res i (unsafe_get a i)
54 let l1 = length a1 and l2 = length a2 in
55 if l1 = 0 && l2 = 0 then [||] else begin
56 let r = create (l1 + l2) (unsafe_get (if l1 > 0 then a1 else a2) 0) in
57 for i = 0 to l1 - 1 do unsafe_set r i (unsafe_get a1 i) done;
58 for i = 0 to l2 - 1 do unsafe_set r (i + l1) (unsafe_get a2 i) done;
62 let concat_aux init al =
63 let rec size accu = function
65 | h::t -> size (accu + length h) t
67 let res = create (size 0 al) init in
68 let rec fill pos = function
71 for i = 0 to length h - 1 do
72 unsafe_set res (pos + i) (unsafe_get h i);
74 fill (pos + length h) t;
81 let rec find_init = function
84 if length a > 0 then concat_aux (unsafe_get a 0) al else find_init rem
88 if ofs < 0 || len < 0 || ofs > length a - len then invalid_arg "Array.sub"
89 else if len = 0 then [||]
91 let r = create len (unsafe_get a ofs) in
92 for i = 1 to len - 1 do unsafe_set r i (unsafe_get a (ofs + i)) done;
96 let fill a ofs len v =
97 if ofs < 0 || len < 0 || ofs > length a - len
98 then invalid_arg "Array.fill"
99 else for i = ofs to ofs + len - 1 do unsafe_set a i v done
101 let blit a1 ofs1 a2 ofs2 len =
102 if len < 0 || ofs1 < 0 || ofs1 > length a1 - len
103 || ofs2 < 0 || ofs2 > length a2 - len
104 then invalid_arg "Array.blit"
105 else if ofs1 < ofs2 then
107 for i = len - 1 downto 0 do
108 unsafe_set a2 (ofs2 + i) (unsafe_get a1 (ofs1 + i))
112 for i = 0 to len - 1 do
113 unsafe_set a2 (ofs2 + i) (unsafe_get a1 (ofs1 + i))
117 for i = 0 to length a - 1 do f(unsafe_get a i) done
121 if l = 0 then [||] else begin
122 let r = create l (f(unsafe_get a 0)) in
123 for i = 1 to l - 1 do
124 unsafe_set r i (f(unsafe_get a i))
130 for i = 0 to length a - 1 do f i (unsafe_get a i) done
134 if l = 0 then [||] else begin
135 let r = create l (f 0 (unsafe_get a 0)) in
136 for i = 1 to l - 1 do
137 unsafe_set r i (f i (unsafe_get a i))
143 let rec tolist i res =
144 if i < 0 then res else tolist (i - 1) (unsafe_get a i :: res) in
145 tolist (length a - 1) []
147 (* Cannot use List.length here because the List module depends on Array. *)
148 let rec list_length accu = function
150 | h::t -> list_length (succ accu) t
153 let of_list = function
156 let a = create (list_length 0 l) hd in
157 let rec fill i = function
159 | hd::tl -> unsafe_set a i hd; fill (i+1) tl in
162 let fold_left f x a =
164 for i = 0 to length a - 1 do
165 r := f !r (unsafe_get a i)
169 let fold_right f a x =
171 for i = length a - 1 downto 0 do
172 r := f (unsafe_get a i) !r
176 exception Bottom of int;;
181 if i31+2 < l then begin
182 if cmp (get a i31) (get a (i31+1)) < 0 then x := i31+1;
183 if cmp (get a !x) (get a (i31+2)) < 0 then x := i31+2;
186 if i31+1 < l && cmp (get a i31) (get a (i31+1)) < 0
188 else if i31 < l then i31 else raise (Bottom i)
190 let rec trickledown l i e =
191 let j = maxson l i in
192 if cmp (get a j) e > 0 then begin
199 let rec trickle l i e = try trickledown l i e with Bottom i -> set a i e in
200 let rec bubbledown l i =
201 let j = maxson l i in
205 let bubble l i = try bubbledown l i with Bottom i -> i in
206 let rec trickleup i e =
207 let father = (i - 1) / 3 in
208 assert (i <> father);
209 if cmp (get a father) e < 0 then begin
210 set a i (get a father);
211 if father > 0 then trickleup father e else set a 0 e;
217 for i = (l + 1) / 3 - 1 downto 0 do trickle l i (get a i); done;
218 for i = l - 1 downto 2 do
221 trickleup (bubble i 0) e;
223 if l > 1 then (let e = (get a 1) in set a 1 (get a 0); set a 0 e);
227 let stable_sort cmp a =
228 let merge src1ofs src1len src2 src2ofs src2len dst dstofs =
229 let src1r = src1ofs + src1len and src2r = src2ofs + src2len in
230 let rec loop i1 s1 i2 s2 d =
231 if cmp s1 s2 <= 0 then begin
235 loop i1 (get a i1) i2 s2 (d + 1)
237 blit src2 i2 dst (d + 1) (src2r - i2)
242 loop i1 s1 i2 (get src2 i2) (d + 1)
244 blit a i1 dst (d + 1) (src1r - i1)
246 in loop src1ofs (get a src1ofs) src2ofs (get src2 src2ofs) dstofs;
248 let isortto srcofs dst dstofs len =
249 for i = 0 to len - 1 do
250 let e = (get a (srcofs + i)) in
251 let j = ref (dstofs + i - 1) in
252 while (!j >= dstofs && cmp (get dst !j) e > 0) do
253 set dst (!j + 1) (get dst !j);
259 let rec sortto srcofs dst dstofs len =
260 if len <= cutoff then isortto srcofs dst dstofs len else begin
263 sortto (srcofs + l1) dst (dstofs + l1) l2;
264 sortto srcofs a (srcofs + l2) l1;
265 merge (srcofs + l2) l1 dst (dstofs + l1) l2 dst dstofs;
269 if l <= cutoff then isortto 0 a 0 l else begin
272 let t = make l2 (get a 0) in
275 merge l2 l1 t 0 l2 a 0;
279 let fast_sort = stable_sort;;