Permalink
Browse files

Fix several compile errors in `atomic-hashmap`.

  • Loading branch information...
ticki committed Aug 11, 2017
1 parent 7118c7b commit 32980a7b45f7e31c3760c7535b414c44abd35b24
Showing with 316 additions and 11 deletions.
  1. +3 −2 atomic-hashmap/src/lib.rs
  2. +1 −1 atomic-hashmap/src/sponge.rs
  3. +28 −8 atomic-hashmap/src/table.rs
  4. +284 −0 atomic-hashmap/src/table.rs.orig
@@ -35,7 +35,7 @@ pub struct HashMap<K, V> {
table: table::Table<K, V>,
}
impl<K: Hash + Eq + 'static, V> HashMap<K, V> {
impl<K: Hash + Eq + 'static + Clone, V: Clone> HashMap<K, V> {
/// Get a value from the map.
pub fn get(&self, key: &K) -> Option<conc::Guard<V>> {
self.table.get(key, Sponge::new(&key))
@@ -45,10 +45,11 @@ impl<K: Hash + Eq + 'static, V> HashMap<K, V> {
///
/// If it already exists, the value is replaced and the old value is returned.
pub fn insert(&self, key: K, val: V) -> Option<conc::Guard<V>> {
let sponge = Sponge::new(&key);
self.table.insert(table::Pair {
key: key,
val: val,
}, Sponge::new(&key))
}, sponge)
}
/// Remove a key from the hash map.
@@ -97,7 +97,7 @@ fn sigma(mut x: u8) -> u8 {
/// When we start squeezing, we set the state to `0` again. Then we pop the highest byte from the
/// internal buffer, which is then XOR'd with the state and permuted by σ. This gives the new state
/// and the extracted byte.
#[derive(Default)]
#[derive(Default, Clone)]
pub struct Sponge {
/// The state of the sponge.
///
@@ -7,6 +7,7 @@ use sponge::Sponge;
use conc;
/// A key-value pair.
#[derive(Clone)]
pub struct Pair<K, V> {
// The key.
pub key: K,
@@ -31,16 +32,16 @@ pub struct Table<K, V> {
buckets: [conc::Atomic<Node<K, V>>; 256],
}
impl<K: Hash + Eq + 'static, V> Table<K, V> {
impl<K: Hash + Eq + 'static + Clone, V: Clone> Table<K, V> {
/// Create a table containing two particular entries.
///
/// This takes two key-value pairs, `pair_a` and `pair_b`, and their respective sponges, and
/// creates a table containing both pairs.
fn two_entries(
pair_a: Pair<K, V>,
sponge_a: Sponge,
mut sponge_a: Sponge,
pair_b: Pair<K, V>,
sponge_b: Sponge,
mut sponge_b: Sponge,
) -> Table<K, V> {
// Start with an empty table.
let mut table = Table::default();
@@ -71,7 +72,8 @@ impl<K: Hash + Eq + 'static, V> Table<K, V> {
.load(atomic::Ordering::Acquire)
.and_then(|node| match *node {
// The bucket was a leaf and the keys match, so we can return the bucket's value.
Node::Leaf(Pair { key: ref found_key, val: ref found_val }) if key == found_key => Some(node.map(|_| found_val)),
Node::Leaf(Pair { key: ref found_key, val: ref found_val }) if key == found_key
=> Some(node.map(|_| found_val)),
// The bucket is a branch with another table, so we recurse and look up in said
// sub-table.
Node::Branch(ref table) => table.get(key, sponge),
@@ -117,7 +119,7 @@ impl<K: Hash + Eq + 'static, V> Table<K, V> {
// lands, this can be simplified to a single `match` statement.
if let Some(some_node) = node { match *some_node {
// There is a branch table. Insert the key-value pair into it.
Node::Branch(table) => return table.insert(pair, sponge),
Node::Branch(ref table) => return table.insert(pair, sponge),
// The key exists, so we can simply update the value.
Node::Leaf(ref found_pair) if found_pair.key == pair.key
// The reason we use CAS here is that the key could have been removed or
@@ -131,7 +133,15 @@ impl<K: Hash + Eq + 'static, V> Table<K, V> {
// Everything went well and the leaf was updated.
Ok(_) => return Some(some_node.map(|_| &found_pair.val)),
// The CAS failed, so we handle the actual node in the next loop iteration.
Err((actual, _)) => node = actual,
Err((actual, Some(box Node::Leaf(pair2)))) => {
// Update the node to the newly read snapshot.
node = actual;
// Put back the pair into the original variable.
pair = pair2;
},
// This case is unreachable as the replacement argument to the CAS is
// always `Some`.
_ => unreachable!(),
},
// Another key exists at the position, so we need to extend the table with a
// branch, containing both entries.
@@ -144,7 +154,9 @@ impl<K: Hash + Eq + 'static, V> Table<K, V> {
// Create a table that contains both the key-value pair we're inserting and the
// one on the place, where we want to insert.
let new_table = Table::two_entries(pair, sponge, old_pair, old_sponge);
// TODO: Eliminate this clone, it is unnecessary (the pairs can be recovered
// from the table), because they're simply moves into a particular entry.
let new_table = Table::two_entries(pair.clone(), sponge.clone(), old_pair.clone(), old_sponge.clone());
// We try to update the current bucket to our table. The reason we use CAS is
// that we want to ensure that the bucket was not changed in the meantime, so
@@ -183,7 +195,15 @@ impl<K: Hash + Eq + 'static, V> Table<K, V> {
// hence we return `None`.
Ok(_) => return None,
// The CAS failed, so we handle the actual node in the next loop iteration.
Err((actual, _)) => node = actual,
Err((actual, Some(box Node::Leaf(pair2)))) => {
// Update the node to the newly read snapshot.
node = actual;
// Put back the pair into the original variable.
pair = pair2;
},
// This case is unreachable as the replacement argument to the CAS is always
// `Some`.
_ => unreachable!(),
}
}
}
Oops, something went wrong.

0 comments on commit 32980a7

Please sign in to comment.