mt_put(mrb_state *mrb, mt_tbl *t, mrb_sym sym, mrb_sym flags, union mt_ptr ptr)
{
  int hash, pos, start, dpos = -1;

  if (t->alloc == 0) {
    mt_rehash(mrb, t);
  }

  mrb_sym *keys = (mrb_sym*)&t->ptr[t->alloc];
  union mt_ptr *vals = t->ptr;
  hash = kh_int_hash_func(mrb, sym);
  start = pos = hash & (t->alloc-1);
  for (;;) {
    mrb_sym key = keys[pos];
    if (MT_KEY_SYM(key) == sym) {
    value_set:
      keys[pos] = MT_KEY(sym, flags);
      vals[pos] = ptr;
      return;
    }
    else if (key == MT_EMPTY) {
      t->size++;
      goto value_set;
    }
    else if (key == MT_DELETED && dpos < 0) {
      dpos = pos;
    }
    pos = (pos+1) & (t->alloc-1);
    if (pos == start) {         /* not found */
      if (dpos > 0) {
        t->size++;
        pos = dpos;
        goto value_set;
      }
      /* no room */
      mt_rehash(mrb, t);
      start = pos = hash & (t->alloc-1);
      keys = (mrb_sym*)&t->ptr[t->alloc];
      vals = t->ptr;
    }
  }
}
mt_put(mrb_state *mrb, mt_tbl *t, mrb_sym sym, mrb_sym flags, union mt_ptr ptr)
{
  int hash, pos, start, dpos = -1;

  if (t->alloc == 0) {
    mt_rehash(mrb, t);
  }

  mrb_sym *keys = (mrb_sym*)&t->ptr[t->alloc];
  union mt_ptr *vals = t->ptr;
  hash = kh_int_hash_func(mrb, sym);
  start = pos = hash & (t->alloc-1);
  for (;;) {
    mrb_sym key = keys[pos];
    if (MT_KEY_SYM(key) == sym) {
    value_set:
      keys[pos] = MT_KEY(sym, flags);
      vals[pos] = ptr;
      return;
    }
    else if (key == MT_EMPTY) {
      t->size++;
      goto value_set;
    }
    else if (key == MT_DELETED && dpos < 0) {
      dpos = pos;
    }
    pos = (pos+1) & (t->alloc-1);
    if (pos == start) {          
      if (dpos > 0) {
        t->size++;
        pos = dpos;
        goto value_set;
      }
       
      mt_rehash(mrb, t);
      start = pos = hash & (t->alloc-1);
      keys = (mrb_sym*)&t->ptr[t->alloc];
      vals = t->ptr;
    }
  }
}