(* test hash functions a bit *)

module H = CCHash

module Hist = struct
  type t = {
    tbl: (int, int) Hashtbl.t;
    mutable n_samples: int;
  }

  let create () : t = { tbl = Hashtbl.create 32; n_samples = 0 }

  let add_n self x n =
    Hashtbl.replace self.tbl x (n + try Hashtbl.find self.tbl x with _ -> 0);
    self.n_samples <- n + self.n_samples

  let pp out (self : t) : unit =
    let max = Hashtbl.fold (fun k _ n -> max k n) self.tbl 0 in
    let min = Hashtbl.fold (fun k _ n -> min k n) self.tbl max in
    for i = min to max do
      let n = try Hashtbl.find self.tbl i with _ -> 0 in
      Format.fprintf out "[v=%-4d, n-inputs %-6d] %s@." i n
        (String.make (int_of_float @@ ceil (log (float n))) '#')
    done
end

let reset_line = "\x1b[2K\r"

let t_int n1 n2 =
  Printf.printf "test hash_int on %d--%d\n" n1 n2;
  let count = Hashtbl.create 128 in
  for i = n1 to n2 do
    Printf.printf "%shash %d…%!" reset_line i;
    let h = H.int i in
    Hashtbl.replace count h (1 + CCHashtbl.get_or count h ~default:0);
    if i mod 1024 * 1024 * 1024 = 0 then Gc.major ()
  done;
  Printf.printf "%s%!" reset_line;
  (* reverse table *)
  let by_count =
    CCHashtbl.to_iter count
    |> Iter.map (fun (_h, n) -> n)
    |> Iter.count ~hash:H.int
  in
  let hist = Hist.create () in
  by_count (fun (n, i) -> Hist.add_n hist n i);
  Format.printf "histogram:@.%a@." Hist.pp hist;
  (*assert (Hist.check_uniform hist);*)
  ()

let () =
  t_int 0 2_000_000;
  t_int (-4_000_000) (-3_500_000);
  ()
