diff --git a/fuzz/fuzz_targets/main.rs b/fuzz/fuzz_targets/main.rs index f8402119..3df308ce 100644 --- a/fuzz/fuzz_targets/main.rs +++ b/fuzz/fuzz_targets/main.rs @@ -161,8 +161,9 @@ fn test_with_inline_cap( small_vec = SmallVec::with_capacity(cap.0); std_vec = Vec::with_capacity(cap.0); } + #[allow(deprecated)] Op::FromVec => { - small_vec = SmallVec::from(Into::>::into(small_vec)); + small_vec = SmallVec::from(small_vec.into_vec()); // No-op on `Vec` } Op::FromSlice(data) => { diff --git a/src/comparisons.rs b/src/comparisons.rs index bc70e5ff..0585df22 100644 --- a/src/comparisons.rs +++ b/src/comparisons.rs @@ -1,3 +1,8 @@ +#[cfg(feature = "equivalent")] +use equivalent::{ + Comparable, + Equivalent +}; use { super::{ SmallVec, @@ -11,68 +16,292 @@ use { core::cmp::Ordering }; -macro_rules! __impl_slice_eq1 { - ([$($vars:tt)*] $lhs:ty, $rhs:ty $(where $ty:ty: $bound:ident)?) => { - impl PartialEq<$rhs> for $lhs - where - Item: PartialEq, - $($ty: $bound)? - { +macro_rules! implementation { + ([$($generics:tt)*] for $left:ty =? $right:ty $(where $typename:ty: $bound:ident)?) => { + impl< + Item: PartialEq, + Other, + Heap: Allocator, + const INLINE: usize, + $($generics)* + > PartialEq<$right> for $left $(where $typename: $bound)? { + #[inline] + fn eq(&self, other: &$right) -> bool { + *AsRef::<[Item]>::as_ref(self) == *AsRef::<[Other]>::as_ref(other) + } + } + }; + ([$($generics:tt)*] for $left:ty =<> $right:ty $(where $typename:ty: $bound:ident)?) => { + impl< + Item: PartialOrd, + Other, + Heap: Allocator, + const INLINE: usize, + $($generics)* + > PartialOrd<$right> for $left $(where $typename: $bound)? { + #[inline] + fn partial_cmp(&self, other: &$right) -> Option { + AsRef::<[Item]>::as_ref(self).iter().partial_cmp(AsRef::<[Other]>::as_ref(other)) + } + } + }; + ([$($generics:tt)*] for $left:ty =?+ $right:ty $(where $typename:ty: $bound:ident)?) => { + impl< + Item: Equivalent, + Other, + Heap: Allocator, + const INLINE: usize, + $($generics)* + > Equivalent<$right> for $left $(where $typename: $bound)? { #[inline] - fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] } + fn equivalent(&self, key: &$right) -> bool { + self.len() == key.len() && self.iter() + .zip(AsRef::<[Other]>::as_ref(key)) + .all(|(item, key)| item.equivalent(key)) + } } }; + ([$($generics:tt)*] for $left:ty =<>+ $right:ty $(where $typename:ty: $bound:ident)?) => { + impl< + Item: Comparable, + Other, + Heap: Allocator, + const INLINE: usize, + $($generics)* + > Comparable<$right> for $left $(where $typename: $bound)? { + fn compare(&self, other: &$right) -> Ordering { + self.iter() + .zip(AsRef::<[Other]>::as_ref(other)) + .map(|(item, key)| item.compare(key)) + .find(|&ordering| ordering != Ordering::Equal) + .unwrap_or_else(|| self.len().cmp(&other.len())) + } + } + } } -__impl_slice_eq1! { [const M: usize, A2: Allocator] - SmallVec, - SmallVec +implementation!([const LENGTH: usize, Assigner: Allocator] for SmallVec =? SmallVec); +impl Eq for SmallVec {} +implementation!([const LENGTH: usize, Assigner: Allocator] for SmallVec =<> SmallVec); +impl Ord for SmallVec { + #[inline] + fn cmp(&self, other: &SmallVec) -> Ordering { + self.as_ref().cmp(other.as_ref()) + } } -__impl_slice_eq1! { [const M: usize] SmallVec, [U; INLINE] } -__impl_slice_eq1! { [const M: usize] SmallVec, &[U; INLINE] } -__impl_slice_eq1! { [] SmallVec, [U] } -__impl_slice_eq1! { [] SmallVec, &[U] } -__impl_slice_eq1! { [] SmallVec, &mut [U] } -__impl_slice_eq1! { [] [Item], SmallVec } -__impl_slice_eq1! { [] &[Item], SmallVec } -__impl_slice_eq1! { [] &mut [Item], SmallVec } -__impl_slice_eq1! { [] Vec, SmallVec } -__impl_slice_eq1! { [] SmallVec, Vec } -__impl_slice_eq1! { [] Cow<'_, [Item]>, SmallVec where Item: Clone } -__impl_slice_eq1! { [] SmallVec, Cow<'_, [U]> where U: Clone } -impl PartialEq> - for VecDeque -where Item: PartialEq +implementation!([const LENGTH: usize] for SmallVec =? [Other; LENGTH]); +implementation!([const LENGTH: usize] for [Item; INLINE] =? SmallVec); +#[cfg(feature = "equivalent")] +implementation!([const LENGTH: usize] for SmallVec =?+ [Other; LENGTH]); +#[cfg(feature = "equivalent")] +implementation!([const LENGTH: usize] for [Item; INLINE] =?+ SmallVec); +implementation!([const LENGTH: usize] for SmallVec =<> [Other; LENGTH]); +implementation!([const LENGTH: usize] for [Item; INLINE] =<> SmallVec); +#[cfg(feature = "equivalent")] +implementation!([const LENGTH: usize] for SmallVec =<>+ [Other; LENGTH]); +#[cfg(feature = "equivalent")] +implementation!([const LENGTH: usize] for [Item; INLINE] =<>+ SmallVec); + +implementation!([const LENGTH: usize] for SmallVec =? &[Other; LENGTH]); +implementation!([const LENGTH: usize] for &[Item; INLINE] =? SmallVec); +#[cfg(feature = "equivalent")] +implementation!([const LENGTH: usize] for SmallVec =?+ &[Other; LENGTH]); +#[cfg(feature = "equivalent")] +implementation!([const LENGTH: usize] for &[Item; INLINE] =?+ SmallVec); +implementation!([const LENGTH: usize] for SmallVec =<> &[Other; LENGTH]); +implementation!([const LENGTH: usize] for &[Item; INLINE] =<> SmallVec); +#[cfg(feature = "equivalent")] +implementation!([const LENGTH: usize] for SmallVec =<>+ &[Other; LENGTH]); +#[cfg(feature = "equivalent")] +implementation!([const LENGTH: usize] for &[Item; INLINE] =<>+ SmallVec); + +implementation!([const LENGTH: usize] for SmallVec =? &mut [Other; LENGTH]); +implementation!([const LENGTH: usize] for &mut [Item; INLINE] =? SmallVec); +#[cfg(feature = "equivalent")] +implementation!([const LENGTH: usize] for SmallVec =?+ &mut [Other; LENGTH]); +#[cfg(feature = "equivalent")] +implementation!([const LENGTH: usize] for &mut [Item; INLINE] =?+ SmallVec); +implementation!([const LENGTH: usize] for SmallVec =<> &mut [Other; LENGTH]); +implementation!([const LENGTH: usize] for &mut [Item; INLINE] =<> SmallVec); +#[cfg(feature = "equivalent")] +implementation!([const LENGTH: usize] for SmallVec =<>+ &mut [Other; LENGTH]); +#[cfg(feature = "equivalent")] +implementation!([const LENGTH: usize] for &mut [Item; INLINE] =<>+ SmallVec); + +implementation!([] for SmallVec =? [Other]); +implementation!([] for [Item] =? SmallVec); +#[cfg(feature = "equivalent")] +implementation!([] for SmallVec =?+ [Other]); +implementation!([] for SmallVec =<> [Other]); +implementation!([] for [Item] =<> SmallVec); +#[cfg(feature = "equivalent")] +implementation!([] for SmallVec =<>+ [Other]); + +implementation!([] for SmallVec =? &[Other]); +implementation!([] for &[Item] =? SmallVec); +#[cfg(feature = "equivalent")] +implementation!([] for SmallVec =?+ &[Other]); +#[cfg(feature = "equivalent")] +implementation!([] for &[Item] =?+ SmallVec); +implementation!([] for SmallVec =<> &[Other]); +implementation!([] for &[Item] =<> SmallVec); +#[cfg(feature = "equivalent")] +implementation!([] for SmallVec =<>+ &[Other]); +#[cfg(feature = "equivalent")] +implementation!([] for &[Item] =<>+ SmallVec); + +implementation!([] for SmallVec =? &mut [Other]); +implementation!([] for &mut [Item] =? SmallVec); +#[cfg(feature = "equivalent")] +implementation!([] for SmallVec =?+ &mut [Other]); +#[cfg(feature = "equivalent")] +implementation!([] for &mut [Item] =?+ SmallVec); +implementation!([] for SmallVec =<> &mut [Other]); +implementation!([] for &mut [Item] =<> SmallVec); +#[cfg(feature = "equivalent")] +implementation!([] for SmallVec =<>+ &mut [Other]); +#[cfg(feature = "equivalent")] +implementation!([] for &mut [Item] =<>+ SmallVec); + +implementation!([] for SmallVec =? Vec); +implementation!([] for Vec =? SmallVec); +#[cfg(feature = "equivalent")] +implementation!([] for SmallVec =?+ Vec); +#[cfg(feature = "equivalent")] +implementation!([] for Vec =?+ SmallVec); +implementation!([] for SmallVec =<> Vec); +implementation!([] for Vec =<> SmallVec); +#[cfg(feature = "equivalent")] +implementation!([] for SmallVec =<>+ Vec); +#[cfg(feature = "equivalent")] +implementation!([] for Vec =<>+ SmallVec); + +implementation!([] for SmallVec =? Cow<'_, [Other]> where Other: Clone); +implementation!([] for Cow<'_, [Item]> =? SmallVec where Item: Clone); +#[cfg(feature = "equivalent")] +implementation!([] for SmallVec =?+ Cow<'_, [Other]> where Other: Clone); +#[cfg(feature = "equivalent")] +implementation!([] for Cow<'_, [Item]> =?+ SmallVec where Item: Clone); +implementation!([] for SmallVec =<> Cow<'_, [Other]> where Other: Clone); +implementation!([] for Cow<'_, [Item]> =<> SmallVec where Item: Clone); +#[cfg(feature = "equivalent")] +implementation!([] for SmallVec =<>+ Cow<'_, [Other]> where Other: Clone); +#[cfg(feature = "equivalent")] +implementation!([] for Cow<'_, [Item]> =<>+ SmallVec where Item: Clone); + +impl, Other, const INLINE: usize, Heap: Allocator> + PartialEq> for VecDeque { #[inline] - fn eq(&self, other: &SmallVec) -> bool { - let other = other.as_ref(); - if self.len() != other.len() { + fn eq(&self, other: &SmallVec) -> bool { + let (first, second) = self.as_slices(); + let Some((before, after)) = other.split_at_checked(first.len()) else { return false; - } - let (sa, sb) = self.as_slices(); - let (oa, ob) = other[..].split_at(sa.len()); - sa == oa && sb == ob + }; + first == before && second == after } } - -impl Eq for SmallVec {} - -impl PartialOrd for SmallVec -where Item: PartialOrd +impl, Other, const INLINE: usize, Heap: Allocator> PartialEq> + for SmallVec { #[inline] - fn partial_cmp(&self, other: &SmallVec) -> Option { - self.as_ref().partial_cmp(other.as_ref()) + fn eq(&self, other: &VecDeque) -> bool { + let (first, second) = other.as_slices(); + let Some((before, after)) = self.split_at_checked(first.len()) else { + return false; + }; + before == first && after == second } } - -impl Ord for SmallVec -where Item: Ord +#[cfg(feature = "equivalent")] +impl, Other, const INLINE: usize, Heap: Allocator> + Equivalent> for VecDeque { #[inline] - fn cmp(&self, other: &SmallVec) -> Ordering { - self.as_ref().cmp(other.as_ref()) + fn equivalent(&self, key: &SmallVec) -> bool { + let (first, second) = self.as_slices(); + let Some((before, after)) = key.split_at_checked(first.len()) else { + return false; + }; + first.len() == before.len() + && first + .iter() + .zip(before) + .all(|(item, key)| item.equivalent(key)) + && second.len() == after.len() + && second + .iter() + .zip(after) + .all(|(item, key)| item.equivalent(key)) + } +} +#[cfg(feature = "equivalent")] +impl, Other, const INLINE: usize, Heap: Allocator> + Equivalent> for SmallVec +{ + #[inline] + fn equivalent(&self, key: &VecDeque) -> bool { + let (first, second) = key.as_slices(); + let Some((before, after)) = self.split_at_checked(first.len()) else { + return false; + }; + first.len() == before.len() + && first + .iter() + .zip(before) + .all(|(item, key)| key.equivalent(item)) + && second.len() == after.len() + && second + .iter() + .zip(after) + .all(|(item, key)| key.equivalent(item)) + } +} +impl, Other, const INLINE: usize, Heap: Allocator> + PartialOrd> for VecDeque +{ + #[inline] + fn partial_cmp(&self, other: &SmallVec) -> Option { + self.iter().partial_cmp(other.iter()) + } +} +impl, Other, const INLINE: usize, Heap: Allocator> + PartialOrd> for SmallVec +{ + #[inline] + fn partial_cmp(&self, other: &VecDeque) -> Option { + self.iter().partial_cmp(other.iter()) + } +} +#[cfg(feature = "equivalent")] +impl, Other, const INLINE: usize, Heap: Allocator> + Comparable> for VecDeque +{ + #[inline] + fn compare(&self, key: &SmallVec) -> Ordering { + let (first, second) = self.as_slices(); + first + .iter() + .chain(second.iter()) + .map(|item| item) + .zip(key.iter()) + .map(|(item, key)| item.compare(key)) + .find(|&ordering| ordering != Ordering::Equal) + .unwrap_or_else(|| self.len().cmp(&key.len())) + } +} +#[cfg(feature = "equivalent")] +impl, Other, const INLINE: usize, Heap: Allocator> + Comparable> for SmallVec +{ + #[inline] + fn compare(&self, key: &VecDeque) -> Ordering { + let (first, second) = key.as_slices(); + self.iter() + .zip(first.iter().chain(second.iter())) + .map(|(item, key)| item.compare(key)) + .find(|&ordering| ordering != Ordering::Equal) + .unwrap_or_else(|| self.len().cmp(&key.len())) } } diff --git a/src/lib.rs b/src/lib.rs index 7f094fb2..5dffb7fd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1833,17 +1833,6 @@ impl Debug for SmallVec equivalent::Equivalent<[Other]> - for SmallVec -where Item: equivalent::Equivalent -{ - fn equivalent(&self, key: &[Other]) -> bool { - self.len() == key.len() && self.iter().zip(key).all(|(item, key)| item.equivalent(key)) - } -} - #[cfg(feature = "zeroize")] impl Zeroize for SmallVec { fn zeroize(&mut self) {