<commit_before>(***********************************************************************)
(*                                                                     *)
(*                           Objective Caml                            *)
(*                                                                     *)
(*         <NAME>, <NAME>, INRIA Rocquencourt         *)
(*                                                                     *)
(*  Copyright 1996 Institut National de Recherche en Informatique et   *)
(*  Automatique.  Distributed only by permission.                      *)
(*                                                                     *)
(***********************************************************************)

(* $Id$ *)

open Obj

let copy o = (magic Array.copy : (< .. > as 'a) -> 'a) o

(**** Compression options ****)

let compact_table = ref true
let copy_parent = ref true
let clean_when_copying = ref true
let retry_count = ref 3
let bucket_small_size = ref 16

(**** Parameters ****)

let step = Sys.word_size / 16

let first_bucket = 0

let bucket_size = 32			(* Must be 256 or less *)

(**** Version ****)

let version = ref 0

(**** Index ****)

type label = int

let label_count = ref 0

let next label =
  incr label_count;
  let label = label + step in
  if label mod (step * bucket_size) = 0 then
    label + step * (65536 - bucket_size)
  else
    label

let decode label =
  (label / 65536 / step, (label mod (step * bucket_size)) / step)

(**** Items ****)

type item

let dummy_item = (magic () : item)

(**** Buckets ****)

type bucket = item array

let bucket_list = ref []

let empty_bucket = [| |]

let new_bucket () =
  let bucket = Array.create (bucket_size + 1) dummy_item in
  bucket.(bucket_size) <- (magic !version : item);
  bucket_list := bucket :: !bucket_list;
  bucket

let copy_bucket bucket =
  let bucket = Array.copy bucket in
  bucket.(bucket_size) <- (magic !version : item);
  bucket_list := bucket :: !bucket_list;
  bucket

let bucket_version bucket =
  (magic bucket.(bucket_size) : int)

(**** Make a clean bucket ****)

let new_filled_bucket pos methods =
  let bucket = new_bucket () in
  List.iter
    (fun (lab, met) ->
       let (buck, elem) = decode lab in
       if buck = pos then
	 bucket.(elem) <- (magic met : item))
    (List.rev methods);
  bucket

(**** Bucket merging ****)

let small_buckets = ref (Array.create 10 [| |])
let small_bucket_count = ref 0

let insert_bucket bucket =
  let length = Array.length !small_buckets in
  if !small_bucket_count >= length then begin
    let new_array = Array.create (2 * length) [| |] in
    Array.blit !small_buckets 0 new_array 0 length;
    small_buckets := new_array
  end;
  !small_buckets.(!small_bucket_count) <- bucket;
  incr small_bucket_count

let remove_bucket n =
  !small_buckets.(n) <- !small_buckets.(!small_bucket_count - 1);
  decr small_bucket_count

let bucket_used b =
  let n = ref 0 in
  for i = 0 to bucket_size - 1 do
    if b.(i) != dummy_item then incr n
  done;
  !n

let small_bucket b = bucket_used b <= !bucket_small_size

exception Failed

let rec except e =
  function
    [] -> []
  | e'::l -> if e == e' then l else e'::(except e l)

let merge_buckets b1 b2 =
  for i = 0 to bucket_size - 1 do
    if
      (b2.(i) != dummy_item) & (b1.(i) != dummy_item) & (b2.(i) != b1.(i))
    then
      raise Failed
  done;
  for i = 0 to bucket_size - 1 do
    if b2.(i) != dummy_item then
      b1.(i) <- b2.(i)
  done;
  bucket_list := except b2 !bucket_list;
  b1

let rec choose bucket i =
  if (i > 0) & (!small_bucket_count > 0) then begin
    let n = Random.int !small_bucket_count in
    if not (small_bucket !small_buckets.(n)) then begin
      remove_bucket n; choose bucket i
    end else
      try
      	merge_buckets !small_buckets.(n) bucket
      with Failed ->
        choose bucket (i - 1)
  end else begin
    insert_bucket bucket;
    bucket
  end

let compact b =
  if
    (b != empty_bucket) & (bucket_version b = !version) & (small_bucket b)
  then
    choose b !retry_count
  else
    b

let compact_buckets buckets =
  for i = 0 to Array.length buckets - 1 do
    buckets.(i) <- compact buckets.(i)
  done

(**** Labels ****)

let first_label = first_bucket * 65536 * step

let last_label = ref first_label
let methods = Hashtbl.create 101

let new_label () =
  let label = !last_label in
  last_label := next !last_label;
  label

let new_method met =
  try
    Hashtbl.find methods met
  with Not_found ->
    let label = new_label () in
    Hashtbl.add methods met label;
    label

let new_anonymous_method =
  new_label

(**** Sparse array ****)

module Vars = Map.Make(struct type t = string let compare = compare end)
type vars = int Vars.t

module Meths = Map.Make(struct type t = string let compare = compare end)
type meths = label list Meths.t

type obj_init
type table =
 { mutable buckets: bucket array;
   mutable methods: meths;
   mutable saved_methods: meths list;
   mutable meth_defs: (label * item) list;
   mutable vars: vars;
   mutable saved_vars: vars list;
   mutable saved_var_lst: int option list;
   mutable size: int;
   mutable init: obj_init list list }

let table_count = ref 0

let initial_size = 1

let new_table () =
  incr table_count;
  { buckets = [| |];
    methods = Meths.empty;
    saved_methods = [];
    meth_defs = [];
    vars = Vars.empty;
    saved_vars = [];
    saved_var_lst = [];
    size = initial_size;
    init = [[]; []]}

let copy_table array1 array2 =
  incr version;
  array1.buckets <- Array.copy array2.buckets;
  array1.methods <- array2.methods;
  array1.saved_methods <- [];
  array1.meth_defs <- array2.meth_defs;
  array1.vars <- array2.vars;
  array1.saved_vars <- [];
  array1.saved_var_lst <- array1.saved_var_lst;
  array1.size <- array2.size;
  array1.init <- array2.init

let resize array new_size =
  let old_size = Array.length array.buckets in
  if new_size > old_size then begin
    let new_buck = Array.create new_size empty_bucket in
    Array.blit array.buckets 0 new_buck 0 old_size;
    array.buckets <- new_buck
 end

let put array label element =
  let (buck, elem) = decode label in
  resize array (buck + 1);
  let bucket = ref (array.buckets.(buck)) in
  if !bucket == empty_bucket then begin
    bucket := new_bucket ();
    array.buckets.(buck) <- !bucket
  end;
  if !bucket.(elem) != element then begin
    if
      (bucket_version !bucket < !version)
          &
      (!bucket.(elem) != dummy_item)
    then begin
      if !clean_when_copying then
        bucket := new_filled_bucket buck array.meth_defs
      else
        bucket := copy_bucket !bucket;
      array.buckets.(buck) <- !bucket
    end;
    !bucket.(elem) <- element
  end

(**** Classes ****)

type t
type class_info =
  {mutable obj_init: t -> t;
   mutable class_init: table -> unit;
   mutable table: table}

let set_initializer table init =
  match table.init with
    l::l'::l'' ->
      let i =
        List.fold_right
          (fun init2 init1 -> (magic init1 : obj_init -> obj_init) init2)
	  l init
      in
        table.init <- (i::l')::l''
  | _ ->
      invalid_arg "Fatal error in Oo.set_initializer."

let inheritance table cl vars meths =
  if
    !copy_parent
    && (table.methods = Meths.empty) && (table.size = initial_size)
    && (table.init = [[]; []])
  then begin
    copy_table table cl.table;
    table.init <- table.init@[[]];
    table.vars <- 
      List.fold_left
        (fun s v ->
           try Vars.add v (Vars.find v table.vars) s with Not_found -> s)
        Vars.empty
        vars;
    table.methods <-
      List.fold_left
        (fun s m ->
           try Meths.add m (Meths.find m table.methods) s with Not_found -> s)
        Meths.empty
        meths
  end else begin
    table.init <- []::table.init;
    table.saved_vars <- table.vars::table.saved_vars;
    table.vars <-
      List.fold_left
        (fun s v ->
           try Vars.add v (Vars.find v table.vars) s with Not_found -> s)
        Vars.empty
        vars;
    table.saved_methods <- table.methods::table.saved_methods;
    table.methods <-
      List.fold_left
        (fun s m ->
           try Meths.add m (Meths.find m table.methods) s with Not_found -> s)
        Meths.empty
        meths;
    cl.class_init table;
    table.vars <-
      List.fold_left
        (fun s v ->
           try Vars.add v (Vars.find v table.vars) s with Not_found -> s)
        (List.hd table.saved_vars)
        vars;
    table.saved_vars <- List.tl table.saved_vars;
    table.methods <-
      List.fold_left
        (fun s m ->
           try Meths.add m (Meths.find m table.methods) s with Not_found -> s)
        (List.hd table.saved_methods)
        meths;
    table.saved_methods <- List.tl table.saved_methods
  end

let get_method_labels table name =
  try
    Meths.find name table.methods
  with Not_found ->
    let label = new_anonymous_method () in
    table.methods <- Meths.add name [label] table.methods;
    [label]

let get_method_label table name =
  List.hd (get_method_labels table name)

let set_method table name element =
  List.iter
    (function label ->
       table.meth_defs <- (label, element) :: table.meth_defs;
       put table label element)
    (get_method_labels table name)

let get_method table label =
  let (buck, elem) = decode label in
  table.buckets.(buck).(elem)

let new_slot table =
  let index = table.size in
  table.size <- index + 1;
  index

let get_variable table name =
  try
    Vars.find name table.vars
  with Not_found ->
    let index = new_slot table in
    table.vars <- Vars.add name index table.vars;
    index

let hide_variable table name =
  try
    let i = Vars.find name table.vars in
    table.vars <- Vars.remove name table.vars;
    table.saved_var_lst <- Some i::table.saved_var_lst
  with Not_found ->
    table.saved_var_lst <- None::table.saved_var_lst

let rec list_remove name =
  function
    [] ->
       invalid_arg "Fatal error in Oo.get_private_variable"
  | (n, _) as a::l ->
       if name = n then l
       else a::list_remove name l

let get_private_variable table name =
  let index =
    try Vars.find name table.vars with Not_found -> new_slot table
  in
  table.vars <-
    begin match List.hd table.saved_var_lst with
      None ->
        Vars.remove name table.vars
    | Some i ->
        Vars.add name i table.vars
    end;
  table.saved_var_lst <- List.tl table.saved_var_lst;
  index

let method_count = ref 0
let inst_var_count = ref 0

let new_object table =
  let obj = Array.create table.size (magic () : t) in
  obj.(0) <- (magic table.buckets : t);
  obj

let create_class class_info public_methods class_init =
  let table = new_table () in
  List.iter
    (function met ->
       table.methods <- Meths.add met [new_method met] table.methods)
    public_methods;
  class_init table;
  method_count := !method_count + List.length table.meth_defs;
  if !compact_table then
    compact_buckets table.buckets;
  inst_var_count := !inst_var_count + table.size - 1;
  class_info.class_init <- class_init;
  class_info.table <- table;
  class_info.obj_init <-
      (function x -> 
         let obj = Array.create table.size (magic () : t) in
         obj.(0) <- (magic table.buckets : t);
         (magic (List.hd (List.hd table.init))) obj x)

(**** Objects ****)

type object = t array

let inst_var obj lab =
  let (buck, elem) = decode lab in
  obj.((magic obj : int array array array).(0).(buck).(elem))

let set_inst_var obj lab value =
  let (buck, elem) = decode lab in
  obj.((magic obj : int array array array).(0).(buck).(elem)) <- value

let send obj lab =
  let (buck, elem) = decode lab in
  (magic obj : (object -> t) array array array).(0).(buck).(elem) obj

(**** Statistics ****)

type stats =
  { classes: int; labels: int; methods: int; inst_vars: int; buckets: int;
    distrib : int array; small_bucket_count: int; small_bucket_max: int }

let distrib () =
  let d = Array.create 32 0 in
  List.iter
    (function b ->
       let n = bucket_used b in
       d.(n - 1) <- d.(n - 1) + 1)
    !bucket_list;
  d

let stats () =
  { classes = !table_count; labels = !label_count;
    methods = !method_count; inst_vars = !inst_var_count;
    buckets = List.length !bucket_list; distrib = distrib ();
    small_bucket_count = !small_bucket_count;
    small_bucket_max = Array.length !small_buckets  }

let sort_buck lst =
  List.map snd
    (Sort.list (fun (n, _) (n', _) -> n <= n')
       (List.map (function b -> (bucket_used b, b)) lst))

let show_buckets () =
  List.iter
    (function b ->
       for i = 0 to bucket_size - 1 do
      	 print_char (if b.(i) == dummy_item then '.' else '*')
       done;
       print_newline ())
    (sort_buck !bucket_list)
<commit_msg>Variable permettant de changer facilement l'indice du premier "bucket".<commit_after>(***********************************************************************)
(*                                                                     *)
(*                           Objective Caml                            *)
(*                                                                     *)
(*         <NAME>, projet Cristal, INRIA Rocquencourt         *)
(*                                                                     *)
(*  Copyright 1996 Institut National de Recherche en Informatique et   *)
(*  Automatique.  Distributed only by permission.                      *)
(*                                                                     *)
(***********************************************************************)

(* $Id$ *)

open Obj

let copy o = (magic Array.copy : (< .. > as 'a) -> 'a) o

(**** Compression options ****)

let compact_table = ref true
let copy_parent = ref true
let clean_when_copying = ref true
let retry_count = ref 3
let bucket_small_size = ref 16

(**** Parameters ****)

let step = Sys.word_size / 16

let first_bucket = 0

let bucket_size = 32			(* Must be 256 or less *)

(**** Version ****)

let version = ref 0

(**** Index ****)

type label = int

let label_count = ref 0

let next label =
  incr label_count;
  let label = label + step in
  if label mod (step * bucket_size) = 0 then
    label + step * (65536 - bucket_size)
  else
    label

let decode label =
  (label / 65536 / step, (label mod (step * bucket_size)) / step)

(**** Items ****)

type item

let dummy_item = (magic () : item)

(**** Buckets ****)

type bucket = item array

let bucket_list = ref []

let empty_bucket = [| |]

let new_bucket () =
  let bucket = Array.create (bucket_size + 1) dummy_item in
  bucket.(bucket_size) <- (magic !version : item);
  bucket_list := bucket :: !bucket_list;
  bucket

let copy_bucket bucket =
  let bucket = Array.copy bucket in
  bucket.(bucket_size) <- (magic !version : item);
  bucket_list := bucket :: !bucket_list;
  bucket

let bucket_version bucket =
  (magic bucket.(bucket_size) : int)

(**** Make a clean bucket ****)

let new_filled_bucket pos methods =
  let bucket = new_bucket () in
  List.iter
    (fun (lab, met) ->
       let (buck, elem) = decode lab in
       if buck = pos then
	 bucket.(elem) <- (magic met : item))
    (List.rev methods);
  bucket

(**** Bucket merging ****)

let small_buckets = ref (Array.create 10 [| |])
let small_bucket_count = ref 0

let insert_bucket bucket =
  let length = Array.length !small_buckets in
  if !small_bucket_count >= length then begin
    let new_array = Array.create (2 * length) [| |] in
    Array.blit !small_buckets 0 new_array 0 length;
    small_buckets := new_array
  end;
  !small_buckets.(!small_bucket_count) <- bucket;
  incr small_bucket_count

let remove_bucket n =
  !small_buckets.(n) <- !small_buckets.(!small_bucket_count - 1);
  decr small_bucket_count

let bucket_used b =
  let n = ref 0 in
  for i = 0 to bucket_size - 1 do
    if b.(i) != dummy_item then incr n
  done;
  !n

let small_bucket b = bucket_used b <= !bucket_small_size

exception Failed

let rec except e =
  function
    [] -> []
  | e'::l -> if e == e' then l else e'::(except e l)

let merge_buckets b1 b2 =
  for i = 0 to bucket_size - 1 do
    if
      (b2.(i) != dummy_item) & (b1.(i) != dummy_item) & (b2.(i) != b1.(i))
    then
      raise Failed
  done;
  for i = 0 to bucket_size - 1 do
    if b2.(i) != dummy_item then
      b1.(i) <- b2.(i)
  done;
  bucket_list := except b2 !bucket_list;
  b1

let rec choose bucket i =
  if (i > 0) & (!small_bucket_count > 0) then begin
    let n = Random.int !small_bucket_count in
    if not (small_bucket !small_buckets.(n)) then begin
      remove_bucket n; choose bucket i
    end else
      try
      	merge_buckets !small_buckets.(n) bucket
      with Failed ->
        choose bucket (i - 1)
  end else begin
    insert_bucket bucket;
    bucket
  end

let compact b =
  if
    (b != empty_bucket) & (bucket_version b = !version) & (small_bucket b)
  then
    choose b !retry_count
  else
    b

let compact_buckets buckets =
  for i = first_bucket to Array.length buckets - 1 do
    buckets.(i) <- compact buckets.(i)
  done

(**** Labels ****)

let first_label = first_bucket * 65536 * step

let last_label = ref first_label
let methods = Hashtbl.create 101

let new_label () =
  let label = !last_label in
  last_label := next !last_label;
  label

let new_method met =
  try
    Hashtbl.find methods met
  with Not_found ->
    let label = new_label () in
    Hashtbl.add methods met label;
    label

let new_anonymous_method =
  new_label

(**** Sparse array ****)

module Vars = Map.Make(struct type t = string let compare = compare end)
type vars = int Vars.t

module Meths = Map.Make(struct type t = string let compare = compare end)
type meths = label list Meths.t

type obj_init
type table =
 { mutable buckets: bucket array;
   mutable methods: meths;
   mutable saved_methods: meths list;
   mutable meth_defs: (label * item) list;
   mutable vars: vars;
   mutable saved_vars: vars list;
   mutable saved_var_lst: int option list;
   mutable size: int;
   mutable init: obj_init list list }

let table_count = ref 0

let initial_size = 1

let new_table () =
  incr table_count;
  { buckets = [| |];
    methods = Meths.empty;
    saved_methods = [];
    meth_defs = [];
    vars = Vars.empty;
    saved_vars = [];
    saved_var_lst = [];
    size = initial_size;
    init = [[]; []]}

let copy_table array1 array2 =
  incr version;
  array1.buckets <- Array.copy array2.buckets;
  array1.methods <- array2.methods;
  array1.saved_methods <- [];
  array1.meth_defs <- array2.meth_defs;
  array1.vars <- array2.vars;
  array1.saved_vars <- [];
  array1.saved_var_lst <- array1.saved_var_lst;
  array1.size <- array2.size;
  array1.init <- array2.init

let resize array new_size =
  let old_size = Array.length array.buckets in
  if new_size > old_size then begin
    let new_buck = Array.create new_size empty_bucket in
    Array.blit array.buckets 0 new_buck 0 old_size;
    array.buckets <- new_buck
 end

let put array label element =
  let (buck, elem) = decode label in
  resize array (buck + 1);
  let bucket = ref (array.buckets.(buck)) in
  if !bucket == empty_bucket then begin
    bucket := new_bucket ();
    array.buckets.(buck) <- !bucket
  end;
  if !bucket.(elem) != element then begin
    if
      (bucket_version !bucket < !version)
          &
      (!bucket.(elem) != dummy_item)
    then begin
      if !clean_when_copying then
        bucket := new_filled_bucket buck array.meth_defs
      else
        bucket := copy_bucket !bucket;
      array.buckets.(buck) <- !bucket
    end;
    !bucket.(elem) <- element
  end

(**** Classes ****)

type t
type class_info =
  {mutable obj_init: t -> t;
   mutable class_init: table -> unit;
   mutable table: table}

let set_initializer table init =
  match table.init with
    l::l'::l'' ->
      let i =
        List.fold_right
          (fun init2 init1 -> (magic init1 : obj_init -> obj_init) init2)
	  l init
      in
        table.init <- (i::l')::l''
  | _ ->
      invalid_arg "Fatal error in Oo.set_initializer."

let inheritance table cl vars meths =
  if
    !copy_parent
    && (table.methods = Meths.empty) && (table.size = initial_size)
    && (table.init = [[]; []])
  then begin
    copy_table table cl.table;
    table.init <- table.init@[[]];
    table.vars <- 
      List.fold_left
        (fun s v ->
           try Vars.add v (Vars.find v table.vars) s with Not_found -> s)
        Vars.empty
        vars;
    table.methods <-
      List.fold_left
        (fun s m ->
           try Meths.add m (Meths.find m table.methods) s with Not_found -> s)
        Meths.empty
        meths
  end else begin
    table.init <- []::table.init;
    table.saved_vars <- table.vars::table.saved_vars;
    table.vars <-
      List.fold_left
        (fun s v ->
           try Vars.add v (Vars.find v table.vars) s with Not_found -> s)
        Vars.empty
        vars;
    table.saved_methods <- table.methods::table.saved_methods;
    table.methods <-
      List.fold_left
        (fun s m ->
           try Meths.add m (Meths.find m table.methods) s with Not_found -> s)
        Meths.empty
        meths;
    cl.class_init table;
    table.vars <-
      List.fold_left
        (fun s v ->
           try Vars.add v (Vars.find v table.vars) s with Not_found -> s)
        (List.hd table.saved_vars)
        vars;
    table.saved_vars <- List.tl table.saved_vars;
    table.methods <-
      List.fold_left
        (fun s m ->
           try Meths.add m (Meths.find m table.methods) s with Not_found -> s)
        (List.hd table.saved_methods)
        meths;
    table.saved_methods <- List.tl table.saved_methods
  end

let get_method_labels table name =
  try
    Meths.find name table.methods
  with Not_found ->
    let label = new_anonymous_method () in
    table.methods <- Meths.add name [label] table.methods;
    [label]

let get_method_label table name =
  List.hd (get_method_labels table name)

let set_method table name element =
  List.iter
    (function label ->
       table.meth_defs <- (label, element) :: table.meth_defs;
       put table label element)
    (get_method_labels table name)

let get_method table label =
  let (buck, elem) = decode label in
  table.buckets.(buck).(elem)

let new_slot table =
  let index = table.size in
  table.size <- index + 1;
  index

let get_variable table name =
  try
    Vars.find name table.vars
  with Not_found ->
    let index = new_slot table in
    table.vars <- Vars.add name index table.vars;
    index

let hide_variable table name =
  try
    let i = Vars.find name table.vars in
    table.vars <- Vars.remove name table.vars;
    table.saved_var_lst <- Some i::table.saved_var_lst
  with Not_found ->
    table.saved_var_lst <- None::table.saved_var_lst

let rec list_remove name =
  function
    [] ->
       invalid_arg "Fatal error in Oo.get_private_variable"
  | (n, _) as a::l ->
       if name = n then l
       else a::list_remove name l

let get_private_variable table name =
  let index =
    try Vars.find name table.vars with Not_found -> new_slot table
  in
  table.vars <-
    begin match List.hd table.saved_var_lst with
      None ->
        Vars.remove name table.vars
    | Some i ->
        Vars.add name i table.vars
    end;
  table.saved_var_lst <- List.tl table.saved_var_lst;
  index

let method_count = ref 0
let inst_var_count = ref 0

let new_object table =
  let obj = Array.create table.size (magic () : t) in
  obj.(0) <- (magic table.buckets : t);
  obj

let create_class class_info public_methods class_init =
  let table = new_table () in
  List.iter
    (function met ->
       table.methods <- Meths.add met [new_method met] table.methods)
    public_methods;
  class_init table;
  method_count := !method_count + List.length table.meth_defs;
  if !compact_table then
    compact_buckets table.buckets;
  inst_var_count := !inst_var_count + table.size - 1;
  class_info.class_init <- class_init;
  class_info.table <- table;
  class_info.obj_init <-
      (function x -> 
         let obj = Array.create table.size (magic () : t) in
         obj.(0) <- (magic table.buckets : t);
         (magic (List.hd (List.hd table.init))) obj x)

(**** Objects ****)

type object = t array

let inst_var obj lab =
  let (buck, elem) = decode lab in
  obj.((magic obj : int array array array).(0).(buck).(elem))

let set_inst_var obj lab value =
  let (buck, elem) = decode lab in
  obj.((magic obj : int array array array).(0).(buck).(elem)) <- value

let send obj lab =
  let (buck, elem) = decode lab in
  (magic obj : (object -> t) array array array).(0).(buck).(elem) obj

(**** Statistics ****)

type stats =
  { classes: int; labels: int; methods: int; inst_vars: int; buckets: int;
    distrib : int array; small_bucket_count: int; small_bucket_max: int }

let distrib () =
  let d = Array.create 32 0 in
  List.iter
    (function b ->
       let n = bucket_used b in
       d.(n - 1) <- d.(n - 1) + 1)
    !bucket_list;
  d

let stats () =
  { classes = !table_count; labels = !label_count;
    methods = !method_count; inst_vars = !inst_var_count;
    buckets = List.length !bucket_list; distrib = distrib ();
    small_bucket_count = !small_bucket_count;
    small_bucket_max = Array.length !small_buckets  }

let sort_buck lst =
  List.map snd
    (Sort.list (fun (n, _) (n', _) -> n <= n')
       (List.map (function b -> (bucket_used b, b)) lst))

let show_buckets () =
  List.iter
    (function b ->
       for i = 0 to bucket_size - 1 do
      	 print_char (if b.(i) == dummy_item then '.' else '*')
       done;
       print_newline ())
    (sort_buck !bucket_list)

{'fraction_non_alphanumeric': 0.12456422108190685, 'fraction_numerical': 0.008656821653805475, 'mean_word_length': 2.4560714769189116, 'pattern_counts': {'":': 0, '<': 114, '<?xml version=': 0, '>': 96, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1915382', 'n_tokens_mistral': 8835, 'n_tokens_neox': 8366, 'n_words': 2555}