
// separate chaining hash routines for scheme symbols.
// see wikipedia article: "Hash table"

int hash_atom(int key, int hash_size) {
  // this algorithm assumes the hash size is 4096
  int hash_val;
  int char1;
  int char2;
  int char3;
  int char4;

  if (numberp(key) == Mtrue) {
    hash_val = get_integer_val(key);
    return hash_val & 0xfff;
  }
  else {
    if (MstrSizeRef(key) >= 8) // use second string data word as hash
      hash_val = MstrHash2Ref(key);
    else // use first string data word as hash
      hash_val = MstrHashRef(key);
    char1 = (hash_val & 0x0e000000) >> 25;
    char2 = (hash_val & 0x0e0000) >> 14;
    char3 = (hash_val & 0x0e00) >> 3;
    char4 = (hash_val & 0x0e) << 8;
    return
      (char1 + char2 + char3 + char4);
  }
}

int hash_binding(int table, int key, int index) {
  int binding;

  binding = assq_(key, vector_ref(table, index));
  if (binding == Mfalse)
    return 0;
  else
    return binding;
}

//int hash_ref(int table, int key) {
//  int binding;
//  int table_size;
//
//  table_size = Mveclength(table);
//
//  binding =
//    assq_(
//      key,
//      vector_ref(
//        table,
//        hash_atom(
//          key,
//          table_size)));
//  if (binding == Mfalse)
//    return 0;
//  // else
//    return Mcdr(binding);
//}

int hash_set(int table, int key, int obj) {
  int hash_index;
  int binding;
  int table_size;

  table_size = Mveclength(table);

  hash_index = hash_atom(key, table_size);
  binding = hash_binding(table, key, hash_index);
  if (binding)
    return rplacd(binding, obj);
  else
    return
      vector_set(
        table, hash_index,
        kons(kons(key, obj), vector_ref(table, hash_index)));
}

int make_hash_table(int size) {
  return make_vector(size);
}

void hash_histogram(int table) {
  int i;
  int size;
  int element_size;

  printf("hash histogram");
  writeln();
  size = Mveclength(table);
  for (i = 0; i < size; i++) {
    element_size = list_length(vector_ref(table, i));
    if (element_size) {
      write_int(i);
      printf(" ");
      write_int(element_size);
      writeln();
    }
  }
  return;
}
