1747ad3c4Slazypassion //! Runtime support for precomputed constant hash tables.
2747ad3c4Slazypassion //!
3*d404368dSBenjamin Bouvier //! The shared module with the same name can generate constant hash tables using open addressing
4*d404368dSBenjamin Bouvier //! and quadratic probing.
5*d404368dSBenjamin Bouvier //!
6*d404368dSBenjamin Bouvier //! The hash tables are arrays that are guaranteed to:
7747ad3c4Slazypassion //!
8747ad3c4Slazypassion //! - Have a power-of-two size.
9747ad3c4Slazypassion //! - Contain at least one empty slot.
10747ad3c4Slazypassion //!
11747ad3c4Slazypassion //! This module provides runtime support for lookups in these tables.
12747ad3c4Slazypassion 
13*d404368dSBenjamin Bouvier // Re-export entities from constant_hash for simplicity of use.
14*d404368dSBenjamin Bouvier pub use cranelift_codegen_shared::constant_hash::*;
15*d404368dSBenjamin Bouvier 
16747ad3c4Slazypassion /// Trait that must be implemented by the entries in a constant hash table.
17747ad3c4Slazypassion pub trait Table<K: Copy + Eq> {
18747ad3c4Slazypassion     /// Get the number of entries in this table which must be a power of two.
len(&self) -> usize19747ad3c4Slazypassion     fn len(&self) -> usize;
20747ad3c4Slazypassion 
21747ad3c4Slazypassion     /// Get the key corresponding to the entry at `idx`, or `None` if the entry is empty.
22747ad3c4Slazypassion     /// The `idx` must be in range.
key(&self, idx: usize) -> Option<K>23747ad3c4Slazypassion     fn key(&self, idx: usize) -> Option<K>;
24747ad3c4Slazypassion }
25747ad3c4Slazypassion 
26747ad3c4Slazypassion /// Look for `key` in `table`.
27747ad3c4Slazypassion ///
28747ad3c4Slazypassion /// The provided `hash` value must have been computed from `key` using the same hash function that
29747ad3c4Slazypassion /// was used to construct the table.
30747ad3c4Slazypassion ///
31747ad3c4Slazypassion /// Returns `Ok(idx)` with the table index containing the found entry, or `Err(idx)` with the empty
32747ad3c4Slazypassion /// sentinel entry if no entry could be found.
probe<K: Copy + Eq, T: Table<K> + ?Sized>( table: &T, key: K, hash: usize, ) -> Result<usize, usize>33747ad3c4Slazypassion pub fn probe<K: Copy + Eq, T: Table<K> + ?Sized>(
34747ad3c4Slazypassion     table: &T,
35747ad3c4Slazypassion     key: K,
36747ad3c4Slazypassion     hash: usize,
37747ad3c4Slazypassion ) -> Result<usize, usize> {
38747ad3c4Slazypassion     debug_assert!(table.len().is_power_of_two());
39747ad3c4Slazypassion     let mask = table.len() - 1;
40747ad3c4Slazypassion 
41747ad3c4Slazypassion     let mut idx = hash;
42747ad3c4Slazypassion     let mut step = 0;
43747ad3c4Slazypassion 
44747ad3c4Slazypassion     loop {
45747ad3c4Slazypassion         idx &= mask;
46747ad3c4Slazypassion 
47747ad3c4Slazypassion         match table.key(idx) {
48747ad3c4Slazypassion             None => return Err(idx),
49747ad3c4Slazypassion             Some(k) if k == key => return Ok(idx),
50747ad3c4Slazypassion             _ => {}
51747ad3c4Slazypassion         }
52747ad3c4Slazypassion 
53747ad3c4Slazypassion         // Quadratic probing.
54747ad3c4Slazypassion         step += 1;
55*d404368dSBenjamin Bouvier 
56747ad3c4Slazypassion         // When `table.len()` is a power of two, it can be proven that `idx` will visit all
57747ad3c4Slazypassion         // entries. This means that this loop will always terminate if the hash table has even
58747ad3c4Slazypassion         // one unused entry.
59747ad3c4Slazypassion         debug_assert!(step < table.len());
60747ad3c4Slazypassion         idx += step;
61747ad3c4Slazypassion     }
62747ad3c4Slazypassion }
63