
// hash table operations based on the wikipedia article: "open addressing" or
// closed hashing with linear probing. 

int hash(int key) {
  int key_size;
  int key_idx;
  int key_offset;
  key_size = string_length(key);
  key_idx = key_size >> 1;
  key_offset = key + key_idx;
  if (key_size >= 4)
    return string_pool[key_offset] *
           string_pool[key_offset + 1] *
           string_pool[key_offset + 2];
  else
    return string_pool[key_offset + 1];
}

// open address hashing algorithm

int find_hash_table_slot(int key) {
  int start;
  int i;
  int wrapped;
  wrapped = 0;
  start = hash(key) % HASH_TABLE_SIZE;
  i = start;
  // search until we either find the key, or find an empty slot
  while ((hash_table_key[i] != 0) && !(stringeq(key, hash_table_key[i]) == 0)) {
    i = i + 1;
    if (wrapped && (i == start)) {
      log_error(HASH_TABLE_EXHAUSTION, 0);
      cleanup();
    }
    else if (i == HASH_TABLE_SIZE) {
      wrapped = 1;
      i = 0;
    }
  }
  return i;
}

//int lookup_hash_table(int key) {
//  int i;
//  i = find_hash_table_slot(key);
//  if (hash_table_key[i] != 0)
//    // key is in table
//    return hash_table_value[i];
//  else
//    // key is not in table
//    return 0;
//}

int intern(int name) {
  int hash_table_idx;
  
  // check for uniqueness of new symbol. if its not
  // in the pool add it. if its found return the
  // original and forget the new one.

  hash_table_idx = find_hash_table_slot(name);
  if (hash_table_key[hash_table_idx] == 0) {
    hash_count = hash_count + 1;
    if (hash_count >= hash_count_threshold) {
      // hash table >= 0.75 full
      log_error(HASH_TABLE_EXHAUSTION, 0);
      cleanup();
    }
    hash_table_key[hash_table_idx] = name;
    return name;
  }
  else {
    // symbol already exists
    pool_idx = name;
    return hash_table_key[hash_table_idx];
  }
}

void hash_stats() {
  write_comment();
  write_int(hash_count);
  printf(" hash table slots occupied");
  writeln();
  return;
}
