123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 |
- (*
- * MultiArray - Resizeable Big Ocaml arrays
- * Copyright (C) 2012 Nicolas Cannasse
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version,
- * with the special exception on linking described in file LICENSE.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
- *)
- type 'a intern
- external ilen : 'a intern -> int = "%obj_size"
- let idup (x : 'a intern) = if ilen x = 0 then x else (Obj.magic (Obj.dup (Obj.repr x)) : 'a intern)
- let imake tag len = (Obj.magic (Obj.new_block tag len) : 'a intern)
- external iget : 'a intern -> int -> 'a = "%obj_field"
- external iset : 'a intern -> int -> 'a -> unit = "%obj_set_field"
- type 'a t = {
- mutable arr : 'a intern intern;
- mutable len : int;
- mutable darr : 'a intern option;
- }
- exception Invalid_arg of int * string * string
- let invalid_arg n f p = raise (Invalid_arg (n,f,p))
- let length d = d.len
- (* create 1K chunks, which allows up to 4GB elements *)
- let nbits = 10
- let size = 1 lsl nbits
- let mask = size - 1
- let create() =
- {
- len = 0;
- arr = imake 0 0;
- darr = Some (imake 0 0);
- }
- let init len f =
- if len > Sys.max_array_length then begin
- let count = (len + size - 1) lsr nbits in
- let d = {
- len = len;
- arr = imake 0 count;
- darr = None;
- } in
- let max = count - 1 in
- for i = 0 to max do
- let arr = imake 0 size in
- iset d.arr i arr;
- for j = 0 to (if i = max then len land mask else size) - 1 do
- iset arr j (f ((i lsl nbits) + j))
- done;
- done;
- d
- end else begin
- let arr = imake 0 len in
- for i = 0 to len - 1 do
- iset arr i (f i)
- done;
- {
- len = len;
- arr = imake 0 0;
- darr = Some arr;
- }
- end
- let make len e =
- if len > Sys.max_array_length then begin
- let count = (len + size - 1) lsr nbits in
- let d = {
- len = len;
- arr = imake 0 count;
- darr = None;
- } in
- let max = count - 1 in
- for i = 0 to max do
- let arr = imake 0 size in
- iset d.arr i arr;
- for j = 0 to (if i = max then len land mask else size) - 1 do
- iset arr j e
- done;
- done;
- d
- end else begin
- let arr = imake 0 len in
- for i = 0 to len - 1 do
- iset arr i e
- done;
- {
- len = len;
- arr = imake 0 0;
- darr = Some arr;
- }
- end
- let empty d =
- d.len = 0
- let get d idx =
- if idx < 0 || idx >= d.len then invalid_arg idx "get" "index";
- match d.darr with
- | None -> iget (iget d.arr (idx lsr nbits)) (idx land mask)
- | Some arr -> iget arr idx
- let set d idx v =
- if idx < 0 || idx >= d.len then invalid_arg idx "set" "index";
- match d.darr with
- | None -> iset (iget d.arr (idx lsr nbits)) (idx land mask) v
- | Some arr -> iset arr idx v
- let add d v =
- (match d.darr with
- | None ->
- let asize = ilen d.arr in
- if d.len >= asize lsl nbits then begin
- let narr = imake 0 (asize + 1) in
- for i = 0 to asize-1 do
- iset narr i (iget d.arr i);
- done;
- iset narr asize (imake 0 size);
- d.arr <- narr;
- end;
- iset (iget d.arr (d.len lsr nbits)) (d.len land mask) v;
- | Some arr ->
- if d.len < ilen arr then begin
- (* set *)
- iset arr d.len v;
- end else if d.len lsl 1 >= Sys.max_array_length then begin
- (* promote *)
- let count = (d.len + size) lsr nbits in
- d.darr <- None;
- d.arr <- imake 0 count;
- let max = count - 1 in
- for i = 0 to max do
- let arr2 = imake 0 size in
- iset d.arr i arr2;
- for j = 0 to (if i = max then d.len land mask else size) - 1 do
- iset arr2 j (iget arr ((i lsl nbits) + j))
- done;
- done;
- iset (iget d.arr (d.len lsr nbits)) (d.len land mask) v;
- end else begin
- (* resize *)
- let arr2 = imake 0 (if d.len = 0 then 1 else d.len lsl 1) in
- for i = 0 to d.len - 1 do
- iset arr2 i (iget arr i)
- done;
- iset arr2 d.len v;
- d.darr <- Some arr2;
- end);
- d.len <- d.len + 1
- let clear d =
- d.len <- 0;
- d.arr <- imake 0 0;
- d.darr <- Some (imake 0 0)
- let of_array src =
- let c = create() in
- Array.iteri (fun i v -> add c v) src;
- c
- let of_list src =
- let c = create() in
- List.iter (add c) src;
- c
- let iter f d = match d.darr with
- | None ->
- let max = ilen d.arr - 1 in
- for i = 0 to max do
- let arr = iget d.arr i in
- for j = 0 to (if i = max then (d.len land mask) else size) - 1 do
- f (iget arr j)
- done;
- done
- | Some arr ->
- for i = 0 to d.len - 1 do
- f (iget arr i)
- done
- let iteri f d = match d.darr with
- | None ->
- let max = ilen d.arr - 1 in
- for i = 0 to max do
- let arr = iget d.arr i in
- for j = 0 to (if i = max then (d.len land mask) else size) - 1 do
- f ((i lsl nbits) + j) (iget arr j)
- done;
- done
- | Some arr ->
- for i = 0 to d.len - 1 do
- f i (iget arr i)
- done
- let map f d = match d.darr with
- | None ->
- let max = ilen d.arr - 1 in
- let d2 = {
- len = d.len;
- arr = imake 0 (max + 1);
- darr = None;
- } in
- for i = 0 to max do
- let arr = iget d.arr i in
- let narr = imake 0 size in
- iset d2.arr i narr;
- for j = 0 to (if i = max then (d.len land mask) else size) - 1 do
- iset narr j (f (iget arr j))
- done;
- done;
- d2
- | Some arr ->
- let arr2 = imake 0 d.len in
- for i = 0 to d.len - 1 do
- iset arr2 i (f (iget arr i))
- done;
- {
- len = d.len;
- arr = imake 0 0;
- darr = Some (arr2);
- }
- let mapi f d = match d.darr with
- | None ->
- let max = ilen d.arr - 1 in
- let d2 = {
- len = d.len;
- arr = imake 0 (max + 1);
- darr = None;
- } in
- for i = 0 to max do
- let arr = iget d.arr i in
- let narr = imake 0 size in
- iset d2.arr i narr;
- for j = 0 to (if i = max then (d.len land mask) else size) - 1 do
- iset narr j (f ((i lsl nbits) + j) (iget arr j))
- done;
- done;
- d2
- | Some arr ->
- let arr2 = imake 0 d.len in
- for i = 0 to d.len - 1 do
- iset arr2 i (f i (iget arr i))
- done;
- {
- len = d.len;
- arr = imake 0 0;
- darr = Some (arr2);
- }
- let fold_left f acc d = match d.darr with
- | None ->
- let acc = ref acc in
- let max = ilen d.arr - 1 in
- for i = 0 to max do
- let arr = iget d.arr i in
- for j = 0 to (if i = max then (d.len land mask) else size) - 1 do
- acc := f !acc (iget arr j)
- done;
- done;
- !acc
- | Some arr ->
- let acc = ref acc in
- for i = 0 to d.len - 1 do
- acc := f !acc (iget arr i)
- done;
- !acc
|