From 8afd3266dac43c04c3fc29065a13c9c9a6a55afe Mon Sep 17 00:00:00 2001 From: Joe Hellerstein Date: Mon, 30 Sep 2024 12:37:25 -0700 Subject: [PATCH] feat: additions to variadics including collection types (#1473) adds a number of features: - collection types for variadics (sets, multisets) that allow search via RefVars (variadic of refs) - into_option (convert a variadic to a variadic of options) - into_vec (convert a variadic to a variadic of vecs) --- variadics/Cargo.toml | 1 + variadics/src/lib.rs | 382 ++++++++++++--- variadics/src/variadic_collections.rs | 648 ++++++++++++++++++++++++++ 3 files changed, 972 insertions(+), 59 deletions(-) create mode 100644 variadics/src/variadic_collections.rs diff --git a/variadics/Cargo.toml b/variadics/Cargo.toml index 0871e76a2134..182161686148 100644 --- a/variadics/Cargo.toml +++ b/variadics/Cargo.toml @@ -12,6 +12,7 @@ workspace = true [dependencies] sealed = "0.5.0" +hashbrown = "0.14.0" [dev-dependencies] trybuild = "1.0" diff --git a/variadics/src/lib.rs b/variadics/src/lib.rs index 548cbf1d153e..d812483f7991 100644 --- a/variadics/src/lib.rs +++ b/variadics/src/lib.rs @@ -11,6 +11,8 @@ //! ## [`var_args!`] #![doc = include_str!("../var_args.md")] +/// module of collection types for variadics +pub mod variadic_collections; use std::any::Any; use sealed::sealed; @@ -125,6 +127,18 @@ pub trait VariadicExt: Variadic { type Reverse: VariadicExt; /// Reverses this variadic value. fn reverse(self) -> Self::Reverse; + /// Reverses an AsRefVar variadic value + fn reverse_ref(this: Self::AsRefVar<'_>) -> ::AsRefVar<'_>; + + /// The length of this variadic type + fn len(&self) -> usize { + Self::LEN + } + + /// Checks if this variadic type is empty. + fn is_empty(&self) -> bool { + Self::LEN == 0 + } /// This as a variadic of references. type AsRefVar<'a>: RefVariadic< @@ -176,7 +190,18 @@ pub trait VariadicExt: Variadic { fn iter_any_mut(&mut self) -> Self::IterAnyMut<'_> where Self: 'static; + + /// type for all elements of the variadic being wrapped in Option + type IntoOption; + /// wrap all elements of the variadic in Option + fn into_option(self) -> Self::IntoOption; + + /// type for all elements of the variadic being wrapped in Vec + type IntoVec: VecVariadic + Default; + /// wrap all elements of the variadic in a Vec + fn into_singleton_vec(self) -> Self::IntoVec; } + #[sealed] impl VariadicExt for (Item, Rest) where @@ -198,6 +223,14 @@ where let (item, rest) = self; rest.reverse().extend((item, ())) } + fn reverse_ref(this: Self::AsRefVar<'_>) -> ::AsRefVar<'_> { + let (item, rest) = this; + let out = Rest::reverse_ref(rest).extend((item, ())); + // TODO!!! + let out2 = unsafe { std::mem::transmute_copy(&out) }; + std::mem::forget(out); + out2 + } type AsRefVar<'a> = (&'a Item, Rest::AsRefVar<'a>) where @@ -238,7 +271,20 @@ where let item: &mut dyn Any = item; std::iter::once(item).chain(rest.iter_any_mut()) } + + type IntoOption = (Option, Rest::IntoOption); + fn into_option(self) -> Self::IntoOption { + let var_args!(item, ...rest) = self; + var_expr!(Some(item), ...rest.into_option()) + } + + type IntoVec = (Vec, Rest::IntoVec); + fn into_singleton_vec(self) -> Self::IntoVec { + let var_args!(item, ...rest) = self; + var_expr!(vec!(item), ...rest.into_singleton_vec()) + } } + #[sealed] impl VariadicExt for () { const LEN: usize = 0; @@ -253,6 +299,7 @@ impl VariadicExt for () { type Reverse = (); fn reverse(self) -> Self::Reverse {} + fn reverse_ref(_this: Self::AsRefVar<'_>) -> ::AsRefVar<'_> {} type AsRefVar<'a> = (); fn as_ref_var(&self) -> Self::AsRefVar<'_> {} @@ -279,6 +326,12 @@ impl VariadicExt for () { { std::iter::empty() } + + type IntoOption = (); + fn into_option(self) -> Self::IntoOption {} + + type IntoVec = (); + fn into_singleton_vec(self) -> Self::IntoVec {} } /// A variadic of either shared references, exclusive references, or both. @@ -287,7 +340,7 @@ impl VariadicExt for () { /// /// This is a sealed trait. #[sealed] -pub trait EitherRefVariadic: Variadic { +pub trait EitherRefVariadic: VariadicExt { /// The un-referenced variadic. Each item will have one layer of shared references removed. /// /// The inverse of [`VariadicExt::AsRefVar`] and [`VariadicExt::AsMutVar`]. @@ -297,7 +350,7 @@ pub trait EitherRefVariadic: Variadic { /// let un_ref: ::UnRefVar = /// var_expr!(1_u32, "Hello".to_owned(), false); /// ``` - type UnRefVar: VariadicExt; + type UnRefVar: for<'a> VariadicExt; /// This type with all exclusive `&mut` references replaced with shared `&` references. /// @@ -319,6 +372,9 @@ pub trait EitherRefVariadic: Variadic { /// /// Conversion from `&` to `&mut` is generally invalid, so a `ref_to_mut()` method does not exist. type MutVar: MutVariadic; + + /// convert entries to ::AsRefVar + fn unref_ref(&self) -> ::AsRefVar<'_>; } #[sealed] impl<'a, Item, Rest> EitherRefVariadic for (&'a Item, Rest) @@ -334,6 +390,11 @@ where } type MutVar = (&'a mut Item, Rest::MutVar); + + fn unref_ref(&self) -> ::AsRefVar<'_> { + let var_args!(item, ...rest) = self; + var_expr!(item, ...rest.unref_ref()) + } } #[sealed] impl<'a, Item, Rest> EitherRefVariadic for (&'a mut Item, Rest) @@ -349,6 +410,11 @@ where } type MutVar = (&'a mut Item, Rest::MutVar); + + fn unref_ref(&self) -> ::AsRefVar<'_> { + let var_args!(item, ...rest) = self; + var_expr!(item, ...rest.unref_ref()) + } } #[sealed] impl EitherRefVariadic for () { @@ -358,6 +424,8 @@ impl EitherRefVariadic for () { fn mut_to_ref(self) -> Self::RefVar {} type MutVar = (); + + fn unref_ref(&self) -> ::AsRefVar<'_> {} } /// A variadic where each item is a shared reference `&item`. @@ -438,50 +506,39 @@ impl CopyRefVariadic for () { fn copy_var(&self) -> Self::UnRefVar {} } -/// Clone a variadic of references [`EitherRefVariadic`] into a variadic of owned values [`EitherRefVariadic::UnRefVar`]. +/// Clone a variadic of references [`AsRefVar`] into a variadic of owned values. /// /// ```rust /// # use variadics::*; /// let ref_var = var_expr!(&1, &format!("hello {}", "world"), &vec![1, 2, 3]); -/// let clone_var = ref_var.clone_var(); +/// let clone_var = CloneVariadic::clone_ref_var(ref_var); /// assert_eq!( /// var_expr!(1, "hello world".to_owned(), vec![1, 2, 3]), /// clone_var /// ); /// ``` #[sealed] -pub trait CloneRefVariadic: EitherRefVariadic { - /// Clone self per-value. - fn clone_var(&self) -> Self::UnRefVar; +pub trait CloneVariadic: VariadicExt + Clone { + /// Clone a variadic of references [`AsRefVar`] into a variadic of owned values. + fn clone_ref_var(this: Self::AsRefVar<'_>) -> Self; } #[sealed] -impl CloneRefVariadic for (&Item, Rest) +impl CloneVariadic for (Item, Rest) where Item: Clone, - Rest: CloneRefVariadic, + Rest: CloneVariadic, { - fn clone_var(&self) -> Self::UnRefVar { - let var_args!(item, ...rest) = self; - var_expr!((*item).clone(), ...rest.clone_var()) + fn clone_ref_var(this: Self::AsRefVar<'_>) -> Self { + let var_args!(item, ...rest) = this; + var_expr!(item.clone(), ...Rest::clone_ref_var(rest)) } } #[sealed] -impl CloneRefVariadic for (&mut Item, Rest) -where - Item: Clone, - Rest: CloneRefVariadic, -{ - fn clone_var(&self) -> Self::UnRefVar { - let var_args!(item, ...rest) = self; - var_expr!((*item).clone(), ...rest.clone_var()) - } -} -#[sealed] -impl CloneRefVariadic for () { - fn clone_var(&self) -> Self::UnRefVar {} +impl CloneVariadic for () { + fn clone_ref_var(_this: Self::AsRefVar<'_>) -> Self {} } -/// A variadic where all item implement `PartialEq`. +/// A variadic where all item implement [`PartialEq`]. #[sealed] pub trait PartialEqVariadic: VariadicExt { /// `PartialEq` between a referenced variadic and a variadic of references, of the same types. @@ -588,36 +645,218 @@ where /// /// This is a sealed trait. #[sealed] -pub trait Split: Variadic +pub trait Split: VariadicExt where - Prefix: Variadic, + Prefix: VariadicExt, { /// The second part when splitting this variadic by `Prefix`. - type Suffix: Variadic; + type Suffix: VariadicExt; /// Splits this variadic into two parts, first the `Prefix`, and second the `Suffix`. fn split(self) -> (Prefix, Self::Suffix); + /// Splits a refvar variadic + fn split_ref( + this: Self::AsRefVar<'_>, + ) -> ( + Prefix::AsRefVar<'_>, + ::AsRefVar<'_>, + ); } #[sealed] impl Split<(Item, PrefixRest)> for (Item, Rest) where - PrefixRest: Variadic, + PrefixRest: VariadicExt, Rest: Split, { + /// The second part when splitting this variadic by `Prefix`. type Suffix = >::Suffix; + /// Splits this variadic into two parts, first the `Prefix`, and second the `Suffix`. fn split(self) -> ((Item, PrefixRest), Self::Suffix) { let (item, rest) = self; let (prefix_rest, suffix) = rest.split(); ((item, prefix_rest), suffix) } + /// Splits a refvar variadic + fn split_ref( + this: Self::AsRefVar<'_>, + ) -> ( + <(Item, PrefixRest) as VariadicExt>::AsRefVar<'_>, + ::AsRefVar<'_>, + ) { + let (item, rest) = this; + let (prefix_rest, suffix) = Rest::split_ref(rest); + ((item, prefix_rest), suffix) + } } #[sealed] -impl Split<()> for Rest +impl Split for Rest where - Rest: Variadic, + Rest: VariadicExt, { type Suffix = Rest; - fn split(self) -> ((), Self::Suffix) { - ((), self) + fn split(self) -> (var_type!(), Self::Suffix) { + (var_expr!(), self) + } + fn split_ref( + this: Self::AsRefVar<'_>, + ) -> (var_type!(), ::AsRefVar<'_>) { + (var_expr!(), this) + } +} + +#[sealed] +/// Helper trait for splitting a variadic into two parts. `Prefix` is the first part, everything +/// after is the `Suffix` or second part. +/// +/// This is a sealed trait. +pub trait SplitBySuffix: VariadicExt +where + Suffix: VariadicExt, +{ + /// The first part when splitting this variadic by `Suffix`. + type Prefix: VariadicExt; + /// Splits this variadic into two parts, first the `Prefix`, and second the `Suffix`. + fn split_by_suffix(self) -> (Self::Prefix, Suffix); + /// Splits a refvar variadic + fn split_by_suffix_ref( + this: Self::AsRefVar<'_>, + ) -> ( + ::AsRefVar<'_>, + Suffix::AsRefVar<'_>, + ); +} +#[sealed] +impl SplitBySuffix for This +where + Suffix: VariadicExt, + This: VariadicExt, + This::Reverse: Split, + Suffix::Reverse: VariadicExt, +{ + /// The second part when splitting this variadic by `Prefix`. + type Prefix = <>::Suffix as VariadicExt>::Reverse; + /// Splits this variadic into two parts, first the `Prefix`, and second the `Suffix`. + fn split_by_suffix(self) -> (Self::Prefix, Suffix) { + let (rsuffix, rprefix) = self.reverse().split(); + (rprefix.reverse(), rsuffix.reverse()) + } + + fn split_by_suffix_ref( + this: Self::AsRefVar<'_>, + ) -> ( + ::AsRefVar<'_>, + Suffix::AsRefVar<'_>, + ) { + let rev = This::reverse_ref(this); + let (rsuffix, rprefix) = >::split_ref(rev); + let out = (rprefix.reverse(), rsuffix.reverse()); + // TODO!!!! + let out2 = unsafe { std::mem::transmute_copy(&out) }; + std::mem::forget(out); + out2 + } +} + +/// trait for Variadic of vecs, as formed by `VariadicExt::into_vec()` +#[sealed] +pub trait VecVariadic: VariadicExt { + /// Individual variadic items without the Vec wrapper + type UnVec: VariadicExt; + + /// zip across all the vecs in this VariadicVec + fn zip_vecs(&self) -> impl Iterator::AsRefVar<'_>>; + + /// append an unvec'ed Variadic into this VariadicVec + fn push(&mut self, item: Self::UnVec); + + /// get the unvec'ed Variadic at position `index` + fn get(&mut self, index: usize) -> Option<::AsRefVar<'_>>; + + /// result type from into_zip + type IntoZip: Iterator; + /// Turns into an iterator of items `UnVec` -- i.e. iterate through rows (not columns!). + fn into_zip(self) -> Self::IntoZip; + + /// result type from drain + type Drain<'a>: Iterator + where + Self: 'a; + /// Turns into a Drain of items `UnVec` -- i.e. iterate through rows (not columns!). + fn drain(&mut self, range: R) -> Self::Drain<'_> + where + R: std::ops::RangeBounds + Clone; +} + +#[sealed] +impl VecVariadic for (Vec, Rest) +where + Rest: VecVariadic, + // Item: 'static, + // Rest: 'static, +{ + type UnVec = var_type!(Item, ...Rest::UnVec); + + fn zip_vecs(&self) -> impl Iterator::AsRefVar<'_>> { + let (this, rest) = self; + std::iter::zip(this.iter(), rest.zip_vecs()) + } + + fn push(&mut self, row: Self::UnVec) { + let (this_vec, rest_vecs) = self; + let (this_col, rest_cols) = row; + this_vec.push(this_col); + rest_vecs.push(rest_cols); + } + + fn get(&mut self, index: usize) -> Option<::AsRefVar<'_>> { + let (this_vec, rest_vecs) = self; + if let Some(rest) = VecVariadic::get(rest_vecs, index) { + this_vec.get(index).map(|item| var_expr!(item, ...rest)) + } else { + None + } + } + + type IntoZip = std::iter::Zip, Rest::IntoZip>; + fn into_zip(self) -> Self::IntoZip { + let (this, rest) = self; + std::iter::zip(this, rest.into_zip()) + } + + type Drain<'a> = std::iter::Zip, Rest::Drain<'a>> where Self: 'a; + fn drain(&mut self, range: R) -> Self::Drain<'_> + where + R: std::ops::RangeBounds + Clone, + { + let (this, rest) = self; + std::iter::zip(this.drain(range.clone()), rest.drain(range)) + } +} + +#[sealed] +impl VecVariadic for var_type!() { + type UnVec = var_type!(); + + fn zip_vecs(&self) -> impl Iterator::AsRefVar<'_>> { + std::iter::repeat(var_expr!()) + } + + fn push(&mut self, _item: Self::UnVec) {} + + fn get(&mut self, _index: usize) -> Option<::AsRefVar<'_>> { + Some(()) + } + + type IntoZip = std::iter::Repeat; + fn into_zip(self) -> Self::IntoZip { + std::iter::repeat(var_expr!()) + } + + type Drain<'a> = std::iter::Repeat where Self: 'a; + fn drain(&mut self, _range: R) -> Self::Drain<'_> + where + R: std::ops::RangeBounds, + { + std::iter::repeat(var_expr!()) } } @@ -628,12 +867,13 @@ mod test { type MyList = var_type!(u8, u16, u32, u64); type MyPrefix = var_type!(u8, u16); - #[expect(dead_code, reason = "compilation test code")] type MySuffix = >::Suffix; + #[allow(dead_code)] const _: MySuffix = var_expr!(0_u32, 0_u64); #[test] + #[allow(clippy::let_unit_value)] fn test_basic_expr() { let _ = var_expr!(); let _ = var_expr!(1); @@ -644,7 +884,7 @@ mod test { variadic_trait! { /// Variaidic list of futures. - #[allow(clippy::allow_attributes, dead_code, reason = "compilation test code")] + #[allow(dead_code)] pub variadic FuturesList where F: std::future::Future {} } @@ -714,28 +954,52 @@ mod test { } #[test] - fn test_eq_ref_vec() { - type MyVar = var_type!(i32, bool, &'static str); - let vec: Vec = vec![ - var_expr!(0, true, "hello"), - var_expr!(1, true, "world"), - var_expr!(2, false, "goodnight"), - var_expr!(3, false, "moon"), - ]; - let needle: ::AsRefVar<'_> = - var_expr!(2, false, "goodnight").as_ref_var(); - assert_eq!( - Some(2), - vec.iter() - .position(|item| ::eq_ref(needle, item.as_ref_var())) - ); - - let missing: ::AsRefVar<'_> = - var_expr!(3, false, "goodnight").as_ref_var(); - assert_eq!( - None, - vec.iter() - .position(|item| ::eq_ref(missing, item.as_ref_var())) - ); + fn test_into_vec() { + use crate::VecVariadic; + + type Item = var_type!(i32, String); + let first: Item = var_expr!(1, "Joe".to_string()); + let second: Item = var_expr!(2, "Mingwei".to_string()); + let mut column_store = first.clone().into_singleton_vec(); + column_store.push(second.clone()); + assert_eq!(column_store.len(), 2); + assert_eq!(column_store.get(0).unwrap(), first.as_ref_var()); + assert_eq!(column_store.get(1).unwrap(), second.as_ref_var()); } } + +#[test] +fn test_eq_ref_vec() { + type MyVar = var_type!(i32, bool, &'static str); + let vec: Vec = vec![ + var_expr!(0, true, "hello"), + var_expr!(1, true, "world"), + var_expr!(2, false, "goodnight"), + var_expr!(3, false, "moon"), + ]; + let needle: ::AsRefVar<'_> = + var_expr!(2, false, "goodnight").as_ref_var(); + assert_eq!( + Some(2), + vec.iter() + .position(|item| ::eq_ref(needle, item.as_ref_var())) + ); + + let missing: ::AsRefVar<'_> = + var_expr!(3, false, "goodnight").as_ref_var(); + assert_eq!( + None, + vec.iter() + .position(|item| ::eq_ref(missing, item.as_ref_var())) + ); +} + +#[test] +fn clone_var_test() { + let ref_var = var_expr!(&1, &format!("hello {}", "world"), &vec![1, 2, 3]); + let clone_var = CloneVariadic::clone_ref_var(ref_var); + assert_eq!( + var_expr!(1, "hello world".to_owned(), vec![1, 2, 3]), + clone_var + ); +} diff --git a/variadics/src/variadic_collections.rs b/variadics/src/variadic_collections.rs new file mode 100644 index 000000000000..f4240423464b --- /dev/null +++ b/variadics/src/variadic_collections.rs @@ -0,0 +1,648 @@ +use std::fmt; +use std::hash::{BuildHasher, Hash, RandomState}; + +use hashbrown::hash_table::{Entry, HashTable}; + +use crate::{PartialEqVariadic, VariadicExt, VecVariadic}; + +/// Trait for a set of Variadic Tuples +pub trait VariadicCollection { + /// The Schema (aka Variadic type) associated with tuples in this set + type Schema: PartialEqVariadic; + + /// Insert an element into the set, return true if successful + fn insert(&mut self, element: Self::Schema) -> bool; + + /// Iterate over the elements of the set + fn iter(&self) -> impl Iterator::AsRefVar<'_>>; + + /// Return number of elements in the set + fn len(&self) -> usize; + + /// Return true if empty + fn is_empty(&self) -> bool; + + /// iterate and drain items from the set without deallocating the container + fn drain(&mut self) -> impl Iterator; + + /// Check for containment + fn contains(&self, value: ::AsRefVar<'_>) -> bool; +} + +/// trait for sets or multisets of variadics +pub trait VariadicSet: VariadicCollection {} + +/// HashSet that stores Variadics of owned values but allows +/// for lookups with RefVariadics as well +#[derive(Clone)] +pub struct VariadicHashSet { + table: HashTable, + hasher: S, +} + +impl VariadicHashSet { + /// Creates a new `VariadicHashSet` with a default hasher. + pub fn new() -> Self { + Self { + table: HashTable::new(), + hasher: RandomState::default(), + } + } +} + +impl Default for VariadicHashSet { + fn default() -> Self { + Self::new() + } +} + +impl fmt::Debug for VariadicHashSet +where + T: fmt::Debug + VariadicExt + PartialEqVariadic, + for<'a> T::AsRefVar<'a>: Hash + fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_set().entries(self.iter()).finish() + } +} + +impl VariadicHashSet +where + T: PartialEqVariadic, + for<'a> T::AsRefVar<'a>: Hash, + S: BuildHasher, +{ + /// given a RefVariadic lookup key, get a RefVariadic version of a tuple in the set + pub fn get<'a>(&'a self, ref_var: T::AsRefVar<'_>) -> Option<&'a T> { + let hash = self.hasher.hash_one(ref_var); + self.table.find(hash, |item| { + ::eq_ref(ref_var, item.as_ref_var()) + }) + } +} +impl VariadicCollection for VariadicHashSet +where + T: VariadicExt + PartialEqVariadic, + for<'a> T::AsRefVar<'a>: Hash, + S: BuildHasher, +{ + type Schema = T; + + fn insert(&mut self, element: T) -> bool { + // let hash = Self::get_hash(&self.hasher, element.as_ref_var()); + let hash = self.hasher.hash_one(element.as_ref_var()); + let entry = self.table.entry( + hash, + |item| ::eq(&element, item), + |item| self.hasher.hash_one(item.as_ref_var()), + ); + match entry { + Entry::Occupied(_occupied_entry) => false, + Entry::Vacant(vacant_entry) => { + vacant_entry.insert(element); + true + } + } + } + + fn len(&self) -> usize { + self.table.len() + } + + fn is_empty(&self) -> bool { + self.table.len() == 0 + } + + fn drain(&mut self) -> impl Iterator { + self.table.drain() + } + + fn contains(&self, value: ::AsRefVar<'_>) -> bool { + self.get(value).is_some() + } + + fn iter(&self) -> impl Iterator> { + self.table.iter().map(|item| item.as_ref_var()) + } +} +impl VariadicSet for VariadicHashSet +where + T: VariadicExt + PartialEqVariadic, + for<'a> T::AsRefVar<'a>: Hash, + S: BuildHasher, +{ +} + +impl IntoIterator for VariadicHashSet +where + T: VariadicExt + PartialEqVariadic, +{ + type Item = T; + type IntoIter = hashbrown::hash_table::IntoIter; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.table.into_iter() + } +} + +impl VariadicHashSet { + /// allocate a new VariadicHashSet with a specific hasher + pub fn with_hasher(hasher: S) -> Self { + Self { + table: HashTable::new(), + hasher, + } + } + /// allocate a new VariadicHashSet with a specific hasher and capacity + pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self { + Self { + table: HashTable::with_capacity(capacity), + hasher, + } + } +} + +// THIS CODE ADAPTED FROM hashbrown::HashMap +impl Extend for VariadicHashSet +where + K: Eq + Hash + PartialEqVariadic, + S: BuildHasher, + for<'a> K::AsRefVar<'a>: Hash, +{ + fn extend>(&mut self, iter: T) { + // Keys may be already present or show multiple times in the iterator. + // Reserve the entire hint lower bound if the map is empty. + // Otherwise reserve half the hint (rounded up), so the map + // will only resize twice in the worst case. + let iter = iter.into_iter(); + // let reserve = + if self.is_empty() { + iter.size_hint().0 + } else { + (iter.size_hint().0 + 1) / 2 + }; + // TODO figure out reserve! + // let hasher = self.hasher.build_hasher(); + // self.table.reserve(reserve, hasher); + iter.for_each(move |k| { + self.insert(k); + }); + } +} + +impl PartialEq for VariadicHashSet +where + T: Eq + Hash + PartialEqVariadic, + S: BuildHasher, + for<'a> T::AsRefVar<'a>: Hash, +{ + fn eq(&self, other: &Self) -> bool { + if self.len() != other.len() { + return false; + } + self.iter().all(|key| other.get(key).is_some()) + } +} + +impl FromIterator for VariadicHashSet +where + T: Eq + Hash + PartialEqVariadic, + S: BuildHasher + Default, + for<'a> T::AsRefVar<'a>: Hash, + // A: Default + Allocator, +{ + fn from_iter>(iter: I) -> Self { + let mut set = Self::with_hasher(Default::default()); + set.extend(iter); + set + } +} + +/// Trait for a multiset of Tuples +pub trait VariadicMultiset: VariadicCollection {} + +/// HashMap keyed on Variadics of (owned value, count) pairs, allows +/// for lookups with RefVariadics. +#[derive(Clone)] +pub struct VariadicCountedHashSet +where + K: VariadicExt, +{ + table: HashTable<(K, usize)>, + hasher: S, + len: usize, +} + +impl VariadicCountedHashSet +where + K: VariadicExt, +{ + /// Creates a new `VariadicCountedHashSet` with a default hasher. + pub fn new() -> Self { + Self { + table: HashTable::new(), + hasher: RandomState::default(), + len: 0, + } + } +} + +impl Default for VariadicCountedHashSet +where + K: VariadicExt, +{ + fn default() -> Self { + Self::new() + } +} + +impl fmt::Debug for VariadicCountedHashSet +where + K: fmt::Debug + VariadicExt + PartialEqVariadic, + for<'a> K::AsRefVar<'a>: Hash + fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_set().entries(self.table.iter()).finish() + } +} + +impl VariadicCountedHashSet +where + K: PartialEqVariadic, + for<'a> K::AsRefVar<'a>: Hash, + S: BuildHasher, +{ + /// given a RefVariadic lookup key, get a RefVariadic version of an entry in the map + pub fn get<'a>(&'a self, ref_var: K::AsRefVar<'_>) -> Option<&'a (K, usize)> { + let hash = self.hasher.hash_one(ref_var); + self.table.find(hash, |(key, _val)| { + ::eq_ref(ref_var, key.as_ref_var()) + }) + } +} + +impl VariadicCollection for VariadicCountedHashSet +where + K: VariadicExt + PartialEqVariadic + Hash + Clone, + for<'a> K::AsRefVar<'a>: Hash, + S: BuildHasher, +{ + type Schema = K; + + fn insert(&mut self, element: K) -> bool { + let hash = self.hasher.hash_one(element.as_ref_var()); + self.table + .entry( + hash, + |(item, _count)| ::eq(&element, item), + |(item, _count)| self.hasher.hash_one(item.as_ref_var()), + ) + .and_modify(|(_, count)| *count += 1) + .or_insert((element, 1)); + self.len += 1; + true + } + + fn len(&self) -> usize { + self.len + } + + fn is_empty(&self) -> bool { + self.len() == 0 + } + + fn drain(&mut self) -> impl Iterator { + // TODO: this shouldn't clone the last copy of each k! + // particularly bad when there's typically only 1 copy per item + self.len = 0; + self.table + .drain() + .flat_map(|(k, num)| (0..num).map(move |_i| k.clone())) + } + + fn contains(&self, value: ::AsRefVar<'_>) -> bool { + self.get(value).is_some() + } + + fn iter(&self) -> impl Iterator> { + self.table + .iter() + .flat_map(|(k, num)| (0..*num).map(move |_i| k.as_ref_var())) + } +} + +impl VariadicMultiset for VariadicCountedHashSet +where + K: VariadicExt + PartialEqVariadic + Hash + Clone, + for<'a> K::AsRefVar<'a>: Hash, + S: BuildHasher, +{ +} + +impl IntoIterator for VariadicCountedHashSet +where + T: VariadicExt + PartialEqVariadic + Clone, +{ + type Item = T; + type IntoIter = DuplicateCounted, T>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + DuplicateCounted { + iter: self.table.into_iter(), + state: None, + } + } +} + +/// Iterator helper for [`VariadicCountedHashSet::into_iter`]. +pub struct DuplicateCounted { + iter: Iter, + state: Option<(Item, usize)>, +} +impl Iterator for DuplicateCounted +where + Iter: Iterator, + Item: Clone, +{ + type Item = Item; + + fn next(&mut self) -> Option { + loop { + match self.state.take() { + Some((item, 1)) => { + self.state = None; + return Some(item); + } + None | Some((_, 0)) => match self.iter.next() { + Some(state) => self.state = Some(state), + None => return None, + }, + Some((item, many)) => { + let out = Some(item.clone()); + self.state = Some((item, many - 1)); + return out; + } + } + } + } +} + +impl VariadicCountedHashSet +where + K: VariadicExt, +{ + /// allocate a new VariadicCountedHashSet with a specific hasher + pub fn with_hasher(hasher: S) -> Self { + Self { + table: HashTable::new(), + hasher, + len: 0, + } + } + /// allocate a new VariadicCountedHashSet with a specific hasher and capacity + pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self { + Self { + table: HashTable::with_capacity(capacity), + hasher, + len: 0, + } + } +} + +// THIS CODE ADAPTED FROM hashbrown::HashTable +impl Extend for VariadicCountedHashSet +where + K: Eq + Hash + PartialEqVariadic + Clone, + S: BuildHasher, + for<'a> K::AsRefVar<'a>: Hash, +{ + fn extend>(&mut self, iter: T) { + // Keys may be already present or show multiple times in the iterator. + // Reserve the entire hint lower bound if the map is empty. + // Otherwise reserve half the hint (rounded up), so the map + // will only resize twice in the worst case. + let iter = iter.into_iter(); + // let reserve = + if self.is_empty() { + iter.size_hint().0 + } else { + (iter.size_hint().0 + 1) / 2 + }; + // TODO: get reserve to work here + // let hasher = self.hasher.build_hasher(); + // self.table.reserve(reserve, hasher); + iter.for_each(move |key| { + // TODO: super inefficient. Need a insert_with_count method + self.insert(key); + }); + } +} + +impl PartialEq for VariadicCountedHashSet +where + T: Eq + Hash + PartialEqVariadic + Clone, + S: BuildHasher, + for<'a> T::AsRefVar<'a>: Hash, +{ + fn eq(&self, other: &Self) -> bool { + if self.len() != other.len() { + return false; + } + + // let v: Vec<&(T, usize)> = + self.table.iter().all(|(key, count)| { + if let Some((_, match_val)) = other.get(key.as_ref_var()) { + match_val == count + } else { + false + } + }) + } +} + +impl FromIterator for VariadicCountedHashSet +where + T: Eq + Hash + PartialEqVariadic + Clone, + S: BuildHasher + Default, + for<'a> T::AsRefVar<'a>: Hash, +{ + fn from_iter>(iter: I) -> Self { + let mut set = Self::with_hasher(Default::default()); + set.extend(iter); + set + } +} + +/// Column storage for Variadic tuples of type Schema +/// An alternative to VariadicHashMultiset +pub struct VariadicColumnMultiset +where + Schema: VariadicExt, +{ + columns: Schema::IntoVec, + last_offset: usize, +} + +impl VariadicColumnMultiset +where + T: VariadicExt, +{ + /// initialize an empty columnar multiset + pub fn new() -> Self { + Self { + columns: ::default(), + last_offset: 0, + } + } +} + +impl Default for VariadicColumnMultiset +where + T: VariadicExt, +{ + fn default() -> Self { + Self::new() + } +} + +impl VariadicCollection for VariadicColumnMultiset +where + Schema: PartialEqVariadic, +{ + type Schema = Schema; + + fn insert(&mut self, element: Schema) -> bool { + if self.last_offset == 0 { + self.columns = element.into_singleton_vec() + } else { + self.columns.push(element); + } + self.last_offset += 1; + true + } + + fn iter(&self) -> impl Iterator::AsRefVar<'_>> { + self.columns.zip_vecs() + } + + fn len(&self) -> usize { + self.last_offset + } + + fn is_empty(&self) -> bool { + self.len() == 0 + } + + fn drain(&mut self) -> impl Iterator { + self.last_offset = 0; + self.columns.drain(0..) + } + + fn contains(&self, value: ::AsRefVar<'_>) -> bool { + self.iter() + .any(|t| ::eq_ref(t, value)) + } +} + +impl VariadicMultiset for VariadicColumnMultiset where Schema: PartialEqVariadic {} + +impl fmt::Debug for VariadicColumnMultiset +where + T: fmt::Debug + VariadicExt + PartialEqVariadic, + for<'a> T::AsRefVar<'a>: Hash + fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_set().entries(self.iter()).finish() + } +} + +impl IntoIterator for VariadicColumnMultiset +where + Schema: PartialEqVariadic, +{ + type Item = Schema; + type IntoIter = ::IntoZip; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.columns.into_zip() + } +} + +impl Extend for VariadicColumnMultiset +where + K: Eq + Hash + PartialEqVariadic, + for<'a> K::AsRefVar<'a>: Hash, +{ + // #[cfg_attr(feature = "inline-more", inline)] + fn extend>(&mut self, iter: T) { + let iter = iter.into_iter(); + // self.table.reserve(reserve, hasher); + iter.for_each(move |k| { + self.insert(k); + }); + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::{var_expr, var_type}; + + type TestSchema = var_type!(i16, i32, i64, &'static str); + + #[test] + fn test_collections() { + let test_data: Vec = vec![ + var_expr!(1, 1, 1, "hello"), + var_expr!(1, 1, 1, "hello"), + var_expr!(1, 1, 1, "world"), + var_expr!(1, 1, 2, "world"), + ]; + + let mut hash_set: VariadicHashSet = Default::default(); + hash_set.extend(test_data.clone()); + let mut multi_set: VariadicCountedHashSet = Default::default(); + let hash = multi_set + .hasher + .hash_one(var_expr!(1, 1, 1, "world").as_ref_var()); + let hash2 = multi_set + .hasher + .hash_one(var_expr!(1, 1, 1, "world").as_ref_var()); + assert_eq!(hash, hash2); + multi_set.extend(test_data.clone()); + let mut columnar: VariadicColumnMultiset = Default::default(); + columnar.extend(test_data.clone()); + + assert_eq!(multi_set.len(), 4); + assert_eq!(columnar.len(), 4); + assert_eq!(hash_set.len(), 3); + + hash_set.insert(var_expr!(1, 1, 1, "hello")); + hash_set.insert(var_expr!(2, 1, 1, "dup")); + hash_set.insert(var_expr!(2, 1, 1, "dup")); + multi_set.insert(var_expr!(1, 1, 1, "hello")); + multi_set.insert(var_expr!(2, 1, 1, "dup")); + multi_set.insert(var_expr!(2, 1, 1, "dup")); + columnar.insert(var_expr!(1, 1, 1, "hello")); + columnar.insert(var_expr!(2, 1, 1, "dup")); + columnar.insert(var_expr!(2, 1, 1, "dup")); + + assert_eq!(multi_set.len(), 7); + assert_eq!(columnar.len(), 7); + assert_eq!(hash_set.len(), 4); + + assert!(test_data.iter().all(|t| hash_set.contains(t.as_ref_var()))); + assert!(test_data.iter().all(|t| multi_set.contains(t.as_ref_var()))); + assert!(test_data.iter().all(|t| columnar.contains(t.as_ref_var()))); + + let _hs = hash_set.drain().collect::>(); + let _ms = multi_set.drain().collect::>(); + let _c = columnar.drain().collect::>(); + assert_eq!(hash_set.len(), 0); + assert_eq!(multi_set.len(), 0); + assert_eq!(columnar.len(), 0); + } +}