///|
/// Marks an empty slot of the open-addressed table.
let slot_free : Int32 = -1

///|
/// Marks a slot whose entry has gone. A cluster keeps being probed past it, and
/// it is reused by the next insert that passes through, which is what keeps a
/// delete from breaking the chain of an open-addressed table.
let slot_dead : Int32 = -2

///|
/// Mixes an element's hash with the process seed. The seed has to reach every
/// bit of the result: a table laid out from a predictable hash is a table an
/// attacker can fill with collisions.
fn[K : Hash] hash_seeded(key : K, seed : Int32) -> Int32 {
  let low = key.hash().to_int64() & 0xffffffffL
  let high = seed.to_int64() & 0xffffffffL
  let mut z = (low.reinterpret_as_uint64() << 32) | high.reinterpret_as_uint64()
  z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9
  z = (z ^ (z >> 27)) * 0x94d049bb133111eb
  z = z ^ (z >> 31)
  (z >> 33).to_uint().reinterpret_as_int() & 0x7fffffff
}

///|
/// The smallest power of two at least `n`, and at least 8.
fn bucket_count(n : Int32) -> Int32 {
  let mut count = 8
  while count < n && count < 0x40000000 {
    count = count * 2
  }
  count
}