(** Growable Arrays *) module LA = Longarray type 'a fill = Elem of 'a | Susp of (int -> 'a) type 'a t = { gaFill: 'a fill; (** Stuff to use to fill in the array as it grows *) mutable gaMaxInitIndex: int; (** Maximum index that was written to. -1 if no writes have * been made. *) mutable gaData: 'a LA.t; } let growTheArray (ga: 'a t) (len: int) (toidx: int) (why: string) : unit = if toidx >= len then begin (* Grow the array by 50% *) let newlen = toidx + 1 + len / 2 in (* ignore (E.log "growing an array to idx=%d (%s)\n" toidx why); *) let data' = begin match ga.gaFill with Elem x -> let data'' = LA.create newlen x in LA.blit ga.gaData 0 data'' 0 len; data'' | Susp f -> LA.init newlen (fun i -> if i < len then LA.get ga.gaData i else f i) end in ga.gaData <- data' end let max_init_index (ga: 'a t) : int = ga.gaMaxInitIndex let num_alloc_index (ga: 'a t) : int = LA.length ga.gaData let reset_max_init_index (ga: 'a t) : unit = ga.gaMaxInitIndex <- -1 let getg (ga: 'a t) (r: int) : 'a = let len = LA.length ga.gaData in if r >= len then growTheArray ga len r "getg"; LA.get ga.gaData r let setg (ga: 'a t) (r: int) (what: 'a) : unit = let len = LA.length ga.gaData in if r >= len then growTheArray ga len r "setg"; if r > max_init_index ga then ga.gaMaxInitIndex <- r; LA.set ga.gaData r what let get (ga: 'a t) (r: int) : 'a = LA.get ga.gaData r let set (ga: 'a t) (r: int) (what: 'a) : unit = if r > max_init_index ga then ga.gaMaxInitIndex <- r; LA.set ga.gaData r what let make (initsz: int) (fill: 'a fill) : 'a t = { gaFill = fill; gaMaxInitIndex = -1; gaData = begin match fill with Elem x -> LA.create initsz x | Susp f -> LA.init initsz f end; } let clear (ga: 'a t) : unit = (* This assumes the user hasn't used the raw "set" on any value past max_init_index. Maybe we shouldn't trust max_init_index here?? *) if ga.gaMaxInitIndex >= 0 then begin begin match ga.gaFill with Elem x -> LA.fill ga.gaData 0 (ga.gaMaxInitIndex+1) x | Susp f -> for i = 0 to ga.gaMaxInitIndex do LA.set ga.gaData i (f i) done end; ga.gaMaxInitIndex <- -1 end let copy (ga: 'a t) : 'a t = { ga with gaData = LA.copy ga.gaData } let deep_copy (ga: 'a t) (copy: 'a -> 'a): 'a t = { ga with gaData = LA.map copy ga.gaData } (* An accumulating for loop. Used internally. *) let fold_for ~(init: 'a) ~(lo: int) ~(hi: int) (f: int -> 'a -> 'a) = let rec forloop i acc = if i > hi then acc else forloop (i+1) (f i acc) in forloop lo init (** Iterate over the initialized elements of the array *) let iter (f: 'a -> unit) (ga: 'a t) = for i = 0 to max_init_index ga do f (LA.get ga.gaData i) done (** Iterate over the initialized elements of the array *) let iteri (f: int -> 'a -> unit) (ga: 'a t) = for i = 0 to max_init_index ga do f i (LA.get ga.gaData i) done (** Iterate over the elements of 2 arrays *) let iter2 (f: int -> 'a -> 'b -> unit) (ga1: 'a t) (ga2: 'b t) = let len1 = max_init_index ga1 in let len2 = max_init_index ga2 in if len1 > -1 || len2 > -1 then begin let max = if len1 > len2 then begin ignore(getg ga2 len1); (*grow ga2 to match ga1*) len1 end else begin ignore(getg ga1 len2); (*grow ga1 to match ga2*) len2 end in for i = 0 to max do f i (LA.get ga1.gaData i) (LA.get ga2.gaData i) done end (** Fold left over the initialized elements of the array *) let fold_left (f: 'acc -> 'a -> 'acc) (acc: 'acc) (ga: 'a t) : 'acc = let rec loop (acc: 'acc) (idx: int) : 'acc = if idx > max_init_index ga then acc else loop (f acc (LA.get ga.gaData idx)) (idx + 1) in loop acc 0 (** Fold left over the initialized elements of the array *) let fold_lefti (f: 'acc -> int -> 'a -> 'acc) (acc: 'acc) (ga: 'a t) : 'acc = let rec loop (acc: 'acc) (idx: int) : 'acc = if idx > max_init_index ga then acc else loop (f acc idx (LA.get ga.gaData idx)) (idx + 1) in loop acc 0 (** Fold right over the initialized elements of the array *) let fold_right (f: 'a -> 'acc -> 'acc) (ga: 'a t) (acc: 'acc) : 'acc = let rec loop (acc: 'acc) (idx: int) : 'acc = if idx < 0 then acc else loop (f (LA.get ga.gaData idx) acc) (idx - 1) in loop acc (max_init_index ga) (** Document generator *) let d_growarray (sep: Pretty.doc) (doit:int -> 'a -> Pretty.doc) () (elements: 'a t) = LA.docArray ~sep:sep doit () elements.gaData let restoreGA ?deepCopy (ga: 'a t) : (unit -> unit) = let old = (match deepCopy with None -> copy ga | Some f -> deep_copy ga f) in (fun () -> if ga.gaFill != old.gaFill then Errormsg.s (Errormsg.bug "restoreGA to an array with a different fill."); ga.gaMaxInitIndex <- old.gaMaxInitIndex; for i = 0 to max_init_index ga do set ga i (getg old i) done) let find (ga: 'a t) (fn: 'a -> bool) : int option = let rec loop (i:int) : int option = if i > ga.gaMaxInitIndex then None else if fn (get ga i) then Some i else loop (i + 1) in loop 0