From a46ba91fede348f9c65425ce0e6f2ea2b2253c72 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 23 Sep 2023 01:19:59 -0700 Subject: [PATCH 1/7] feat: implement partial Eq for IndexMap/IndexSet --- src/index_map.rs | 13 +++++++++++++ src/index_set.rs | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/index_map.rs b/src/index_map.rs index fb70b7f..daa79bc 100644 --- a/src/index_map.rs +++ b/src/index_map.rs @@ -235,3 +235,16 @@ impl Default for FrozenIndexMap { } } } + +impl PartialEq for FrozenIndexMap { + 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 + } +} diff --git a/src/index_set.rs b/src/index_set.rs index 9e99632..f0fa6ea 100644 --- a/src/index_set.rs +++ b/src/index_set.rs @@ -180,3 +180,16 @@ impl Default for FrozenIndexSet { Self::from(IndexSet::default()) } } + +impl PartialEq for FrozenIndexSet { + 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 + } +} From 4d096bbaddb474a8ebb5c01f5b66046e7abbbc30 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 23 Sep 2023 01:20:58 -0700 Subject: [PATCH 2/7] feat: implement PartialEq fof FrozenMap/FrozenVec --- src/map.rs | 13 +++++++++++++ src/vec.rs | 9 +++++++++ 2 files changed, 22 insertions(+) diff --git a/src/map.rs b/src/map.rs index 147a2ec..38dcd16 100644 --- a/src/map.rs +++ b/src/map.rs @@ -495,3 +495,16 @@ impl Default for FrozenBTreeMap { } } } + +impl PartialEq for FrozenMap { + 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 + } +} diff --git a/src/vec.rs b/src/vec.rs index 33b6e6a..e93f7a3 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -275,6 +275,15 @@ impl<'a, T: StableDeref> IntoIterator for &'a FrozenVec { } } +impl PartialEq for FrozenVec +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"]; From b668b4ed873bda57a55600a66398c6d2ba8dbbe6 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 23 Sep 2023 01:21:26 -0700 Subject: [PATCH 3/7] feat: implement PartialEq for sync FrozenVec/FrozenMap/FrozenBTreeMap --- src/sync.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/sync.rs b/src/sync.rs index a551b9a..3b2744d 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -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; @@ -381,6 +382,14 @@ impl std::convert::AsMut> for FrozenMap { } } +impl PartialEq for FrozenMap { + fn eq(&self, other: &Self) -> bool { + let self_ref: &HashMap = &self.map.read().unwrap(); + let other_ref: &HashMap = &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 { @@ -488,6 +497,14 @@ impl Default for FrozenVec { } } +impl PartialEq for FrozenVec { + fn eq(&self, other: &Self) -> bool { + let self_ref: &Vec = &self.vec.read().unwrap(); + let other_ref: &Vec = &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 @@ -933,3 +950,11 @@ impl Default for FrozenBTreeMap { Self::new() } } + +impl PartialEq for FrozenBTreeMap { + fn eq(&self, other: &Self) -> bool { + let self_ref: &BTreeMap = &self.0.read().unwrap(); + let other_ref: &BTreeMap = &other.0.read().unwrap(); + self_ref == other_ref + } +} From 63c33fd33127df3024d43e88e96d2f07d58a2616 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 23 Sep 2023 20:22:03 -0700 Subject: [PATCH 4/7] feat: implement PartialEq for LockFreeFrozenVec --- src/sync.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/sync.rs b/src/sync.rs index 3b2744d..7f372eb 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -696,6 +696,26 @@ impl LockFreeFrozenVec { } } +impl PartialEq for LockFreeFrozenVec { + 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 + for index in 0..self_len { + // the indices are in bounds, so this is safe + if unsafe { self.get_unchecked(index) } != unsafe { other.get_unchecked(index) } { + return false; + } + } + return true; + } +} + #[test] fn test_non_lockfree_unchecked() { #[derive(Copy, Clone, Debug, PartialEq, Eq)] From b9f7b83145640e4c8e01411ee781a582b836a01e Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Mon, 25 Sep 2023 13:20:45 -0700 Subject: [PATCH 5/7] docs: add more safety comments for LockFreeFrozenVec --- src/sync.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sync.rs b/src/sync.rs index 7f372eb..ab18efe 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -705,9 +705,10 @@ impl PartialEq for LockFreeFrozenVec { return false; } - // since the lengths are the same, just check the elements in order + // 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 for index in 0..self_len { - // the indices are in bounds, so this is safe + // 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) } { return false; } From b2cae94c075406cbf1732c41357164915b3b676b Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Mon, 25 Sep 2023 14:39:39 -0700 Subject: [PATCH 6/7] docs: remove comment about changes --- src/sync.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sync.rs b/src/sync.rs index ab18efe..44cdab8 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -706,7 +706,6 @@ impl PartialEq for LockFreeFrozenVec { } // 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 for index in 0..self_len { // 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) } { From 2dd067f78cdfe4623ec8094b61949c1fa3bb4b30 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Mon, 23 Oct 2023 12:37:56 -0700 Subject: [PATCH 7/7] fix: use get in PartialEq for up-to-date values --- src/sync.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sync.rs b/src/sync.rs index 1b32369..3cdca7a 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -810,7 +810,7 @@ impl PartialEq for LockFreeFrozenVec { // Since the lengths are the same, just check the elements in order for index in 0..self_len { // 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) } { + if self.get(index) != other.get(index) { return false; } }