exception ReturnInt of int ;;

type 'a dynamic = {
  mutable len : int ;
  mutable memlen : int ;
  mutable tab : 'a array
} ;;

let dyn_create (elt : 'a) =
  {
    len = 0 ;
    memlen = 16 ;
    tab = Array.make 16 elt
  } ;;

let dyn_mem (dyn : 'a dynamic) (id : int) =
  if id < 0 || id >= dyn.len then begin
    Printf.fprintf stderr "(at index %d with len %d) \n" id dyn.len;
    failwith "ERROR : invalid access" ;
  end;
  dyn.tab.(id) ;;

let dyn_add (dyn : 'a dynamic) (elt : 'a) =
  if dyn.len = dyn.memlen then begin
    let _new = Array.make (2 * dyn.memlen) dyn.tab.(0) in
    for i = 0 to dyn.memlen -1 do
      _new.(i) <- dyn.tab.(i)
    done;
    dyn.tab <- _new ;
    dyn.memlen <- dyn.memlen * 2 ;
  end;
  dyn.tab.(dyn.len) <- elt ;
  dyn.len <- dyn.len +1 ;;

let dyn_remove (dyn : 'a dynamic) (elt : 'a) =
  try
    for i = 0 to dyn.len -1 do
      if dyn.tab.(i) = elt then
        raise (ReturnInt i)
    done;
    raise (ReturnInt (-1))
  with
    | ReturnInt (-1) -> ()
    | ReturnInt k ->
      for i = k to dyn.len -2 do
        dyn.tab.(i) <- dyn.tab.(i+1)
      done;
      dyn.len <- dyn.len -1 ;
      if (dyn.memlen >= 32) && (dyn.len * 4 <= dyn.memlen) then begin
        let _new = Array.make (dyn.memlen/2) dyn.tab.(0) in
        for i = 0 to dyn.len -1 do
          _new.(i) <- dyn.tab.(i)
        done;
        dyn.tab <- _new ;
        dyn.memlen <- dyn.memlen/2 ;
      end ;;

let dyn_remove_id (dyn : 'a dynamic) (id : int) =
  assert (id >= 0 && id < dyn.len) ;
  let temp = dyn.tab.(dyn.len -1) in
  dyn.tab.(dyn.len -1) <- dyn.tab.(id) ;
  dyn.tab.(id) <- temp ;
  dyn.len <- dyn.len - 1;
  if (dyn.memlen >= 32) && (dyn.len * 4 <= dyn.memlen) then begin
    let _new = Array.make (dyn.memlen/2) dyn.tab.(0) in
    for i = 0 to dyn.len -1 do
      _new.(i) <- dyn.tab.(i)
    done;
    dyn.tab <- _new ;
    dyn.memlen <- dyn.memlen/2 ;
  end ;;

let dyn_fold_left (f : 'b -> 'a -> 'b) (acc0 : 'b) (dyn : 'a dynamic) =
  let acc = ref acc0 in
  for i = 0 to dyn.len -1 do
    acc := f !acc dyn.tab.(i)
  done;
  !acc ;;