multiArray.ml 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. (*
  2. * MultiArray - Resizeable Big Ocaml arrays
  3. * Copyright (C) 2012 Nicolas Cannasse
  4. *
  5. * This library is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Lesser General Public
  7. * License as published by the Free Software Foundation; either
  8. * version 2.1 of the License, or (at your option) any later version,
  9. * with the special exception on linking described in file LICENSE.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  19. *)
  20. type 'a intern
  21. external ilen : 'a intern -> int = "%obj_size"
  22. let idup (x : 'a intern) = if ilen x = 0 then x else (Obj.magic (Obj.dup (Obj.repr x)) : 'a intern)
  23. let imake tag len = (Obj.magic (Obj.new_block tag len) : 'a intern)
  24. external iget : 'a intern -> int -> 'a = "%obj_field"
  25. external iset : 'a intern -> int -> 'a -> unit = "%obj_set_field"
  26. type 'a t = {
  27. mutable arr : 'a intern intern;
  28. mutable len : int;
  29. mutable darr : 'a intern option;
  30. }
  31. exception Invalid_arg of int * string * string
  32. let invalid_arg n f p = raise (Invalid_arg (n,f,p))
  33. let length d = d.len
  34. (* create 1K chunks, which allows up to 4GB elements *)
  35. let nbits = 10
  36. let size = 1 lsl nbits
  37. let mask = size - 1
  38. let create() =
  39. {
  40. len = 0;
  41. arr = imake 0 0;
  42. darr = Some (imake 0 0);
  43. }
  44. let init len f =
  45. if len > Sys.max_array_length then begin
  46. let count = (len + size - 1) lsr nbits in
  47. let d = {
  48. len = len;
  49. arr = imake 0 count;
  50. darr = None;
  51. } in
  52. let max = count - 1 in
  53. for i = 0 to max do
  54. let arr = imake 0 size in
  55. iset d.arr i arr;
  56. for j = 0 to (if i = max then len land mask else size) - 1 do
  57. iset arr j (f ((i lsl nbits) + j))
  58. done;
  59. done;
  60. d
  61. end else begin
  62. let arr = imake 0 len in
  63. for i = 0 to len - 1 do
  64. iset arr i (f i)
  65. done;
  66. {
  67. len = len;
  68. arr = imake 0 0;
  69. darr = Some arr;
  70. }
  71. end
  72. let make len e =
  73. if len > Sys.max_array_length then begin
  74. let count = (len + size - 1) lsr nbits in
  75. let d = {
  76. len = len;
  77. arr = imake 0 count;
  78. darr = None;
  79. } in
  80. let max = count - 1 in
  81. for i = 0 to max do
  82. let arr = imake 0 size in
  83. iset d.arr i arr;
  84. for j = 0 to (if i = max then len land mask else size) - 1 do
  85. iset arr j e
  86. done;
  87. done;
  88. d
  89. end else begin
  90. let arr = imake 0 len in
  91. for i = 0 to len - 1 do
  92. iset arr i e
  93. done;
  94. {
  95. len = len;
  96. arr = imake 0 0;
  97. darr = Some arr;
  98. }
  99. end
  100. let empty d =
  101. d.len = 0
  102. let get d idx =
  103. if idx < 0 || idx >= d.len then invalid_arg idx "get" "index";
  104. match d.darr with
  105. | None -> iget (iget d.arr (idx lsr nbits)) (idx land mask)
  106. | Some arr -> iget arr idx
  107. let set d idx v =
  108. if idx < 0 || idx >= d.len then invalid_arg idx "set" "index";
  109. match d.darr with
  110. | None -> iset (iget d.arr (idx lsr nbits)) (idx land mask) v
  111. | Some arr -> iset arr idx v
  112. let add d v =
  113. (match d.darr with
  114. | None ->
  115. let asize = ilen d.arr in
  116. if d.len >= asize lsl nbits then begin
  117. let narr = imake 0 (asize + 1) in
  118. for i = 0 to asize-1 do
  119. iset narr i (iget d.arr i);
  120. done;
  121. iset narr asize (imake 0 size);
  122. d.arr <- narr;
  123. end;
  124. iset (iget d.arr (d.len lsr nbits)) (d.len land mask) v;
  125. | Some arr ->
  126. if d.len < ilen arr then begin
  127. (* set *)
  128. iset arr d.len v;
  129. end else if d.len lsl 1 >= Sys.max_array_length then begin
  130. (* promote *)
  131. let count = (d.len + size) lsr nbits in
  132. d.darr <- None;
  133. d.arr <- imake 0 count;
  134. let max = count - 1 in
  135. for i = 0 to max do
  136. let arr2 = imake 0 size in
  137. iset d.arr i arr2;
  138. for j = 0 to (if i = max then d.len land mask else size) - 1 do
  139. iset arr2 j (iget arr ((i lsl nbits) + j))
  140. done;
  141. done;
  142. iset (iget d.arr (d.len lsr nbits)) (d.len land mask) v;
  143. end else begin
  144. (* resize *)
  145. let arr2 = imake 0 (if d.len = 0 then 1 else d.len lsl 1) in
  146. for i = 0 to d.len - 1 do
  147. iset arr2 i (iget arr i)
  148. done;
  149. iset arr2 d.len v;
  150. d.darr <- Some arr2;
  151. end);
  152. d.len <- d.len + 1
  153. let clear d =
  154. d.len <- 0;
  155. d.arr <- imake 0 0;
  156. d.darr <- Some (imake 0 0)
  157. let of_array src =
  158. let c = create() in
  159. Array.iteri (fun i v -> add c v) src;
  160. c
  161. let of_list src =
  162. let c = create() in
  163. List.iter (add c) src;
  164. c
  165. let iter f d = match d.darr with
  166. | None ->
  167. let max = ilen d.arr - 1 in
  168. for i = 0 to max do
  169. let arr = iget d.arr i in
  170. for j = 0 to (if i = max then (d.len land mask) else size) - 1 do
  171. f (iget arr j)
  172. done;
  173. done
  174. | Some arr ->
  175. for i = 0 to d.len - 1 do
  176. f (iget arr i)
  177. done
  178. let iteri f d = match d.darr with
  179. | None ->
  180. let max = ilen d.arr - 1 in
  181. for i = 0 to max do
  182. let arr = iget d.arr i in
  183. for j = 0 to (if i = max then (d.len land mask) else size) - 1 do
  184. f ((i lsl nbits) + j) (iget arr j)
  185. done;
  186. done
  187. | Some arr ->
  188. for i = 0 to d.len - 1 do
  189. f i (iget arr i)
  190. done
  191. let map f d = match d.darr with
  192. | None ->
  193. let max = ilen d.arr - 1 in
  194. let d2 = {
  195. len = d.len;
  196. arr = imake 0 (max + 1);
  197. darr = None;
  198. } in
  199. for i = 0 to max do
  200. let arr = iget d.arr i in
  201. let narr = imake 0 size in
  202. iset d2.arr i narr;
  203. for j = 0 to (if i = max then (d.len land mask) else size) - 1 do
  204. iset narr j (f (iget arr j))
  205. done;
  206. done;
  207. d2
  208. | Some arr ->
  209. let arr2 = imake 0 d.len in
  210. for i = 0 to d.len - 1 do
  211. iset arr2 i (f (iget arr i))
  212. done;
  213. {
  214. len = d.len;
  215. arr = imake 0 0;
  216. darr = Some (arr2);
  217. }
  218. let mapi f d = match d.darr with
  219. | None ->
  220. let max = ilen d.arr - 1 in
  221. let d2 = {
  222. len = d.len;
  223. arr = imake 0 (max + 1);
  224. darr = None;
  225. } in
  226. for i = 0 to max do
  227. let arr = iget d.arr i in
  228. let narr = imake 0 size in
  229. iset d2.arr i narr;
  230. for j = 0 to (if i = max then (d.len land mask) else size) - 1 do
  231. iset narr j (f ((i lsl nbits) + j) (iget arr j))
  232. done;
  233. done;
  234. d2
  235. | Some arr ->
  236. let arr2 = imake 0 d.len in
  237. for i = 0 to d.len - 1 do
  238. iset arr2 i (f i (iget arr i))
  239. done;
  240. {
  241. len = d.len;
  242. arr = imake 0 0;
  243. darr = Some (arr2);
  244. }
  245. let fold_left f acc d = match d.darr with
  246. | None ->
  247. let acc = ref acc in
  248. let max = ilen d.arr - 1 in
  249. for i = 0 to max do
  250. let arr = iget d.arr i in
  251. for j = 0 to (if i = max then (d.len land mask) else size) - 1 do
  252. acc := f !acc (iget arr j)
  253. done;
  254. done;
  255. !acc
  256. | Some arr ->
  257. let acc = ref acc in
  258. for i = 0 to d.len - 1 do
  259. acc := f !acc (iget arr i)
  260. done;
  261. !acc