Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement PartialEq for LockFreeFrozenVec #62

Merged
merged 8 commits into from
Oct 24, 2023
13 changes: 13 additions & 0 deletions src/index_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,3 +235,16 @@ impl<K: Eq + Hash, V, S: Default> Default for FrozenIndexMap<K, V, S> {
}
}
}

impl<T: Hash + Eq, S: PartialEq> PartialEq for FrozenIndexMap<T, S> {
fn eq(&self, other: &Self) -> bool {
assert!(!self.in_use.get());
assert!(!other.in_use.get());
self.in_use.set(true);
other.in_use.set(true);
let ret = unsafe { *self.map.get() == *other.map.get() };
self.in_use.set(false);
other.in_use.set(false);
ret
}
}
13 changes: 13 additions & 0 deletions src/index_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,16 @@ impl<T: Eq + Hash, S: Default> Default for FrozenIndexSet<T, S> {
Self::from(IndexSet::default())
}
}

impl<T: Hash + Eq, S: BuildHasher> PartialEq for FrozenIndexSet<T, S> {
fn eq(&self, other: &Self) -> bool {
assert!(!self.in_use.get());
assert!(!other.in_use.get());
self.in_use.set(true);
other.in_use.set(true);
let ret = unsafe { *self.set.get() == *other.set.get() };
self.in_use.set(false);
other.in_use.set(false);
ret
}
}
13 changes: 13 additions & 0 deletions src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -495,3 +495,16 @@ impl<K: Clone + Ord, V: StableDeref> Default for FrozenBTreeMap<K, V> {
}
}
}

impl<K: Eq + Hash, V: PartialEq + StableDeref> PartialEq for FrozenMap<K, V> {
fn eq(&self, other: &Self) -> bool {
assert!(!self.in_use.get());
assert!(!other.in_use.get());
self.in_use.set(true);
other.in_use.set(true);
let ret = self.map.get() == other.map.get();
self.in_use.set(false);
other.in_use.set(false);
ret
}
}
46 changes: 46 additions & 0 deletions src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use stable_deref_trait::StableDeref;
use std::alloc::Layout;
use std::borrow::Borrow;
use std::cmp::Eq;
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::hash::Hash;
Expand Down Expand Up @@ -381,6 +382,14 @@ impl<K, V> std::convert::AsMut<HashMap<K, V>> for FrozenMap<K, V> {
}
}

impl<K: Eq + Hash, V: PartialEq> PartialEq for FrozenMap<K, V> {
fn eq(&self, other: &Self) -> bool {
let self_ref: &HashMap<K, V> = &self.map.read().unwrap();
let other_ref: &HashMap<K, V> = &other.map.read().unwrap();
self_ref == other_ref
}
}

/// Append-only threadsafe version of `std::vec::Vec` where
/// insertion does not require mutable access
pub struct FrozenVec<T> {
Expand Down Expand Up @@ -488,6 +497,14 @@ impl<T> Default for FrozenVec<T> {
}
}

impl<T: PartialEq> PartialEq for FrozenVec<T> {
fn eq(&self, other: &Self) -> bool {
let self_ref: &Vec<T> = &self.vec.read().unwrap();
let other_ref: &Vec<T> = &other.vec.read().unwrap();
self_ref == other_ref
}
}

// The context for these functions is that we want to have a
// series of exponentially increasing buffer sizes. We want
// to maximize the total size of the buffers (since this
Expand Down Expand Up @@ -679,6 +696,27 @@ impl<T: Copy> LockFreeFrozenVec<T> {
}
}

impl<T: Copy + PartialEq> PartialEq for LockFreeFrozenVec<T> {
fn eq(&self, other: &Self) -> bool {
// first check the length
let self_len = self.len.load(Ordering::Acquire);
let other_len = other.len.load(Ordering::Acquire);
if self_len != other_len {
return false;
}

// Since the lengths are the same, just check the elements in order
// this assumes that the vectors don't change while equality is being checked
aminya marked this conversation as resolved.
Show resolved Hide resolved
for index in 0..self_len {
aminya marked this conversation as resolved.
Show resolved Hide resolved
// This is safe because the indices are in bounds (for `LockFreeFrozenVec` the bounds can only grow).
if unsafe { self.get_unchecked(index) } != unsafe { other.get_unchecked(index) } {
aminya marked this conversation as resolved.
Show resolved Hide resolved
return false;
}
}
return true;
}
}

#[test]
fn test_non_lockfree_unchecked() {
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -933,3 +971,11 @@ impl<K: Clone + Ord, V: StableDeref> Default for FrozenBTreeMap<K, V> {
Self::new()
}
}

impl<K: PartialEq, V: PartialEq> PartialEq for FrozenBTreeMap<K, V> {
fn eq(&self, other: &Self) -> bool {
let self_ref: &BTreeMap<K, V> = &self.0.read().unwrap();
let other_ref: &BTreeMap<K, V> = &other.0.read().unwrap();
self_ref == other_ref
}
}
9 changes: 9 additions & 0 deletions src/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,15 @@ impl<'a, T: StableDeref> IntoIterator for &'a FrozenVec<T> {
}
}

impl<T: StableDeref> PartialEq for FrozenVec<T>
where
T::Target: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.vec.get() == other.vec.get()
}
}

#[test]
fn test_iteration() {
let vec = vec!["a", "b", "c", "d"];
Expand Down
Loading