From 44ff5b54702a2f5421939bd841bd8609b363f8cb Mon Sep 17 00:00:00 2001 From: Moritz Hoffmann Date: Fri, 8 Nov 2024 12:46:35 +0100 Subject: [PATCH 1/5] wip Signed-off-by: Moritz Hoffmann --- README.md | 10 +- benches/bench.rs | 3 +- src/impls.rs | 18 +- src/impls/slice.rs | 362 +++++++++++++++++++++------------------ src/impls/slice_owned.rs | 282 +++++++++++++++++------------- src/impls/string.rs | 92 +++++----- src/impls/tuple.rs | 89 +++++----- src/impls/vec.rs | 91 +++++++--- src/lib.rs | 162 ++++++++++-------- tests/cow.rs | 3 +- tests/person.rs | 3 +- tests/recursive.rs | 3 +- 12 files changed, 645 insertions(+), 473 deletions(-) diff --git a/README.md b/README.md index c49ca46..0f5dda5 100644 --- a/README.md +++ b/README.md @@ -5,18 +5,18 @@ A flat container for Rust. ```toml [dependencies] -flatcontainer = "0.4" +flatcontainer = "0.6" ``` ## Example ```rust -use flatcontainer::FlatStack; +use flatcontainer::{Index, RegionPreference}; let r: Result<_, u16> = Ok("abc"); -let mut c = FlatStack::default_impl::>(); -c.copy(&r); -assert_eq!(r, c.get(0)); +let mut c = < as RegionPreference>::Region>::default(); +c.push(&r); +assert_eq!(r, c.index(0)); ``` ## Details diff --git a/benches/bench.rs b/benches/bench.rs index ba8cf73..d951bff 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -1,5 +1,5 @@ //! A simple benchmark for flatcontainer, adopted from `columnation`'s benchmark. - +/* use codspeed_bencher_compat::{benchmark_group, benchmark_main, Bencher}; use flatcontainer::impls::deduplicate::{CollapseSequence, ConsecutiveIndexPairs}; use flatcontainer::impls::index::IndexOptimized; @@ -524,3 +524,4 @@ benchmark_group!( vec_u_vn_s_realloc, ); benchmark_main!(clone, copy, copy_flat, copy_region, alloc); +*/ diff --git a/src/impls.rs b/src/impls.rs index 3dbf004..93b43ac 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -1,16 +1,16 @@ //! Various region implementations. -pub mod codec; -pub mod columns; -pub mod deduplicate; -pub mod huffman_container; -pub mod index; -pub mod mirror; -pub mod option; -pub mod result; +// pub mod codec; +// pub mod columns; +// pub mod deduplicate; +// pub mod huffman_container; +// pub mod index; +// pub mod mirror; +// pub mod option; +// pub mod result; pub mod slice; pub mod slice_owned; -pub mod storage; +// pub mod storage; pub mod string; pub mod tuple; mod vec; diff --git a/src/impls/slice.rs b/src/impls/slice.rs index 34dda42..4780cb1 100644 --- a/src/impls/slice.rs +++ b/src/impls/slice.rs @@ -7,8 +7,10 @@ use std::ops::{Deref, Range}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use crate::impls::index::IndexContainer; -use crate::{IntoOwned, Push, Region, RegionPreference, ReserveItems}; +use crate::{ + Clear, HeapSize, Index, IndexAs, IntoOwned, Len, Push, Region, RegionPreference, Reserve, + ReserveItems, +}; impl RegionPreference for Vec { type Owned = Vec; @@ -25,6 +27,8 @@ impl RegionPreference for [T; N] { type Region = SliceRegion; } +type Idx = u64; + /// A container representing slices of data. /// /// Reading from this region is more involved than for others, because the data only exists in @@ -36,7 +40,7 @@ impl RegionPreference for [T; N] { /// /// We fill some data into a slice region and use the [`ReadSlice`] to extract it later. /// ``` -/// use flatcontainer::{RegionPreference, Push, Region, SliceRegion}; +/// use flatcontainer::{RegionPreference, Push, Region, SliceRegion, Index}; /// let mut r = ::Region>>::default(); /// /// let panagram_en = "The quick fox jumps over the lazy dog" @@ -46,88 +50,123 @@ impl RegionPreference for [T; N] { /// .split(" ") /// .collect::>(); /// -/// let en_index = r.push(&panagram_en); -/// let de_index = r.push(&panagram_de); +/// r.push(&panagram_en); +/// r.push(&panagram_de); /// -/// assert!(panagram_de.into_iter().eq(r.index(de_index))); -/// assert!(panagram_en.into_iter().eq(r.index(en_index))); +/// assert!(panagram_de.into_iter().eq(r.index(0))); +/// assert!(panagram_en.into_iter().eq(r.index(1))); /// -/// assert_eq!(r.index(de_index).get(2), "jagen"); +/// assert_eq!(r.index(1).get(2), "jagen"); /// ``` #[derive(Debug)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct SliceRegion::Index>> { - /// Container of slices. - slices: O, +pub struct SliceRegion> { + /// Container of bounds. + bounds: B, /// Inner region. inner: R, } impl Clone for SliceRegion where - R: Region + Clone, + R: Clone, O: Clone, { fn clone(&self) -> Self { Self { - slices: self.slices.clone(), + bounds: self.bounds.clone(), inner: self.inner.clone(), } } fn clone_from(&mut self, source: &Self) { - self.slices.clone_from(&source.slices); + self.bounds.clone_from(&source.bounds); self.inner.clone_from(&source.inner); } } -impl> Region for SliceRegion { - type Owned = Vec; - type ReadItem<'a> = ReadSlice<'a, R, O> where Self: 'a; - type Index = (usize, usize); - +impl Region for SliceRegion { #[inline] fn merge_regions<'a>(regions: impl Iterator + Clone) -> Self where Self: 'a, { Self { - slices: O::default(), + bounds: B::merge_regions(regions.clone().map(|r| &r.bounds)), inner: R::merge_regions(regions.map(|r| &r.inner)), } } - #[inline] - fn index(&self, (start, end): Self::Index) -> Self::ReadItem<'_> { - ReadSlice(Ok(ReadSliceInner { - region: self, - start, - end, - })) - } - #[inline] fn reserve_regions<'a, I>(&mut self, regions: I) where Self: 'a, I: Iterator + Clone, { - self.slices - .reserve(regions.clone().map(|r| r.slices.len()).sum()); + self.bounds + .reserve_regions(regions.clone().map(|r| &r.bounds)); self.inner.reserve_regions(regions.map(|r| &r.inner)); } +} +impl Len for SliceRegion +where + B: Len, +{ + #[inline] + fn len(&self) -> usize { + self.bounds.len() + } +} + +impl Clear for SliceRegion +where + R: Clear, + B: Clear, +{ #[inline] fn clear(&mut self) { - self.slices.clear(); + self.bounds.clear(); self.inner.clear(); } - +} +impl HeapSize for SliceRegion +where + R: HeapSize, + B: HeapSize, +{ #[inline] fn heap_size(&self, mut callback: F) { - self.slices.heap_size(&mut callback); + self.bounds.heap_size(&mut callback); self.inner.heap_size(callback); } +} + +impl Index for SliceRegion +where + R: Index, + B: IndexAs, +{ + type Owned = Vec; + + type ReadItem<'a> = ReadSlice<'a, R, B> where Self: 'a; + #[inline] + fn index(&self, index: usize) -> Self::ReadItem<'_> { + let start = if index == 0 { + 0 + } else { + self.bounds + .index_as(index - 1) + .try_into() + .expect("must fit") + }; + let end = self.bounds.index_as(index).try_into().expect("must fit"); + ReadSlice(Ok(ReadSliceInner { + region: self, + start, + end, + })) + } #[inline] fn reborrow<'b, 'a: 'b>(item: Self::ReadItem<'a>) -> Self::ReadItem<'b> @@ -138,22 +177,20 @@ impl> Region for SliceRegion { } } -impl> Default for SliceRegion { +impl Default for SliceRegion { #[inline] fn default() -> Self { Self { - slices: O::default(), + bounds: B::default(), inner: R::default(), } } } /// A helper to read data out of a slice region. -pub struct ReadSlice<'a, R: Region, O: IndexContainer = Vec<::Index>>( - Result, &'a [R::Owned]>, -); +pub struct ReadSlice<'a, R: Index, B>(Result, &'a [R::Owned]>); -impl> ReadSlice<'_, R, O> { +impl> ReadSlice<'_, R, B> { /// Read the n-th item from the underlying region. /// /// # Panics @@ -194,7 +231,7 @@ impl> ReadSlice<'_, R, O> { } } -impl> PartialEq for ReadSlice<'_, R, O> +impl> PartialEq for ReadSlice<'_, R, B> where for<'a> R::ReadItem<'a>: PartialEq, { @@ -203,12 +240,9 @@ where } } -impl> Eq for ReadSlice<'_, R, O> where - for<'a> R::ReadItem<'a>: Eq -{ -} +impl> Eq for ReadSlice<'_, R, B> where for<'a> R::ReadItem<'a>: Eq {} -impl> PartialOrd for ReadSlice<'_, R, O> +impl> PartialOrd for ReadSlice<'_, R, O> where for<'a> R::ReadItem<'a>: PartialOrd, { @@ -217,7 +251,7 @@ where } } -impl> Ord for ReadSlice<'_, R, O> +impl> Ord for ReadSlice<'_, R, O> where for<'a> R::ReadItem<'a>: Ord, { @@ -226,13 +260,13 @@ where } } -struct ReadSliceInner<'a, R: Region, O: IndexContainer = Vec<::Index>> { +struct ReadSliceInner<'a, R, O> { region: &'a SliceRegion, start: usize, end: usize, } -impl> ReadSliceInner<'_, R, O> { +impl> ReadSliceInner<'_, R, O> { /// Read the n-th item from the underlying region. /// /// # Panics @@ -249,9 +283,7 @@ impl> ReadSliceInner<'_, R, O> { self.start, self.end ); - self.region - .inner - .index(self.region.slices.index(self.start + index)) + self.region.inner.index(self.start + index) } /// The number of elements in this slice. @@ -267,7 +299,7 @@ impl> ReadSliceInner<'_, R, O> { } } -impl> Debug for ReadSlice<'_, R, O> +impl> Debug for ReadSlice<'_, R, O> where for<'a> R::ReadItem<'a>: Debug, { @@ -276,27 +308,27 @@ where } } -impl> Clone for ReadSlice<'_, R, O> { +impl> Clone for ReadSlice<'_, R, O> { #[inline] fn clone(&self) -> Self { *self } } -impl> Clone for ReadSliceInner<'_, R, O> { +impl> Clone for ReadSliceInner<'_, R, O> { #[inline] fn clone(&self) -> Self { *self } } -impl> Copy for ReadSlice<'_, R, O> {} -impl> Copy for ReadSliceInner<'_, R, O> {} +impl> Copy for ReadSlice<'_, R, O> {} +impl> Copy for ReadSliceInner<'_, R, O> {} impl<'a, R, O> IntoOwned<'a> for ReadSlice<'a, R, O> where - R: Region, - O: IndexContainer, + R: Index, + O: IndexAs, { type Owned = Vec; @@ -321,7 +353,7 @@ where } } -impl<'a, R: Region, O: IndexContainer> IntoIterator for ReadSlice<'a, R, O> { +impl<'a, R: Index, O: IndexAs> IntoIterator for ReadSlice<'a, R, O> { type Item = R::ReadItem<'a>; type IntoIter = ReadSliceIter<'a, R, O>; @@ -338,11 +370,11 @@ impl<'a, R: Region, O: IndexContainer> IntoIterator for ReadSlice<'a, /// An iterator over the items read from a slice region. #[derive(Debug)] -pub struct ReadSliceIter<'a, C: Region, O: IndexContainer>( +pub struct ReadSliceIter<'a, C: Index, O: IndexAs>( Result, std::slice::Iter<'a, C::Owned>>, ); -impl<'a, C: Region, O: IndexContainer> Clone for ReadSliceIter<'a, C, O> { +impl<'a, C: Index, O: IndexAs> Clone for ReadSliceIter<'a, C, O> { #[inline] fn clone(&self) -> Self { Self(self.0.clone()) @@ -351,19 +383,16 @@ impl<'a, C: Region, O: IndexContainer> Clone for ReadSliceIter<'a, C, /// An iterator over the items read from a slice region. #[derive(Debug)] -pub struct ReadSliceIterInner<'a, C: Region, O: IndexContainer>( - &'a SliceRegion, - Range, -); +pub struct ReadSliceIterInner<'a, C: Index, O: IndexAs>(&'a SliceRegion, Range); -impl<'a, C: Region, O: IndexContainer> Clone for ReadSliceIterInner<'a, C, O> { +impl<'a, C: Index, O: IndexAs> Clone for ReadSliceIterInner<'a, C, O> { #[inline] fn clone(&self) -> Self { Self(self.0, self.1.clone()) } } -impl<'a, C: Region, O: IndexContainer> Iterator for ReadSliceIter<'a, C, O> { +impl<'a, C: Index, O: IndexAs> Iterator for ReadSliceIter<'a, C, O> { type Item = C::ReadItem<'a>; #[inline] @@ -377,100 +406,101 @@ impl<'a, C: Region, O: IndexContainer> Iterator for ReadSliceIter<'a, impl<'a, R, O> ExactSizeIterator for ReadSliceIter<'a, R, O> where - R: Region, - O: IndexContainer, + R: Index, + O: IndexAs, std::slice::Iter<'a, R::Owned>: ExactSizeIterator, ReadSliceIterInner<'a, R, O>: ExactSizeIterator, { } -impl<'a, C: Region, O: IndexContainer> Iterator for ReadSliceIterInner<'a, C, O> { +impl<'a, C: Index, O: IndexAs> Iterator for ReadSliceIterInner<'a, C, O> { type Item = C::ReadItem<'a>; #[inline] fn next(&mut self) -> Option { - self.1 - .next() - .map(|idx| self.0.inner.index(self.0.slices.index(idx))) + self.1.next().map(|idx| self.0.inner.index(idx)) } } impl<'a, R, O> ExactSizeIterator for ReadSliceIterInner<'a, R, O> where - R: Region, - O: IndexContainer, + R: Index, + O: IndexAs, Range: ExactSizeIterator, { } -impl<'a, C, T, O> Push<&'a [T]> for SliceRegion +impl<'a, C, T, B> Push<&'a [T]> for SliceRegion where - C: Region + Push<&'a T>, - O: IndexContainer, + C: Push<&'a T> + Len, + B: IndexAs + Push, { #[inline] - fn push(&mut self, item: &'a [T]) -> as Region>::Index { - let start = self.slices.len(); - self.slices.extend(item.iter().map(|t| self.inner.push(t))); - (start, self.slices.len()) + fn push(&mut self, items: &'a [T]) { + for item in items.iter() { + self.inner.push(item); + } + self.bounds + .push(self.inner.len().try_into().expect("must fit")); } } impl<'a, T, R, O> ReserveItems<&'a [T]> for SliceRegion where - R: Region + ReserveItems<&'a T>, - O: IndexContainer, + R: ReserveItems<&'a T>, + O: Reserve, { #[inline] fn reserve_items(&mut self, items: I) where I: Iterator + Clone, { - self.slices.reserve(items.clone().map(<[T]>::len).sum()); + self.bounds.reserve(1); self.inner.reserve_items(items.flatten()); } } impl Push> for SliceRegion where - C: Region + Push, - O: IndexContainer, + C: Push + Len, + O: IndexAs + Push, { #[inline] - fn push(&mut self, item: Vec) -> as Region>::Index { - let start = self.slices.len(); - self.slices - .extend(item.into_iter().map(|t| self.inner.push(t))); - (start, self.slices.len()) + fn push(&mut self, items: Vec) { + for item in items { + self.inner.push(item); + } + self.bounds + .push(self.inner.len().try_into().expect("must fit")); } } impl Push<&Vec> for SliceRegion where - for<'a> C: Region + Push<&'a T>, - O: IndexContainer, + C: for<'a> Push<&'a T> + Len, + O: Push + IndexAs, { #[inline] - fn push(&mut self, item: &Vec) -> as Region>::Index { + fn push(&mut self, item: &Vec) { self.push(item.as_slice()) } } impl<'a, C, T, O> Push<&&'a Vec> for SliceRegion where - C: Region + Push<&'a T>, - O: IndexContainer, + C: Push<&'a T> + Len, + O: Push + IndexAs, { #[inline] - fn push(&mut self, item: &&'a Vec) -> as Region>::Index { + fn push(&mut self, item: &&'a Vec) { self.push(item.as_slice()) } } impl<'a, T, R, O> ReserveItems<&'a Vec> for SliceRegion where - for<'b> R: Region + ReserveItems<&'b T>, - O: IndexContainer, + R: ReserveItems<&'a T>, + O: Reserve, { #[inline] fn reserve_items(&mut self, items: I) @@ -481,22 +511,21 @@ where } } -impl<'a, C, O> Push> for SliceRegion +impl<'a, C, B> Push> for SliceRegion where - C: Region + Push<::ReadItem<'a>>, - O: IndexContainer, + C: Index + Push<::ReadItem<'a>> + Len, + B: IndexAs + Push, { #[inline] - fn push(&mut self, item: ReadSlice<'a, C, O>) -> as Region>::Index { + fn push(&mut self, item: ReadSlice<'a, C, B>) { match item.0 { Ok(inner) => self.push(inner), Err(slice) => { - let start_len = self.slices.len(); for item in slice.iter().map(IntoOwned::borrow_as) { - let index = self.inner.push(item); - self.slices.push(index); + self.inner.push(item); } - (start_len, self.slices.len()) + self.bounds + .push(self.inner.len().try_into().expect("must fit")); } } } @@ -504,59 +533,61 @@ where impl<'a, C, O> Push> for SliceRegion where - C: Region + Push<::ReadItem<'a>>, - O: IndexContainer, + C: Index + Push<::ReadItem<'a>> + Len, + O: IndexAs + Push, { #[inline] - fn push(&mut self, item: ReadSliceInner<'a, C, O>) -> as Region>::Index { + fn push(&mut self, item: ReadSliceInner<'a, C, O>) { let ReadSliceInner { region, start, end } = item; - let start_len = self.slices.len(); for index in start..end { - let index = region.slices.index(index); - let index = self.inner.push(region.inner.index(index)); - self.slices.push(index); + self.inner.push(region.inner.index(index)); } - (start_len, self.slices.len()) + self.bounds + .push(self.inner.len().try_into().expect("must fit")); } } impl Push<[T; N]> for SliceRegion where - for<'a> R: Region + Push<&'a T>, - O: IndexContainer, + for<'a> R: Push + Len, + O: IndexAs + Push, { #[inline] - fn push(&mut self, item: [T; N]) -> as Region>::Index { - self.push(item.as_slice()) + fn push(&mut self, items: [T; N]) { + for item in items { + self.inner.push(item); + } + self.bounds + .push(self.inner.len().try_into().expect("must fit")); } } impl<'a, T, R, O, const N: usize> Push<&'a [T; N]> for SliceRegion where - R: Region + Push<&'a T>, - O: IndexContainer, + R: Push<&'a T> + Len, + O: Push + IndexAs, { #[inline] - fn push(&mut self, item: &'a [T; N]) -> as Region>::Index { + fn push(&mut self, item: &'a [T; N]) { self.push(item.as_slice()) } } impl<'a, T, R, O, const N: usize> Push<&&'a [T; N]> for SliceRegion where - R: Region + Push<&'a T>, - O: IndexContainer, + R: Push<&'a T> + Len, + O: Push + IndexAs, { #[inline] - fn push(&mut self, item: &&'a [T; N]) -> as Region>::Index { + fn push(&mut self, item: &&'a [T; N]) { self.push(item.as_slice()) } } impl<'a, T, R, O, const N: usize> ReserveItems<&'a [T; N]> for SliceRegion where - R: Region + ReserveItems<&'a T>, - O: IndexContainer, + R: ReserveItems<&'a T>, + O: Reserve, { fn reserve_items(&mut self, items: I) where @@ -568,15 +599,14 @@ where impl<'a, R, O> ReserveItems> for SliceRegion where - R: Region + ReserveItems<::ReadItem<'a>> + 'a, - O: IndexContainer, + R: Index + ReserveItems<::ReadItem<'a>> + 'a, + O: Reserve + IndexAs, { fn reserve_items(&mut self, items: I) where I: Iterator> + Clone, { - self.slices - .reserve(items.clone().map(|read_slice| read_slice.len()).sum()); + self.bounds.reserve(1); self.inner.reserve_items(items.flatten()); } } @@ -584,19 +614,19 @@ where #[cfg(test)] mod tests { use super::*; - use crate::{MirrorRegion, Push, Region}; + use crate::{Index, Push}; #[test] fn read_slice() { let s = [1, 2, 3, 4]; - let mut r = >>::default(); + let mut r = >>::default(); - let index = r.push(s); + r.push(s); - assert!(s.iter().copied().eq(r.index(index).iter())); + assert!(s.iter().eq(r.index(0).iter())); - let index = r.push(s); - let slice = r.index(index); + r.push(s); + let slice = r.index(1); assert_eq!(s.len(), slice.len()); assert!(!slice.is_empty()); assert_eq!(s.get(0), Some(&1)); @@ -604,8 +634,8 @@ mod tests { assert_eq!(s.get(2), Some(&3)); assert_eq!(s.get(3), Some(&4)); - let index = <_ as Push<[u8; 0]>>::push(&mut r, []); - let slice = r.index(index); + <_ as Push<[u8; 0]>>::push(&mut r, []); + let slice = r.index(2); assert_eq!(0, slice.len()); assert!(slice.is_empty()); } @@ -613,83 +643,83 @@ mod tests { #[test] #[should_panic] fn test_get_out_of_bounds() { - let mut r = >>::default(); - let index = r.push([1; 4]); + let mut r = >>::default(); + r.push([1; 4]); // Index 4 is out of bounds and expected to panic. - let _ = r.index(index).get(4); + let _ = r.index(0).get(4); } #[test] fn test_read_slice_debug() { - let mut r = >>::default(); - let index = r.push([1; 4]); + let mut r = >>::default(); + r.push([1; 4]); - assert_eq!("[1, 1, 1, 1]", format!("{:?}", r.index(index))); + assert_eq!("[1, 1, 1, 1]", format!("{:?}", r.index(0))); } #[test] fn test_read_slice_clone() { - let mut r = >>::default(); - let index = r.push([1; 4]); + let mut r = >>::default(); + r.push([1; 4]); - assert_eq!("[1, 1, 1, 1]", format!("{:?}", r.index(index).clone())); + assert_eq!("[1, 1, 1, 1]", format!("{:?}", r.index(0).clone())); } #[test] fn test_read_slice_eq() { - let mut r = >>::default(); - let index = r.push([1; 4]); + let mut r = >>::default(); + r.push([1; 4]); assert_eq!( as IntoOwned>::borrow_as(&vec![1; 4]), - r.index(index) + r.index(0) ); assert_ne!( as IntoOwned>::borrow_as(&vec![0; 4]), - r.index(index) + r.index(0) ); assert_ne!( as IntoOwned>::borrow_as(&vec![1; 5]), - r.index(index) + r.index(0) ); } #[test] fn test_read_slice_cmp() { - let mut r = >>::default(); - let index = r.push([1; 4]); + let mut r = >>::default(); + r.push([1; 4]); assert_eq!( Ordering::Less, - as IntoOwned>::borrow_as(&vec![0; 4]).cmp(&r.index(index)) + as IntoOwned>::borrow_as(&vec![0; 4]).cmp(&r.index(0)) ); assert_eq!( Ordering::Equal, - as IntoOwned>::borrow_as(&vec![1; 4]).cmp(&r.index(index)) + as IntoOwned>::borrow_as(&vec![1; 4]).cmp(&r.index(0)) ); assert_eq!( Ordering::Greater, - as IntoOwned>::borrow_as(&vec![2; 4]).cmp(&r.index(index)) + as IntoOwned>::borrow_as(&vec![2; 4]).cmp(&r.index(0)) ); assert_eq!( Ordering::Less, - as IntoOwned>::borrow_as(&vec![1; 3]).cmp(&r.index(index)) + as IntoOwned>::borrow_as(&vec![1; 3]).cmp(&r.index(0)) ); assert_eq!( Ordering::Equal, - as IntoOwned>::borrow_as(&vec![1; 4]).cmp(&r.index(index)) + as IntoOwned>::borrow_as(&vec![1; 4]).cmp(&r.index(0)) ); assert_eq!( Ordering::Greater, - as IntoOwned>::borrow_as(&vec![1; 5]).cmp(&r.index(index)) + as IntoOwned>::borrow_as(&vec![1; 5]).cmp(&r.index(0)) ); } #[test] fn test_reserve_ref_slice() { - let mut r = >>::default(); + let mut r = >>::default(); r.reserve_items(std::iter::once([1; 4].as_slice())); let mut cap = 0; r.heap_size(|_, ca| { @@ -700,7 +730,7 @@ mod tests { #[test] fn test_reserve_ref_vec() { - let mut r = >>::default(); + let mut r = >>::default(); r.reserve_items(std::iter::once(&vec![1; 4])); let mut cap = 0; r.heap_size(|_, ca| { @@ -711,7 +741,7 @@ mod tests { #[test] fn test_reserve_ref_array() { - let mut r = >>::default(); + let mut r = >>::default(); r.reserve_items(std::iter::once(&[1; 4])); let mut cap = 0; r.heap_size(|_, ca| { diff --git a/src/impls/slice_owned.rs b/src/impls/slice_owned.rs index 209e0e0..3e34f60 100644 --- a/src/impls/slice_owned.rs +++ b/src/impls/slice_owned.rs @@ -5,8 +5,10 @@ use std::marker::PhantomData; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use crate::impls::storage::{PushStorage, Storage}; -use crate::{Push, PushIter, Region, ReserveItems}; +// use crate::impls::storage::{PushStorage, Storage}; +use crate::{Clear, HeapSize, Index, IndexAs, Len, Push, PushIter, Region, Reserve, ReserveItems}; + +type Idx = u64; /// A container for owned types. /// @@ -18,80 +20,142 @@ use crate::{Push, PushIter, Region, ReserveItems}; /// # Examples /// /// ``` -/// use flatcontainer::{Push, OwnedRegion, Region}; +/// use flatcontainer::{Push, OwnedRegion, Region, Index}; /// let mut r = >::default(); /// /// let panagram_en = "The quick fox jumps over the lazy dog"; /// let panagram_de = "Zwölf Boxkämpfer jagen Viktor quer über den großen Sylter Deich"; /// -/// let en_index = r.push(panagram_en.as_bytes()); -/// let de_index = r.push(panagram_de.as_bytes()); +/// r.push(panagram_en.as_bytes()); +/// r.push(panagram_de.as_bytes()); /// -/// assert_eq!(panagram_de.as_bytes(), r.index(de_index)); -/// assert_eq!(panagram_en.as_bytes(), r.index(en_index)); +/// assert_eq!(panagram_en.as_bytes(), r.index(0)); +/// assert_eq!(panagram_de.as_bytes(), r.index(1)); /// ``` #[derive(Debug)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct OwnedRegion> { +pub struct OwnedRegion, B = Vec> { slices: S, + bounds: B, _marker: PhantomData, } -impl Clone for OwnedRegion { +impl Clone for OwnedRegion { fn clone(&self) -> Self { Self { slices: self.slices.clone(), + bounds: self.bounds.clone(), _marker: PhantomData, } } fn clone_from(&mut self, source: &Self) { self.slices.clone_from(&source.slices); + self.bounds.clone_from(&source.bounds); } } -impl Region for OwnedRegion +impl Region for OwnedRegion where [T]: ToOwned, - S: Storage + std::ops::Index, Output = [T]>, + S: Region + std::ops::Index, Output = [T]>, + B: Region, { - type Owned = <[T] as ToOwned>::Owned; - type ReadItem<'a> = &'a [T] where Self: 'a; - type Index = (usize, usize); - #[inline] fn merge_regions<'a>(regions: impl Iterator + Clone) -> Self where Self: 'a, { Self { - slices: S::merge_regions(regions.map(|r| &r.slices)), + slices: S::merge_regions(regions.clone().map(|r| &r.slices)), + bounds: B::merge_regions(regions.map(|r| &r.bounds)), _marker: PhantomData, } } - #[inline] - fn index(&self, (start, end): Self::Index) -> Self::ReadItem<'_> { - &self.slices[start..end] - } - #[inline] fn reserve_regions<'a, I>(&mut self, regions: I) where Self: 'a, I: Iterator + Clone, { - self.slices.reserve_regions(regions.map(|r| &r.slices)); + self.slices + .reserve_regions(regions.clone().map(|r| &r.slices)); + self.bounds.reserve_regions(regions.map(|r| &r.bounds)); + } +} + +impl Default for OwnedRegion { + #[inline] + fn default() -> Self { + Self { + slices: S::default(), + bounds: B::default(), + _marker: PhantomData, + } } +} +impl HeapSize for OwnedRegion +where + S: HeapSize, + B: HeapSize, +{ + #[inline] + fn heap_size(&self, mut callback: F) { + self.slices.heap_size(&mut callback); + self.bounds.heap_size(&mut callback); + } +} + +impl Clear for OwnedRegion +where + S: Clear, + B: Clear, +{ #[inline] fn clear(&mut self) { self.slices.clear(); + self.bounds.clear(); } +} +impl Len for OwnedRegion +where + B: Len, +{ #[inline] - fn heap_size(&self, callback: F) { - self.slices.heap_size(callback); + fn len(&self) -> usize { + self.bounds.len() + } + + #[inline] + fn is_empty(&self) -> bool { + self.bounds.is_empty() + } +} + +impl Index for OwnedRegion +where + [T]: ToOwned, + S: std::ops::Index, Output = [T]>, + B: IndexAs, +{ + type Owned = <[T] as ToOwned>::Owned; + type ReadItem<'a> = &'a [T] where Self: 'a; + + #[inline] + fn index(&self, index: usize) -> Self::ReadItem<'_> { + let start = if index == 0 { + 0 + } else { + self.bounds + .index_as(index - 1) + .try_into() + .expect("must fit") + }; + let end = self.bounds.index_as(index).try_into().expect("must fit"); + &self.slices[start..end] } #[inline] @@ -103,61 +167,46 @@ where } } -impl> Default for OwnedRegion { - #[inline] - fn default() -> Self { - Self { - slices: S::default(), - _marker: PhantomData, - } - } -} - -impl Push<[T; N]> for OwnedRegion +impl Push<[T; N]> for OwnedRegion where - [T]: ToOwned, - S: Storage - + for<'a> PushStorage> - + std::ops::Index, Output = [T]>, + S: Push + Len, + B: Push, { #[inline] - fn push(&mut self, item: [T; N]) -> as Region>::Index { - let start = self.slices.len(); - self.slices.push_storage(PushIter(item)); - (start, self.slices.len()) + fn push(&mut self, items: [T; N]) { + for item in items { + self.slices.push(item); + } + self.bounds + .push(self.slices.len().try_into().expect("must fit")); } } -impl Push<&[T; N]> for OwnedRegion +impl Push<&[T; N]> for OwnedRegion where - T: Clone, - S: Storage - + for<'a> PushStorage<&'a [T]> - + std::ops::Index, Output = [T]>, + OwnedRegion: for<'a> Push<&'a [T]>, { #[inline] - fn push(&mut self, item: &[T; N]) -> as Region>::Index { + fn push(&mut self, item: &[T; N]) { self.push(item.as_slice()) } } -impl Push<&&[T; N]> for OwnedRegion +impl Push<&&[T; N]> for OwnedRegion where - T: Clone, - S: Storage - + for<'a> PushStorage<&'a [T]> - + std::ops::Index, Output = [T]>, + Self: for<'a> Push<&'a [T]>, { #[inline] - fn push(&mut self, item: &&[T; N]) -> as Region>::Index { + fn push(&mut self, item: &&[T; N]) { self.push(*item) } } -impl<'b, T, S, const N: usize> ReserveItems<&'b [T; N]> for OwnedRegion +impl<'b, T, S, B, const N: usize> ReserveItems<&'b [T; N]> for OwnedRegion where T: Clone, - S: Storage + std::ops::Index, Output = [T]>, + S: Reserve, + B: Reserve, { #[inline] fn reserve_items(&mut self, items: I) @@ -168,35 +217,37 @@ where } } -impl Push<&[T]> for OwnedRegion +impl Push<&[T]> for OwnedRegion where T: Clone, - S: Storage - + for<'a> PushStorage<&'a [T]> - + std::ops::Index, Output = [T]>, + S: for<'a> Push<&'a T> + Len, + B: Push, { #[inline] - fn push(&mut self, item: &[T]) -> as Region>::Index { - let start = self.slices.len(); - self.slices.push_storage(item); - (start, self.slices.len()) + fn push(&mut self, items: &[T]) { + for item in items { + self.slices.push(item); + } + self.bounds + .push(self.slices.len().try_into().expect("must fit")); } } -impl> Push<&&[T]> for OwnedRegion +impl Push<&&[T]> for OwnedRegion where + T: Clone, for<'a> Self: Push<&'a [T]>, { #[inline] - fn push(&mut self, item: &&[T]) -> as Region>::Index { + fn push(&mut self, item: &&[T]) { self.push(*item) } } -impl<'b, T, S> ReserveItems<&'b [T]> for OwnedRegion +impl<'b, T, S, B> ReserveItems<&'b [T]> for OwnedRegion where - [T]: ToOwned, - S: Storage + std::ops::Index, Output = [T]>, + S: Reserve, + B: Reserve, { #[inline] fn reserve_items(&mut self, items: I) @@ -204,41 +255,38 @@ where I: Iterator + Clone, { self.slices.reserve(items.map(<[T]>::len).sum()); + self.bounds.reserve(1); } } -impl Push> for OwnedRegion +impl Push> for OwnedRegion where - [T]: ToOwned, - S: Storage - + for<'a> PushStorage<&'a mut Vec> - + std::ops::Index, Output = [T]>, + S: Push + Len, + B: Push, { #[inline] - fn push(&mut self, mut item: Vec) -> as Region>::Index { - let start = self.slices.len(); - self.slices.push_storage(&mut item); - (start, self.slices.len()) + fn push(&mut self, items: Vec) { + for item in items { + self.slices.push(item); + } + self.bounds + .push(self.slices.len().try_into().expect("must fit")); } } -impl Push<&Vec> for OwnedRegion +impl Push<&Vec> for OwnedRegion where - T: Clone, - S: Storage - + for<'a> PushStorage<&'a [T]> - + std::ops::Index, Output = [T]>, + Self: for<'a> Push<&'a [T]>, { #[inline] - fn push(&mut self, item: &Vec) -> as Region>::Index { + fn push(&mut self, item: &Vec) { self.push(item.as_slice()) } } -impl<'a, T, S> ReserveItems<&'a Vec> for OwnedRegion +impl<'a, T, S, B> ReserveItems<&'a Vec> for OwnedRegion where - [T]: ToOwned, - S: Storage + std::ops::Index, Output = [T]>, + Self: ReserveItems<&'a [T]>, { #[inline] fn reserve_items(&mut self, items: I) @@ -249,28 +297,26 @@ where } } -impl Push> for OwnedRegion +impl Push> for OwnedRegion where - I: IntoIterator, - ::IntoIter: ExactSizeIterator, - T: Clone, - S: Storage - + PushStorage> - + std::ops::Index, Output = [T]>, + I: IntoIterator, + S: Push + Len, + B: Push, { #[inline] - fn push(&mut self, item: PushIter) -> as Region>::Index { - let start = self.slices.len(); - self.slices.push_storage(item); - (start, self.slices.len()) + fn push(&mut self, items: PushIter) { + for item in items { + self.slices.push(item); + } + self.bounds + .push(self.slices.len().try_into().expect("must fit")); } } -impl ReserveItems> for OwnedRegion +impl ReserveItems> for OwnedRegion where - [T]: ToOwned, - S: Storage + std::ops::Index, Output = [T]>, - J: IntoIterator, + S: Reserve, + J: IntoIterator, { #[inline] fn reserve_items(&mut self, items: I) @@ -278,13 +324,13 @@ where I: Iterator> + Clone, { self.slices - .reserve(items.flat_map(|i| i.0.into_iter()).count()); + .reserve(items.flat_map(|i| i.into_iter()).count()); } } #[cfg(test)] mod tests { - use crate::{Push, PushIter, Region, ReserveItems}; + use crate::{Push, PushIter, ReserveItems}; use super::*; @@ -292,26 +338,31 @@ mod tests { fn test_copy_array() { let mut r = >::default(); r.reserve_items(std::iter::once(&[1; 4])); - let index = r.push([1; 4]); - assert_eq!([1, 1, 1, 1], r.index(index)); + assert_eq!(0, r.len()); + r.push([1; 4]); + assert_eq!([1, 1, 1, 1], r.index(0)); + assert_eq!(1, r.len()); } #[test] fn test_copy_ref_ref_array() { let mut r = >::default(); ReserveItems::reserve_items(&mut r, std::iter::once(&[1; 4])); - let index = r.push(&&[1; 4]); - assert_eq!([1, 1, 1, 1], r.index(index)); + r.push(&&[1; 4]); + assert_eq!([1, 1, 1, 1], r.index(0)); + assert_eq!(1, r.len()); } #[test] fn test_copy_vec() { let mut r = >::default(); ReserveItems::reserve_items(&mut r, std::iter::once(&vec![1; 4])); - let index = r.push(&vec![1; 4]); - assert_eq!([1, 1, 1, 1], r.index(index)); - let index = r.push(vec![2; 4]); - assert_eq!([2, 2, 2, 2], r.index(index)); + r.push(&vec![1; 4]); + assert_eq!([1, 1, 1, 1], r.index(0)); + assert_eq!(1, r.len()); + r.push(vec![2; 4]); + assert_eq!([2, 2, 2, 2], r.index(1)); + assert_eq!(2, r.len()); } #[test] @@ -319,7 +370,8 @@ mod tests { let mut r = >::default(); let iter = [1; 4].into_iter(); r.reserve_items(std::iter::once(PushIter(iter.clone()))); - let index = r.push(PushIter(iter)); - assert_eq!([1, 1, 1, 1], r.index(index)); + r.push(PushIter(iter)); + assert_eq!([1, 1, 1, 1], r.index(0)); + assert_eq!(1, r.len()); } } diff --git a/src/impls/string.rs b/src/impls/string.rs index e92e5bd..901ea55 100644 --- a/src/impls/string.rs +++ b/src/impls/string.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; use crate::impls::slice_owned::OwnedRegion; -use crate::{Push, Region, RegionPreference, ReserveItems}; +use crate::{Clear, HeapSize, Index, Len, Push, Region, RegionPreference, ReserveItems}; /// A region to store strings and read `&str`. /// @@ -18,7 +18,7 @@ use crate::{Push, Region, RegionPreference, ReserveItems}; /// /// We fill some data into a string region and use extract it later. /// ``` -/// use flatcontainer::{RegionPreference, Push, OwnedRegion, Region, StringRegion}; +/// use flatcontainer::{RegionPreference, Push, OwnedRegion, Region, StringRegion, Index}; /// let mut r = ::default(); /// /// let panagram_en = "The quick fox jumps over the lazy dog"; @@ -27,8 +27,8 @@ use crate::{Push, Region, RegionPreference, ReserveItems}; /// let en_index = r.push(panagram_en); /// let de_index = r.push(panagram_de); /// -/// assert_eq!(panagram_de, r.index(de_index)); -/// assert_eq!(panagram_en, r.index(en_index)); +/// assert_eq!(panagram_en, r.index(0)); +/// assert_eq!(panagram_de, r.index(1)); /// ``` #[derive(Default, Debug)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] @@ -50,12 +50,8 @@ impl Clone for StringRegion { impl Region for StringRegion where - for<'a> R: Region = &'a [u8]> + 'a, + R: Region, { - type Owned = String; - type ReadItem<'a> = &'a str where Self: 'a ; - type Index = R::Index; - #[inline] fn merge_regions<'a>(regions: impl Iterator + Clone) -> Self where @@ -66,12 +62,6 @@ where } } - #[inline] - fn index(&self, index: Self::Index) -> Self::ReadItem<'_> { - // SAFETY: All Push implementations only accept correct utf8 data - unsafe { std::str::from_utf8_unchecked(self.inner.index(index)) } - } - #[inline] fn reserve_regions<'a, I>(&mut self, regions: I) where @@ -80,15 +70,19 @@ where { self.inner.reserve_regions(regions.map(|r| &r.inner)); } +} - #[inline] - fn clear(&mut self) { - self.inner.clear(); - } +impl Index for StringRegion +where + for<'a> R: Index = &'a [u8]> + 'a, +{ + type Owned = String; + type ReadItem<'a> = &'a str where Self: 'a ; #[inline] - fn heap_size(&self, callback: F) { - self.inner.heap_size(callback); + fn index(&self, index: usize) -> Self::ReadItem<'_> { + // SAFETY: All Push implementations only accept correct utf8 data + unsafe { std::str::from_utf8_unchecked(self.inner.index(index)) } } #[inline] @@ -100,6 +94,26 @@ where } } +impl Len for StringRegion { + #[inline] + fn len(&self) -> usize { + self.inner.len() + } +} + +impl HeapSize for StringRegion { + fn heap_size(&self, callback: F) { + self.inner.heap_size(callback); + } +} + +impl Clear for StringRegion { + #[inline] + fn clear(&mut self) { + self.inner.clear(); + } +} + impl RegionPreference for String { type Owned = Self; type Region = StringRegion; @@ -112,27 +126,27 @@ impl RegionPreference for &str { impl Push for StringRegion where - for<'a> R: Region = &'a [u8]> + Push<&'a [u8]> + 'a, + Self: for<'a> Push<&'a str>, { #[inline] - fn push(&mut self, item: String) -> as Region>::Index { + fn push(&mut self, item: String) { self.push(item.as_str()) } } impl Push<&String> for StringRegion where - for<'a> R: Region = &'a [u8]> + Push<&'a [u8]> + 'a, + Self: for<'a> Push<&'a str>, { #[inline] - fn push(&mut self, item: &String) -> as Region>::Index { + fn push(&mut self, item: &String) { self.push(item.as_str()) } } impl<'b, R> ReserveItems<&'b String> for StringRegion where - for<'a> R: Region = &'a [u8]> + ReserveItems<&'a [u8]> + 'a, + for<'a> R: ReserveItems<&'a [u8]> + 'a, { #[inline] fn reserve_items(&mut self, items: I) @@ -145,27 +159,27 @@ where impl Push<&str> for StringRegion where - for<'a> R: Region = &'a [u8]> + Push<&'a [u8]> + 'a, + for<'a> R: Push<&'a [u8]> + 'a, { #[inline] - fn push(&mut self, item: &str) -> as Region>::Index { + fn push(&mut self, item: &str) { self.inner.push(item.as_bytes()) } } impl Push<&&str> for StringRegion where - for<'a> R: Region = &'a [u8]> + Push<&'a [u8]> + 'a, + for<'a> R: Push<&'a [u8]> + 'a, { #[inline] - fn push(&mut self, item: &&str) -> as Region>::Index { + fn push(&mut self, item: &&str) { self.push(*item) } } impl<'b, R> ReserveItems<&'b str> for StringRegion where - for<'a> R: Region = &'a [u8]> + ReserveItems<&'a [u8]> + 'a, + for<'a> R: ReserveItems<&'a [u8]> + 'a, { #[inline] fn reserve_items(&mut self, items: I) @@ -178,7 +192,7 @@ where impl<'a, 'b: 'a, R> ReserveItems<&'a &'b str> for StringRegion where - for<'c> R: Region = &'c [u8]> + ReserveItems<&'c [u8]> + 'c, + for<'c> R: ReserveItems<&'c [u8]> + 'c, { #[inline] fn reserve_items(&mut self, items: I) @@ -191,13 +205,13 @@ where #[cfg(test)] mod tests { - use crate::{IntoOwned, Push, Region, ReserveItems, StringRegion}; + use crate::{HeapSize, Index, IntoOwned, Push, ReserveItems, StringRegion}; #[test] fn test_inner() { let mut r = ::default(); - let index = r.push("abc"); - assert_eq!(r.index(index), "abc"); + r.push("abc"); + assert_eq!(r.index(0), "abc"); } #[test] @@ -249,10 +263,10 @@ mod tests { fn owned() { let mut r = ::default(); - let idx = r.push("abc"); - let reference = r.index(idx); + r.push("abc"); + let reference = r.index(0); let owned = reference.into_owned(); - let idx = r.push(owned); - assert_eq!("abc", r.index(idx)); + r.push(owned); + assert_eq!("abc", r.index(1)); } } diff --git a/src/impls/tuple.rs b/src/impls/tuple.rs index 2348fb1..709bae0 100644 --- a/src/impls/tuple.rs +++ b/src/impls/tuple.rs @@ -4,7 +4,7 @@ use paste::paste; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use crate::{IntoOwned, Push, Region, RegionPreference, ReserveItems}; +use crate::{IntoOwned, Push, Region, RegionPreference, ReserveItems, Clear, Len, HeapSize, Index}; /// The macro creates the region implementation for tuples macro_rules! tuple_flatcontainer { @@ -24,10 +24,7 @@ macro_rules! tuple_flatcontainer { } #[allow(non_snake_case)] - impl<$($name: Region + Clone),*> Clone for []<$($name),*> - where - $(<$name as Region>::Index: crate::Index),* - { + impl<$($name: Clone),*> Clone for []<$($name),*> { fn clone(&self) -> Self { Self { $([]: self.[].clone(),)* @@ -40,15 +37,7 @@ macro_rules! tuple_flatcontainer { } #[allow(non_snake_case)] - impl<$($name: Region),*> Region for []<$($name),*> - where - $(<$name as Region>::Index: crate::Index),* - { - type Owned = ($($name::Owned,)*); - type ReadItem<'a> = ($($name::ReadItem<'a>,)*) where Self: 'a; - - type Index = ($($name::Index,)*); - + impl<$($name: Region),*> Region for []<$($name),*> { #[inline] fn merge_regions<'a>(regions: impl Iterator + Clone) -> Self where @@ -58,14 +47,6 @@ macro_rules! tuple_flatcontainer { $([]: $name::merge_regions(regions.clone().map(|r| &r.[]))),* } } - - #[inline] fn index(&self, index: Self::Index) -> Self::ReadItem<'_> { - let ($($name,)*) = index; - ( - $(self.[].index($name),)* - ) - } - #[inline(always)] fn reserve_regions<'a, It>(&mut self, regions: It) where @@ -74,15 +55,17 @@ macro_rules! tuple_flatcontainer { { $(self.[].reserve_regions(regions.clone().map(|r| &r.[]));)* } + } - #[inline(always)] - fn clear(&mut self) { - $(self.[].clear();)* - } + #[allow(non_snake_case)] + impl<$($name: Index),*> Index for []<$($name),*> { + type Owned = ($($name::Owned,)*); + type ReadItem<'a> = ($($name::ReadItem<'a>,)*) where Self: 'a; - #[inline] - fn heap_size(&self, mut callback: Fn) { - $(self.[].heap_size(&mut callback);)* + #[inline] fn index(&self, index: usize) -> Self::ReadItem<'_> { + ( + $(self.[].index(index),)* + ) } #[inline] @@ -94,6 +77,34 @@ macro_rules! tuple_flatcontainer { } } + #[allow(non_snake_case)] + impl<$($name: Clear),*> Clear for []<$($name),*> { + #[inline(always)] + fn clear(&mut self) { + $(self.[].clear();)* + } + } + + #[allow(non_snake_case)] + impl<$($name: Len),*> Len for []<$($name),*> { + #[inline(always)] + fn len(&self) -> usize { + self.0.len() + } + #[inline(always)] + fn is_empty(&self) -> bool { + self.0.is_empty() + } + } + + #[allow(non_snake_case)] + impl<$($name: HeapSize),*> HeapSize for []<$($name),*> { + #[inline] + fn heap_size(&self, mut callback: Fn) { + $(self.[].heap_size(&mut callback);)* + } + } + #[allow(non_camel_case_types)] #[allow(non_snake_case)] impl<$($name, [<$name _C>]: Region ),*> Push<($($name,)*)> for []<$([<$name _C>]),*> @@ -101,10 +112,9 @@ macro_rules! tuple_flatcontainer { $([<$name _C>]: Push<$name>),* { #[inline] - fn push(&mut self, item: ($($name,)*)) - -> <[]<$([<$name _C>]),*> as Region>::Index { + fn push(&mut self, item: ($($name,)*)) { let ($($name,)*) = item; - ($(self.[].push($name),)*) + $(self.[].push($name);)* } } @@ -112,13 +122,12 @@ macro_rules! tuple_flatcontainer { #[allow(non_snake_case)] impl<'a, $($name, [<$name _C>]),*> Push<&'a ($($name,)*)> for []<$([<$name _C>]),*> where - $([<$name _C>]: Region + Push<&'a $name>),* + $([<$name _C>]: Push<&'a $name>),* { #[inline] - fn push(&mut self, item: &'a ($($name,)*)) - -> <[]<$([<$name _C>]),*> as Region>::Index { + fn push(&mut self, item: &'a ($($name,)*)) { let ($($name,)*) = item; - ($(self.[].push($name),)*) + $(self.[].push($name);)* } } @@ -241,12 +250,12 @@ cfg_if::cfg_if! { #[cfg(test)] mod tests { use crate::impls::tuple::TupleABCRegion; - use crate::{FlatStack, MirrorRegion, Push, Region, StringRegion}; + use crate::{Push, Region, StringRegion}; #[test] fn test_tuple() { let t = (1, 2, 3); - let mut r = , MirrorRegion<_>, MirrorRegion<_>>>::default(); + let mut r = , Vec<_>, Vec<_>>>::default(); let index = r.push(t); assert_eq!(t, r.index(index)); @@ -266,7 +275,7 @@ mod tests { #[test] fn test_nested() { let t = ("abc", 2, 3); - let mut r = , MirrorRegion<_>>>::default(); + let mut r = , Vec<_>>>::default(); let index = r.push(t); assert_eq!(t, r.index(index)); @@ -283,7 +292,7 @@ mod tests { #[test] fn test_heap_size() { let t = ("abc", 2, 3); - let mut r = , MirrorRegion<_>>>::default(); + let mut r = , Vec<_>>>::default(); let _ = r.push(t); diff --git a/src/impls/vec.rs b/src/impls/vec.rs index 712a79d..3aa1f25 100644 --- a/src/impls/vec.rs +++ b/src/impls/vec.rs @@ -1,12 +1,9 @@ //! Definitions to use `Vec` as a region. -use crate::{Push, Region, ReserveItems}; - -impl Region for Vec { - type Owned = T; - type ReadItem<'a> = &'a T where Self: 'a; - type Index = usize; +use crate::{Clear, HeapSize, Index, IndexAs, Len, Push, Region, Reserve, ReserveItems}; +impl Region for Vec { + #[inline(always)] fn merge_regions<'a>(regions: impl Iterator + Clone) -> Self where Self: 'a, @@ -14,10 +11,7 @@ impl Region for Vec { Self::with_capacity(regions.map(Vec::len).sum()) } - fn index(&self, index: Self::Index) -> Self::ReadItem<'_> { - &self[index] - } - + #[inline(always)] fn reserve_regions<'a, I>(&mut self, regions: I) where Self: 'a, @@ -25,16 +19,16 @@ impl Region for Vec { { self.reserve(regions.map(Vec::len).sum()); } +} - fn clear(&mut self) { - self.clear(); - } - - fn heap_size(&self, mut callback: F) { - let size_of_t = std::mem::size_of::(); - callback(self.len() * size_of_t, self.capacity() * size_of_t); +impl Index for Vec { + type Owned = T; + type ReadItem<'a> = &'a T where Self: 'a; + #[inline(always)] + fn index(&self, index: usize) -> Self::ReadItem<'_> { + &self[index] } - + #[inline(always)] fn reborrow<'b, 'a: 'b>(item: Self::ReadItem<'a>) -> Self::ReadItem<'b> where Self: 'a, @@ -43,28 +37,69 @@ impl Region for Vec { } } +impl IndexAs for Vec { + #[inline(always)] + fn index_as(&self, index: usize) -> T { + self[index] + } +} + impl Push for Vec { - fn push(&mut self, item: T) -> Self::Index { + #[inline(always)] + fn push(&mut self, item: T) { self.push(item); - self.len() - 1 } } impl Push<&T> for Vec { - fn push(&mut self, item: &T) -> Self::Index { + #[inline(always)] + fn push(&mut self, item: &T) { self.push(item.clone()); - self.len() - 1 } } impl Push<&&T> for Vec { - fn push(&mut self, item: &&T) -> Self::Index { + #[inline(always)] + fn push(&mut self, item: &&T) { self.push((*item).clone()); - self.len() - 1 + } +} + +impl Clear for Vec { + #[inline(always)] + fn clear(&mut self) { + self.clear(); + } +} + +impl Len for Vec { + #[inline(always)] + fn len(&self) -> usize { + self.len() + } + #[inline(always)] + fn is_empty(&self) -> bool { + self.is_empty() + } +} + +impl HeapSize for Vec { + #[inline(always)] + fn heap_size(&self, mut callback: F) { + let size_of_t = std::mem::size_of::(); + callback(self.len() * size_of_t, self.capacity() * size_of_t); + } +} + +impl Reserve for Vec { + #[inline(always)] + fn reserve(&mut self, additional: usize) { + self.reserve(additional); } } impl ReserveItems for Vec { + #[inline(always)] fn reserve_items(&mut self, items: I) where I: Iterator + Clone, @@ -75,13 +110,15 @@ impl ReserveItems for Vec { #[cfg(test)] mod tests { + use crate::Index; + #[test] fn vec() { - use crate::{Push, Region, ReserveItems}; + use crate::{Push, ReserveItems}; let mut region = Vec::::new(); - let index = <_ as Push<_>>::push(&mut region, 42); - assert_eq!(region.index(index), &42); + <_ as Push<_>>::push(&mut region, 42); + assert_eq!(region.index(0), &42); let mut region = Vec::::new(); region.push(42); diff --git a/src/lib.rs b/src/lib.rs index 759a508..5b24e06 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,38 +2,18 @@ #![deny(missing_docs)] use std::borrow::Borrow; -use std::fmt::{Debug, Formatter}; - -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; pub mod impls; -use crate::impls::index::IndexContainer; -pub use impls::columns::ColumnsRegion; -pub use impls::mirror::MirrorRegion; -pub use impls::option::OptionRegion; -pub use impls::result::ResultRegion; +// use crate::impls::index::IndexContainer; +// pub use impls::columns::ColumnsRegion; +// pub use impls::mirror::MirrorRegion; +// pub use impls::option::OptionRegion; +// pub use impls::result::ResultRegion; pub use impls::slice::SliceRegion; pub use impls::slice_owned::OwnedRegion; pub use impls::string::StringRegion; -/// An index into a region. Automatically implemented for relevant types. -/// -/// We require an index to be [`Copy`] and to support serde. -#[cfg(feature = "serde")] -pub trait Index: Copy + Serialize + for<'a> Deserialize<'a> {} -#[cfg(feature = "serde")] -impl Deserialize<'a>> Index for T {} - -/// An index into a region. Automatically implemented for relevant types. -/// -/// We require an index to be [`Copy`]. -#[cfg(not(feature = "serde"))] -pub trait Index: Copy {} -#[cfg(not(feature = "serde"))] -impl Index for T {} - /// A region to absorb presented data and present it as a type with a lifetime. /// /// This type absorbs data and provides an index to look up an equivalent representation @@ -41,46 +21,17 @@ impl Index for T {} /// presentation of the data, and what data it can absorb. /// /// Implement the [`Push`] trait for all types that can be copied into a region. -pub trait Region: Default { - /// An owned type that can be constructed from a read item. - type Owned; - - /// The type of the data that one gets out of the container. - type ReadItem<'a>: IntoOwned<'a, Owned = Self::Owned> - where - Self: 'a; - - /// The type to index into the container. Should be treated - /// as an opaque type, even if known. - type Index: Index; - +pub trait Region { /// Construct a region that can absorb the contents of `regions` in the future. fn merge_regions<'a>(regions: impl Iterator + Clone) -> Self where Self: 'a; - /// Index into the container. The index must be obtained by - /// pushing data into the container. - #[must_use] - fn index(&self, index: Self::Index) -> Self::ReadItem<'_>; - /// Ensure that the region can absorb the items of `regions` without reallocation fn reserve_regions<'a, I>(&mut self, regions: I) where Self: 'a, I: Iterator + Clone; - - /// Remove all elements from this region, but retain allocations if possible. - fn clear(&mut self); - - /// Heap size, size - capacity - fn heap_size(&self, callback: F); - - /// Converts a read item into one with a narrower lifetime. - #[must_use] - fn reborrow<'b, 'a: 'b>(item: Self::ReadItem<'a>) -> Self::ReadItem<'b> - where - Self: 'a; } /// A trait to let types express a default container type and an owned type, which can @@ -89,14 +40,14 @@ pub trait Region: Default { /// # Example /// /// ``` -/// # use flatcontainer::{FlatStack, RegionPreference}; -/// let _ = FlatStack::<<((Vec, &[usize]), Option, Result) as RegionPreference>::Region>::default(); +/// # use flatcontainer::{RegionPreference}; +/// let _ = <<((Vec, &[usize]), Option, Result) as RegionPreference>::Region>::default(); /// ``` pub trait RegionPreference { /// The owned type of the region. type Owned; /// The recommended container type. - type Region: Region; + type Region: Index; } impl RegionPreference for &T { @@ -104,18 +55,16 @@ impl RegionPreference for &T { type Region = T::Region; } -/// Push an item `T` into a region. -pub trait Push: Region { - /// Push `item` into self, returning an index that allows to look up the - /// corresponding read item. - #[must_use] - fn push(&mut self, item: T) -> Self::Index; +/// Push an item `T` into a container. +pub trait Push { + /// Push `item` into self. + fn push(&mut self, item: T); } /// Reserve space in the receiving region. /// /// Closely related to [`Push`], but separate because target type is likely different. -pub trait ReserveItems: Region { +pub trait ReserveItems { /// Ensure that the region can absorb `items` without reallocation. fn reserve_items(&mut self, items: I) where @@ -156,7 +105,7 @@ impl<'a, T: ToOwned + ?Sized> IntoOwned<'a> for &'a T { owned.borrow() } } - +/* /// A container for indices into a region. #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr( @@ -413,6 +362,7 @@ impl Clone for FlatStack { self.indices.clone_from(&source.indices); } } +*/ /// A type to wrap and push iterators into regions. /// @@ -422,10 +372,85 @@ impl Clone for FlatStack { #[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] pub struct PushIter(pub I); +impl IntoIterator for PushIter { + type Item = I::Item; + type IntoIter = I::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +/// TODO +pub trait IndexAs { + /// TODO + fn index_as(&self, index: usize) -> T; +} + +/// TODO +pub trait Len { + /// TODO + fn len(&self) -> usize; + /// TODO + fn is_empty(&self) -> bool { + self.len() == 0 + } +} + +/// TODO +pub trait Reserve { + /// TODO + fn reserve(&mut self, additional: usize); +} + +/// TODO +pub trait WithCapacity { + /// TODO + fn with_capacity(capacity: usize) -> Self; +} + +/// TODO +pub trait Clear { + /// TODO + fn clear(&mut self); +} + +/// TODO +pub trait HeapSize { + /// TODO + fn heap_size(&self, callback: F); +} + +/// TODO +pub trait Index { + /// An owned type that can be constructed from a read item. + type Owned; + /// The type of the data that one gets out of the container. + type ReadItem<'a>: IntoOwned<'a, Owned = Self::Owned> + where + Self: 'a; + /// TODO + fn index(&self, index: usize) -> Self::ReadItem<'_>; + + /// Converts a read item into one with a narrower lifetime. + #[must_use] + fn reborrow<'b, 'a: 'b>(item: Self::ReadItem<'a>) -> Self::ReadItem<'b> + where + Self: 'a; + // #[inline] + // fn reborrow<'b, 'a: 'b>(item: Self::ReadItem<'a>) -> Self::ReadItem<'b> + // where + // Self: 'a, + // { + // item + // } +} + +/* #[cfg(test)] mod tests { - use crate::impls::deduplicate::{CollapseSequence, ConsecutiveIndexPairs}; - use crate::impls::tuple::TupleARegion; + // use crate::impls::deduplicate::{CollapseSequence, ConsecutiveIndexPairs}; + // use crate::impls::tuple::TupleARegion; use super::*; @@ -679,3 +704,4 @@ mod tests { let _ = R::reborrow(item) == R::reborrow(IntoOwned::borrow_as(owned)); } } +*/ diff --git a/tests/cow.rs b/tests/cow.rs index d82e5b7..43438af 100644 --- a/tests/cow.rs +++ b/tests/cow.rs @@ -1,6 +1,6 @@ //! What follows is an example of a Cow-like type that can be used to switch between a GAT //! and an owned type at runtime. - +/* use std::fmt::{Debug, Formatter}; use std::marker::PhantomData; @@ -171,3 +171,4 @@ fn test_gat_cow() { assert_eq!("abcdef", item.into_owned()); assert_eq!("abc", c.get(0).into_owned()); } +*/ diff --git a/tests/person.rs b/tests/person.rs index 5f3a43c..9c32b97 100644 --- a/tests/person.rs +++ b/tests/person.rs @@ -1,5 +1,5 @@ //! Test a slightly more struct with nested regions, representing people. - +/* use flatcontainer::{FlatStack, IntoOwned, Push, Region, RegionPreference, ReserveItems}; struct Person { @@ -186,3 +186,4 @@ fn test_person() { assert_eq!(copied_hobby, hobby); } } +*/ diff --git a/tests/recursive.rs b/tests/recursive.rs index 65e4cd1..ef229c1 100644 --- a/tests/recursive.rs +++ b/tests/recursive.rs @@ -1,5 +1,5 @@ //! Demonstration of how to encode recursive data structures. - +/* use flatcontainer::impls::deduplicate::ConsecutiveIndexPairs; use flatcontainer::{IntoOwned, Push, Region, StringRegion}; @@ -149,3 +149,4 @@ fn recursive() { println!("{region:?}"); } +*/ From f6a3dc0d5b6e8ad34d69929e37139a67e8de9e0f Mon Sep 17 00:00:00 2001 From: Moritz Hoffmann Date: Fri, 8 Nov 2024 17:05:45 +0100 Subject: [PATCH 2/5] progress --- src/bitmap.rs | 188 +++++++++++++++++++++++++ src/impls.rs | 3 +- src/impls/option.rs | 141 ++++++++++++++----- src/impls/tuple.rs | 56 ++++---- src/lib.rs | 335 +++++++++++++++++++++++++------------------- src/primitive.rs | 60 ++++++++ src/rank_select.rs | 182 ++++++++++++++++++++++++ 7 files changed, 756 insertions(+), 209 deletions(-) create mode 100644 src/bitmap.rs create mode 100644 src/primitive.rs create mode 100644 src/rank_select.rs diff --git a/src/bitmap.rs b/src/bitmap.rs new file mode 100644 index 0000000..ba004c7 --- /dev/null +++ b/src/bitmap.rs @@ -0,0 +1,188 @@ +//! Bitmaps + +use crate::{Clear, HeapSize, Index, IndexAs, Len, Push, Region, Reserve, ReserveItems}; +use serde::{Deserialize, Serialize}; + +/// TODO +#[derive(Default, Clone, Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct Bools> { + values: V, + last_word: u64, + last_bits: u8, +} + +impl> Bools { + /// Number of blocks in the bitmap. + #[inline(always)] + pub fn blocks(&self) -> usize { + self.values.len() + (self.last_bits > 0) as usize + } + + /// Value of the last block. + #[inline(always)] + pub fn last_block(&self) -> (u64, u8) { + if self.last_bits > 0 || self.values.is_empty() { + (self.last_word, self.last_bits) + } else { + (self.values.index_as(self.values.len() - 1), 64) + } + } + + /// Value of the block at the given index. + pub fn block(&self, index: usize) -> (u64, u8) { + if index == self.values.len() { + (self.last_word, self.last_bits) + } else { + (self.values.index_as(index), 64) + } + } +} + +impl Len for Bools { + #[inline(always)] + fn len(&self) -> usize { + self.values.len() * 64 + self.last_bits as usize + } +} + +impl Clear for Bools { + #[inline(always)] + fn clear(&mut self) { + self.values.clear(); + self.last_word = 0; + self.last_bits = 0; + } +} + +impl HeapSize for Bools { + fn heap_size(&self, callback: F) { + self.values.heap_size(callback); + } +} + +impl Region for Bools +where + V: Region, +{ + fn merge_regions<'a>(regions: impl Iterator + Clone) -> Self + where + Self: 'a, + { + Self { + values: V::merge_regions(regions.map(|r| &r.values)), + last_word: 0, + last_bits: 0, + } + } + + fn reserve_regions<'a, I>(&mut self, regions: I) + where + Self: 'a, + I: Iterator + Clone, + { + self.values.reserve_regions(regions.map(|r| &r.values)); + } +} + +impl ReserveItems for Bools +where + V: Reserve, +{ + fn reserve_items(&mut self, items: I) + where + I: Iterator + Clone, + { + self.values.reserve((items.count() + 63) / 64); + } +} + +impl Index for Bools +where + V: Len + IndexAs, +{ + type Owned = bool; + type ReadItem<'a> = bool where Self: 'a; + + fn index(&self, index: usize) -> Self::ReadItem<'_> { + let block = index / 64; + let word = if block == self.values.len() { + self.last_word + } else { + self.values.index_as(block) + }; + let bit = index % 64; + word & (1 << bit) != 0 + } + + fn reborrow<'b, 'a: 'b>(item: Self::ReadItem<'a>) -> Self::ReadItem<'b> + where + Self: 'a, + { + item + } +} + +impl IndexAs for Bools +where + V: IndexAs + Len, +{ + #[inline(always)] + fn index_as(&self, index: usize) -> bool { + self.index(index) + } +} + +impl> Push for Bools { + #[inline(always)] + fn push(&mut self, item: bool) { + self.last_word |= (item as u64) << self.last_bits; + self.last_bits += 1; + // If we have filled the last word, push it to the values and reset the last word + if self.last_bits == 64 { + self.values.push(self.last_word); + self.last_word = 0; + self.last_bits = 0; + } + } +} + +impl Push<&bool> for Bools +where + Self: Push, +{ + #[inline(always)] + fn push(&mut self, item: &bool) { + self.push(*item); + } +} + +#[cfg(test)] +mod tests { + use crate::{Index, Push}; + + use super::*; + + #[test] + fn test_bitmap() { + let mut bitmap = ::default(); + for i in 0..100 { + bitmap.push(i % 2 == 0); + } + assert_eq!(bitmap.len(), 100); + for i in 0..100 { + assert_eq!(bitmap.index(i), i % 2 == 0); + } + + let mut bitmap = ::default(); + assert_eq!((0, 0), bitmap.last_block()); + bitmap.push(true); + assert_eq!((0b1, 1), bitmap.last_block()); + for _ in 0..63 { + bitmap.push(false); + } + bitmap.push(true); + assert_eq!((0b1, 1), bitmap.last_block()); + assert_eq!((0b1, 64), bitmap.block(0)); + } +} diff --git a/src/impls.rs b/src/impls.rs index 93b43ac..9380937 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -6,11 +6,10 @@ // pub mod huffman_container; // pub mod index; // pub mod mirror; -// pub mod option; +pub mod option; // pub mod result; pub mod slice; pub mod slice_owned; -// pub mod storage; pub mod string; pub mod tuple; mod vec; diff --git a/src/impls/option.rs b/src/impls/option.rs index ec518b6..47f681a 100644 --- a/src/impls/option.rs +++ b/src/impls/option.rs @@ -3,11 +3,14 @@ #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use crate::{IntoOwned, Push, Region, RegionPreference, ReserveItems}; +use crate::rank_select::RankSelect; +use crate::{ + Clear, HeapSize, Index, IndexAs, IntoOwned, Len, Push, Region, RegionPreference, ReserveItems, +}; impl RegionPreference for Option { type Owned = Option; - type Region = OptionRegion; + type Region = OptionRegion, Vec>; } /// A region to hold [`Option`]s. @@ -16,25 +19,27 @@ impl RegionPreference for Option { /// /// The region can hold options: /// ``` -/// # use flatcontainer::{RegionPreference, Push, OptionRegion, Region}; +/// # use flatcontainer::{RegionPreference, Push, OptionRegion, Index}; /// let mut r = ::Region>>::default(); /// -/// let some_index = r.push(Some(123)); +/// r.push(Some(123)); /// // Type annotations required for `None`: -/// let none_index = r.push(Option::::None); +/// r.push(Option::::None); /// -/// assert_eq!(Some(123), r.index(some_index)); -/// assert_eq!(None, r.index(none_index)); +/// assert_eq!(Some(&123), r.index(0)); +/// assert_eq!(None, r.index(1)); /// ``` #[derive(Default, Debug)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct OptionRegion { +pub struct OptionRegion, RV = Vec> { + ranks: RankSelect, inner: R, } -impl Clone for OptionRegion { +impl Clone for OptionRegion { fn clone(&self) -> Self { Self { + ranks: self.ranks.clone(), inner: self.inner.clone(), } } @@ -44,43 +49,76 @@ impl Clone for OptionRegion { } } -impl Region for OptionRegion { - type Owned = Option; - type ReadItem<'a> = Option<::ReadItem<'a>> where Self: 'a; - type Index = Option; - +impl Region for OptionRegion { #[inline] fn merge_regions<'a>(regions: impl Iterator + Clone) -> Self where Self: 'a, { Self { + ranks: RankSelect::merge_regions(regions.clone().map(|r| &r.ranks)), inner: R::merge_regions(regions.map(|r| &r.inner)), } } - #[inline] - fn index(&self, index: Self::Index) -> Self::ReadItem<'_> { - index.map(|t| self.inner.index(t)) - } - #[inline] fn reserve_regions<'a, I>(&mut self, regions: I) where Self: 'a, I: Iterator + Clone, { + self.ranks + .reserve_regions(regions.clone().map(|r| &r.ranks)); self.inner.reserve_regions(regions.map(|r| &r.inner)); } +} - #[inline] +impl HeapSize for OptionRegion +where + R: HeapSize, + RC: HeapSize, + RV: HeapSize, +{ + fn heap_size(&self, mut callback: F) { + self.ranks.heap_size(&mut callback); + self.inner.heap_size(callback); + } +} + +impl Clear for OptionRegion +where + R: Clear, + RC: Clear, + RV: Clear, +{ fn clear(&mut self) { + self.ranks.clear(); self.inner.clear(); } +} + +impl Len for OptionRegion { + fn len(&self) -> usize { + self.ranks.len() + } +} + +impl Index for OptionRegion +where + R: Index, + RC: IndexAs + Len, + RV: IndexAs + Len, +{ + type Owned = Option; + type ReadItem<'a> = Option<::ReadItem<'a>> where Self: 'a; #[inline] - fn heap_size(&self, callback: F) { - self.inner.heap_size(callback); + fn index(&self, index: usize) -> Self::ReadItem<'_> { + if self.ranks.index_as(index) { + Some(self.inner.index(self.ranks.rank(index))) + } else { + None + } } #[inline] @@ -118,27 +156,47 @@ where } } -impl Push> for OptionRegion +impl Push> for OptionRegion where - TR: Region + Push, + TR: Push, + RC: IndexAs + Len + Push, + RV: IndexAs + Len + Push, { #[inline] - fn push(&mut self, item: Option) -> as Region>::Index { - item.map(|t| self.inner.push(t)) + fn push(&mut self, item: Option) { + match item { + Some(t) => { + self.ranks.push(true); + self.inner.push(t); + } + None => { + self.ranks.push(false); + } + } } } -impl<'a, T: 'a, TR> Push<&'a Option> for OptionRegion +impl<'a, T: 'a, TR, RC, RV> Push<&'a Option> for OptionRegion where - TR: Region + Push<&'a T>, + TR: Push<&'a T>, + RC: IndexAs + Len + Push, + RV: IndexAs + Len + Push, { #[inline] - fn push(&mut self, item: &'a Option) -> as Region>::Index { - item.as_ref().map(|t| self.inner.push(t)) + fn push(&mut self, item: &'a Option) { + match item { + Some(t) => { + self.ranks.push(true); + self.inner.push(t); + } + None => { + self.ranks.push(false); + } + } } } -impl ReserveItems> for OptionRegion +impl ReserveItems> for OptionRegion where TR: Region + ReserveItems, { @@ -154,7 +212,7 @@ where } } -impl<'a, T: 'a, TR> ReserveItems<&'a Option> for OptionRegion +impl<'a, T: 'a, TR, RC, RV> ReserveItems<&'a Option> for OptionRegion where TR: Region + ReserveItems<&'a T>, { @@ -169,13 +227,13 @@ where #[cfg(test)] mod tests { - use crate::{MirrorRegion, OwnedRegion, Region, ReserveItems}; + use crate::{OwnedRegion, ReserveItems}; use super::*; #[test] fn test_reserve() { - let mut r = >>::default(); + let mut r = >>::default(); ReserveItems::reserve_items(&mut r, [Some(0), None].iter()); ReserveItems::reserve_items(&mut r, [Some(0), None].into_iter()); @@ -184,11 +242,24 @@ mod tests { #[test] fn test_heap_size() { let mut r = >>::default(); - ReserveItems::reserve_items(&mut r, [Some([1; 1]), None].iter()); + ReserveItems::reserve_items( + &mut r, + std::iter::once(Some(&[1; 1])).chain(std::iter::repeat_n(None, 1000)), + ); let mut cap = 0; r.heap_size(|_, ca| { cap += ca; }); assert!(cap > 0); + for item in std::iter::once(Some(&[1; 1])).chain(std::iter::repeat_n(None, 10000)) { + r.push(item); + } + let mut siz = 0; + r.heap_size(|s, _| { + siz += s; + }); + assert!(siz > 0); + println!("{siz}"); + println!("{r:?}") } } diff --git a/src/impls/tuple.rs b/src/impls/tuple.rs index 709bae0..0683908 100644 --- a/src/impls/tuple.rs +++ b/src/impls/tuple.rs @@ -4,7 +4,7 @@ use paste::paste; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use crate::{IntoOwned, Push, Region, RegionPreference, ReserveItems, Clear, Len, HeapSize, Index}; +use crate::{Clear, HeapSize, Index, IntoOwned, Len, Push, Region, RegionPreference, ReserveItems}; /// The macro creates the region implementation for tuples macro_rules! tuple_flatcontainer { @@ -86,14 +86,17 @@ macro_rules! tuple_flatcontainer { } #[allow(non_snake_case)] + #[allow(unused_variables)] impl<$($name: Len),*> Len for []<$($name),*> { #[inline(always)] fn len(&self) -> usize { - self.0.len() + $(let len = self.[].len();)* + len } #[inline(always)] fn is_empty(&self) -> bool { - self.0.is_empty() + $(let is_empty = self.[].is_empty();)* + is_empty } } @@ -249,44 +252,45 @@ cfg_if::cfg_if! { #[cfg(test)] mod tests { - use crate::impls::tuple::TupleABCRegion; - use crate::{Push, Region, StringRegion}; + use crate::{Push, StringRegion}; + + use super::*; #[test] fn test_tuple() { let t = (1, 2, 3); let mut r = , Vec<_>, Vec<_>>>::default(); - let index = r.push(t); - assert_eq!(t, r.index(index)); + r.push(t); + assert_eq!((&1, &2, &3), r.index(0)); - let index = r.push((&1, &2, &3)); - assert_eq!(t, r.index(index)); + r.push((&1, &2, &4)); + assert_eq!((&1, &2, &4), r.index(1)); - let index = r.push((&1, 2, 3)); - assert_eq!(t, r.index(index)); + r.push((&1, 2, 5)); + assert_eq!((&1, &2, &5), r.index(2)); - let index = r.push(&(1, 2, 3)); - assert_eq!(t, r.index(index)); + r.push(&(1, 2, 6)); + assert_eq!((&1, &2, &6), r.index(3)); - let index = r.push(&(1, &2, 3)); - assert_eq!(t, r.index(index)); + r.push(&(1, &2, 7)); + assert_eq!((&1, &2, &7), r.index(4)); } #[test] fn test_nested() { let t = ("abc", 2, 3); let mut r = , Vec<_>>>::default(); - let index = r.push(t); - assert_eq!(t, r.index(index)); + r.push(t); + assert_eq!(("abc", &2, &3), r.index(0)); - let index = r.push((&"abc", &2, &3)); - assert_eq!(t, r.index(index)); + r.push((&"abc", &2, &3)); + assert_eq!(("abc", &2, &3), r.index(1)); - let index = r.push((&"abc", 2, 3)); - assert_eq!(t, r.index(index)); + r.push((&"abc", 2, 3)); + assert_eq!(("abc", &2, &3), r.index(2)); - let index = r.push(&("abc", 2, 3)); - assert_eq!(t, r.index(index)); + r.push(&("abc", 2, 3)); + assert_eq!(("abc", &2, &3), r.index(3)); } #[test] @@ -311,10 +315,10 @@ mod tests { } #[test] fn test_reserve_items() { - let mut c = FlatStack::default_impl::<(usize, String, Vec)>(); - c.copy((1, format!("Hello"), &["abc"])); + let mut c = <(usize, String, Vec) as RegionPreference>::Region::default(); + c.push((1, format!("Hello"), &["abc"])); - let mut c2 = FlatStack::default_impl::<(usize, String, Vec)>(); + let mut c2 = <(usize, String, Vec) as RegionPreference>::Region::default(); c2.reserve_items(c.iter()); } } diff --git a/src/lib.rs b/src/lib.rs index 5b24e06..2c7c738 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,12 +3,16 @@ use std::borrow::Borrow; +mod bitmap; pub mod impls; +mod primitive; +mod rank_select; +// pub mod storage; // use crate::impls::index::IndexContainer; // pub use impls::columns::ColumnsRegion; // pub use impls::mirror::MirrorRegion; -// pub use impls::option::OptionRegion; +pub use impls::option::OptionRegion; // pub use impls::result::ResultRegion; pub use impls::slice::SliceRegion; pub use impls::slice_owned::OwnedRegion; @@ -444,154 +448,191 @@ pub trait Index { // { // item // } + + /// TODO + fn iter(&self) -> IntoIter<'_, Self> + where + Self: Len + Sized, + { + IntoIter { + index: 0, + region: self, + } + } +} + +#[derive(Clone, Copy, Debug)] +/// TODO +pub struct IntoIter<'a, R: Index + Len> { + /// TODO + index: usize, + /// TODO + region: &'a R, +} + +impl<'a, R: Index + Len> Iterator for IntoIter<'a, R> { + type Item = R::ReadItem<'a>; + + fn next(&mut self) -> Option { + if self.index < self.region.len() { + let item = self.region.index(self.index); + self.index += 1; + Some(item) + } else { + None + } + } } -/* #[cfg(test)] mod tests { - // use crate::impls::deduplicate::{CollapseSequence, ConsecutiveIndexPairs}; - // use crate::impls::tuple::TupleARegion; + use std::fmt::Debug; - use super::*; + use crate::impls::tuple::TupleARegion; - fn copy, T>(r: &mut R, item: T) -> R::Index { - r.push(item) - } + use super::*; - #[test] - fn test_readme() { - let r: Result<_, u16> = Ok("abc"); - let mut c = FlatStack::default_impl::>(); - c.copy(r); - assert_eq!(r, c.get(0)); - } + // #[test] + // fn test_readme() { + // let r: Result<_, u16> = Ok("abc"); + // let mut c = FlatStack::default_impl::>(); + // c.copy(r); + // assert_eq!(r, c.get(0)); + // } #[test] fn test_slice_string_onto() { let mut c = ::default(); - let index = c.push("abc".to_string()); - assert_eq!("abc", c.index(index)); - let index = c.push("def"); - assert_eq!("def", c.index(index)); + c.push("abc".to_string()); + assert_eq!("abc", c.index(0)); + c.push("def"); + assert_eq!("def", c.index(1)); } #[test] fn test_container_string() { - let mut c = FlatStack::default_impl::(); - c.copy(&"abc".to_string()); - assert_eq!("abc", c.get(0)); - c.copy("def"); - assert_eq!("def", c.get(1)); + let mut c = ::Region::default(); + c.push(&"abc".to_string()); + assert_eq!("abc", c.index(0)); + c.push("def"); + assert_eq!("def", c.index(1)); } #[test] fn test_vec() { - let mut c = >>::default(); + let mut c = >>::default(); let slice = &[1u8, 2, 3]; - let idx = c.push(slice); - assert!(slice.iter().copied().eq(c.index(idx))); + c.push(slice); + assert!(slice.iter().eq(c.index(0))); } #[test] fn test_vec_onto() { - let mut c = >>::default(); + let mut c = >>::default(); let slice = &[1u8, 2, 3][..]; - let idx = c.push(slice); - assert!(slice.iter().copied().eq(c.index(idx))); + c.push(slice); + assert!(slice.iter().eq(c.index(0))); } - #[test] - fn test_result() { - let r: Result<_, u16> = Ok("abc"); - let mut c = >>::default(); - let idx = copy(&mut c, r); - assert_eq!(r, c.index(idx)); - } + // #[test] + // fn test_result() { + // let r: Result<_, u16> = Ok("abc"); + // let mut c = >>::default(); + // let idx = copy(&mut c, r); + // assert_eq!(r, c.index(idx)); + // } #[test] fn all_types() { - fn test_copy(t: T) + fn test_copy(t: T) where - for<'a> R: Push + Push<::ReadItem<'a>>, + for<'a> R: Region + + Default + + Push + + Push<::ReadItem<'a>> + + Index + + Clone + + Clear + + HeapSize + Len, // Make sure that types are debug, even if we don't use this in the test. for<'a> R::ReadItem<'a>: Debug, { - let mut c = FlatStack::<_>::default(); - c.copy(t); + let mut c = R::default(); + c.push(t); let mut cc = c.clone(); - cc.copy(c.get(0)); + cc.push(c.index(0)); c.clear(); let mut r = R::default(); - let _ = r.push(cc.get(0)); + let _ = r.push(cc.index(0)); c.reserve_regions(std::iter::once(&r)); - let mut c = FlatStack::merge_capacity(std::iter::once(&c)); - c.copy(cc.get(0)); + let mut c = R::merge_regions(std::iter::once(&c)); + c.push(cc.index(0)); } test_copy::<_, StringRegion>(&"a".to_string()); test_copy::<_, StringRegion>("a".to_string()); test_copy::<_, StringRegion>("a"); - test_copy::<_, MirrorRegion<()>>(()); - test_copy::<_, MirrorRegion<()>>(&()); - test_copy::<_, MirrorRegion>(true); - test_copy::<_, MirrorRegion>(&true); - test_copy::<_, MirrorRegion>(' '); - test_copy::<_, MirrorRegion>(&' '); - test_copy::<_, MirrorRegion>(0u8); - test_copy::<_, MirrorRegion>(&0u8); - test_copy::<_, MirrorRegion>(0u16); - test_copy::<_, MirrorRegion>(&0u16); - test_copy::<_, MirrorRegion>(0u32); - test_copy::<_, MirrorRegion>(&0u32); - test_copy::<_, MirrorRegion>(0u64); - test_copy::<_, MirrorRegion>(&0u64); - test_copy::<_, MirrorRegion>(0u128); - test_copy::<_, MirrorRegion>(&0u128); - test_copy::<_, MirrorRegion>(0usize); - test_copy::<_, MirrorRegion>(&0usize); - test_copy::<_, MirrorRegion>(0i8); - test_copy::<_, MirrorRegion>(&0i8); - test_copy::<_, MirrorRegion>(0i16); - test_copy::<_, MirrorRegion>(&0i16); - test_copy::<_, MirrorRegion>(0i32); - test_copy::<_, MirrorRegion>(&0i32); - test_copy::<_, MirrorRegion>(0i64); - test_copy::<_, MirrorRegion>(&0i64); - test_copy::<_, MirrorRegion>(0i128); - test_copy::<_, MirrorRegion>(&0i128); - test_copy::<_, MirrorRegion>(0isize); - test_copy::<_, MirrorRegion>(&0isize); - test_copy::<_, MirrorRegion>(0f32); - test_copy::<_, MirrorRegion>(&0f32); - test_copy::<_, MirrorRegion>(0f64); - test_copy::<_, MirrorRegion>(&0f64); - test_copy::<_, MirrorRegion>>(std::num::Wrapping(0i8)); - test_copy::<_, MirrorRegion>>(&std::num::Wrapping(0i8)); - test_copy::<_, MirrorRegion>>(std::num::Wrapping(0i16)); - test_copy::<_, MirrorRegion>>(&std::num::Wrapping(0i16)); - test_copy::<_, MirrorRegion>>(std::num::Wrapping(0i32)); - test_copy::<_, MirrorRegion>>(&std::num::Wrapping(0i32)); - test_copy::<_, MirrorRegion>>(std::num::Wrapping(0i64)); - test_copy::<_, MirrorRegion>>(&std::num::Wrapping(0i64)); - test_copy::<_, MirrorRegion>>(std::num::Wrapping(0i128)); - test_copy::<_, MirrorRegion>>(&std::num::Wrapping(0i128)); - test_copy::<_, MirrorRegion>>(std::num::Wrapping(0isize)); - test_copy::<_, MirrorRegion>>(&std::num::Wrapping(0isize)); - - test_copy::<_, ResultRegion, MirrorRegion>>(Result::::Ok(0)); - test_copy::<_, ResultRegion, MirrorRegion>>(&Result::::Ok(0)); - test_copy::<_, ResultRegion, MirrorRegion>>(Result::::Err(0)); - test_copy::<_, ResultRegion, MirrorRegion>>(&Result::::Err(0)); - - test_copy::<_, SliceRegion>>([0u8].as_slice()); - test_copy::<_, SliceRegion>>(vec![0u8]); - test_copy::<_, SliceRegion>>(&vec![0u8]); + // test_copy::<_, MirrorRegion<()>>(()); + // test_copy::<_, MirrorRegion<()>>(&()); + // test_copy::<_, MirrorRegion>(true); + // test_copy::<_, MirrorRegion>(&true); + // test_copy::<_, MirrorRegion>(' '); + // test_copy::<_, MirrorRegion>(&' '); + // test_copy::<_, MirrorRegion>(0u8); + // test_copy::<_, MirrorRegion>(&0u8); + // test_copy::<_, MirrorRegion>(0u16); + // test_copy::<_, MirrorRegion>(&0u16); + // test_copy::<_, MirrorRegion>(0u32); + // test_copy::<_, MirrorRegion>(&0u32); + // test_copy::<_, MirrorRegion>(0u64); + // test_copy::<_, MirrorRegion>(&0u64); + // test_copy::<_, MirrorRegion>(0u128); + // test_copy::<_, MirrorRegion>(&0u128); + // test_copy::<_, MirrorRegion>(0usize); + // test_copy::<_, MirrorRegion>(&0usize); + // test_copy::<_, MirrorRegion>(0i8); + // test_copy::<_, MirrorRegion>(&0i8); + // test_copy::<_, MirrorRegion>(0i16); + // test_copy::<_, MirrorRegion>(&0i16); + // test_copy::<_, MirrorRegion>(0i32); + // test_copy::<_, MirrorRegion>(&0i32); + // test_copy::<_, MirrorRegion>(0i64); + // test_copy::<_, MirrorRegion>(&0i64); + // test_copy::<_, MirrorRegion>(0i128); + // test_copy::<_, MirrorRegion>(&0i128); + // test_copy::<_, MirrorRegion>(0isize); + // test_copy::<_, MirrorRegion>(&0isize); + // test_copy::<_, MirrorRegion>(0f32); + // test_copy::<_, MirrorRegion>(&0f32); + // test_copy::<_, MirrorRegion>(0f64); + // test_copy::<_, MirrorRegion>(&0f64); + // test_copy::<_, MirrorRegion>>(std::num::Wrapping(0i8)); + // test_copy::<_, MirrorRegion>>(&std::num::Wrapping(0i8)); + // test_copy::<_, MirrorRegion>>(std::num::Wrapping(0i16)); + // test_copy::<_, MirrorRegion>>(&std::num::Wrapping(0i16)); + // test_copy::<_, MirrorRegion>>(std::num::Wrapping(0i32)); + // test_copy::<_, MirrorRegion>>(&std::num::Wrapping(0i32)); + // test_copy::<_, MirrorRegion>>(std::num::Wrapping(0i64)); + // test_copy::<_, MirrorRegion>>(&std::num::Wrapping(0i64)); + // test_copy::<_, MirrorRegion>>(std::num::Wrapping(0i128)); + // test_copy::<_, MirrorRegion>>(&std::num::Wrapping(0i128)); + // test_copy::<_, MirrorRegion>>(std::num::Wrapping(0isize)); + // test_copy::<_, MirrorRegion>>(&std::num::Wrapping(0isize)); + // + // test_copy::<_, ResultRegion, MirrorRegion>>(Result::::Ok(0)); + // test_copy::<_, ResultRegion, MirrorRegion>>(&Result::::Ok(0)); + // test_copy::<_, ResultRegion, MirrorRegion>>(Result::::Err(0)); + // test_copy::<_, ResultRegion, MirrorRegion>>(&Result::::Err(0)); + // + // test_copy::<_, SliceRegion>>([0u8].as_slice()); + // test_copy::<_, SliceRegion>>(vec![0u8]); + // test_copy::<_, SliceRegion>>(&vec![0u8]); test_copy::<_, SliceRegion>(["a"].as_slice()); test_copy::<_, SliceRegion>(vec!["a"]); @@ -607,89 +648,92 @@ mod tests { test_copy::<_, <(u8, u8) as RegionPreference>::Region>((1, 2)); test_copy::<_, <(u8, u8) as RegionPreference>::Region>(&(1, 2)); - test_copy::<_, ConsecutiveIndexPairs>>([1, 2, 3].as_slice()); + // test_copy::<_, ConsecutiveIndexPairs>>([1, 2, 3].as_slice()); - test_copy::<_, CollapseSequence>>([1, 2, 3].as_slice()); - test_copy::<_, CollapseSequence>>(&[1, 2, 3]); + // test_copy::<_, CollapseSequence>>([1, 2, 3].as_slice()); + // test_copy::<_, CollapseSequence>>(&[1, 2, 3]); test_copy::<_, OptionRegion>(Some("abc")); test_copy::<_, OptionRegion>(&Some("abc")); test_copy::<_, OptionRegion>(Option::<&'static str>::None); test_copy::<_, OptionRegion>(&Option::<&'static str>::None); - test_copy::<_, ResultRegion>>( - Result::<&'static str, u8>::Ok("abc"), - ); - test_copy::<_, ResultRegion>>( - &Result::<&'static str, u8>::Ok("abc"), - ); - test_copy::<_, ResultRegion>>( - Result::<&'static str, u8>::Err(1), - ); - test_copy::<_, ResultRegion>>( - Result::<&'static str, u8>::Err(2), - ); + // test_copy::<_, ResultRegion>>( + // Result::<&'static str, u8>::Ok("abc"), + // ); + // test_copy::<_, ResultRegion>>( + // &Result::<&'static str, u8>::Ok("abc"), + // ); + // test_copy::<_, ResultRegion>>( + // Result::<&'static str, u8>::Err(1), + // ); + // test_copy::<_, ResultRegion>>( + // Result::<&'static str, u8>::Err(2), + // ); } #[test] fn slice_region_read_item() { fn is_clone(_: &T) {} - let mut c = FlatStack::>>::default(); - c.copy(vec![1, 2, 3]); + let mut c = >>::default(); + c.push(vec![1, 2, 3]); - let mut r = SliceRegion::>::default(); - let idx = r.push([1, 2, 3]); - let read_item = r.index(idx); + let mut r = SliceRegion::>::default(); + r.push([1, 2, 3]); + let read_item = r.index(0); is_clone(&read_item); let _read_item3 = read_item; - assert_eq!(vec![1, 2, 3], read_item.into_iter().collect::>()); + assert_eq!( + vec![1, 2, 3], + read_item.into_iter().copied().collect::>() + ); } #[test] fn nested_slice_copy() { - let mut c = FlatStack::default_impl::<[[[[[u8; 1]; 1]; 1]; 1]; 1]>(); - - c.copy([[[[[1]]]]]); - c.copy(&[[[[[1]]]]]); - c.copy(&[[[[[&1]]]]]); - c.copy([[[[[&1]]]]]); - c.copy([[&[[[&1]]]]]); - c.copy([[[[[1]]; 1]; 1]; 1]); - c.copy(&[[[[[1; 1]; 1]; 1]; 1]; 1]); - c.copy(&[[[[[&1; 1]; 1]; 1]; 1]; 1]); - c.copy([[[[[&1; 1]; 1]; 1]; 1]; 1]); - c.copy([[&[[[&1; 1]; 1]; 1]; 1]; 1]); - c.copy([[vec![[[1; 1]; 1]; 1]; 1]; 1]); - c.copy(&[[vec![[[1; 1]; 1]; 1]; 1]; 1]); - c.copy(&[[vec![[[&1; 1]; 1]; 1]; 1]; 1]); - c.copy([[[vec![[&1; 1]; 1]; 1]; 1]; 1]); - c.copy([[&vec![[[&1; 1]; 1]; 1]; 1]; 1]); + let mut c = <[[[[[u8; 1]; 1]; 1]; 1]; 1] as RegionPreference>::Region::default(); + + c.push([[[[[1]]]]]); + c.push(&[[[[[1]]]]]); + c.push(&[[[[[&1]]]]]); + c.push([[[[[&1]]]]]); + c.push([[&[[[&1]]]]]); + c.push([[[[[1]]; 1]; 1]; 1]); + c.push(&[[[[[1; 1]; 1]; 1]; 1]; 1]); + c.push(&[[[[[&1; 1]; 1]; 1]; 1]; 1]); + c.push([[[[[&1; 1]; 1]; 1]; 1]; 1]); + c.push([[&[[[&1; 1]; 1]; 1]; 1]; 1]); + c.push([[vec![[[1; 1]; 1]; 1]; 1]; 1]); + c.push(&[[vec![[[1; 1]; 1]; 1]; 1]; 1]); + c.push(&[[vec![[[&1; 1]; 1]; 1]; 1]; 1]); + c.push([[[vec![[&1; 1]; 1]; 1]; 1]; 1]); + c.push([[&vec![[[&1; 1]; 1]; 1]; 1]; 1]); } #[test] fn test_owned() { - fn owned_roundtrip(region: &mut R, index: R::Index) + fn owned_roundtrip(region: &mut R, index: usize) where - for<'a> R: Region + Push<<::ReadItem<'a> as IntoOwned<'a>>::Owned>, + for<'a> R: Index + Push<<::ReadItem<'a> as IntoOwned<'a>>::Owned> + Len, for<'a> R::ReadItem<'a>: IntoOwned<'a, Owned = O> + Eq + Debug, { let item = region.index(index); let owned = item.into_owned(); - let index2 = region.push(owned); + region.push(owned); let item = region.index(index); - assert_eq!(item, region.index(index2)); + assert_eq!(item, region.index(region.len() - 1)); } let mut c = ::default(); - let index = c.push("abc".to_string()); - owned_roundtrip::(&mut c, index); + c.push("abc".to_string()); + owned_roundtrip::(&mut c, 0); } /// Test that items and owned variants can be reborrowed to shorten their lifetimes. fn _test_reborrow(item: R::ReadItem<'_>, owned: &R::Owned) where - R: Region, + R: Index, for<'a> R::ReadItem<'a>: Eq, { // The following line requires `reborrow` because otherwise owned must outlive '_. @@ -704,4 +748,3 @@ mod tests { let _ = R::reborrow(item) == R::reborrow(IntoOwned::borrow_as(owned)); } } -*/ diff --git a/src/primitive.rs b/src/primitive.rs new file mode 100644 index 0000000..7e116bd --- /dev/null +++ b/src/primitive.rs @@ -0,0 +1,60 @@ +//! Support for primitive types. + +use crate::{IntoOwned, RegionPreference}; + +macro_rules! impl_region_preference { + ($($index_type:ty),*) => { + $( + impl RegionPreference for $index_type { + type Owned = Self; + type Region = Vec; + } + + impl<'a> IntoOwned<'a> for $index_type { + type Owned = $index_type; + + #[inline] + fn into_owned(self) -> Self::Owned { + self + } + + #[inline] + fn clone_onto(self, other: &mut Self::Owned) { + *other = self; + } + + #[inline] + fn borrow_as(owned: &'a Self::Owned) -> Self { + *owned + } + } + )* + }; +} + +impl_region_preference!( + u8, + u16, + u32, + u64, + u128, + usize, + i8, + i16, + i32, + i64, + i128, + isize, + f32, + f64, + char, + bool, + (), + std::num::Wrapping, + std::num::Wrapping, + std::num::Wrapping, + std::num::Wrapping, + std::num::Wrapping, + std::num::Wrapping, + std::time::Duration +); diff --git a/src/rank_select.rs b/src/rank_select.rs new file mode 100644 index 0000000..be37ea3 --- /dev/null +++ b/src/rank_select.rs @@ -0,0 +1,182 @@ +//! Rank select structures + +use crate::bitmap::Bools; +use crate::{Clear, HeapSize, Index, IndexAs, Len, Push, Region, Reserve, ReserveItems}; +use serde::{Deserialize, Serialize}; + +#[derive(Default, Clone, Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct RankSelect, V = Vec> { + counts: C, + values: Bools, +} + +impl Region for RankSelect { + fn merge_regions<'a>(regions: impl Iterator + Clone) -> Self + where + Self: 'a, + { + Self { + counts: C::merge_regions(regions.clone().map(|r| &r.counts)), + values: Bools::merge_regions(regions.map(|r| &r.values)), + } + } + + fn reserve_regions<'a, I>(&mut self, regions: I) + where + Self: 'a, + I: Iterator + Clone, + { + self.counts + .reserve_regions(regions.clone().map(|r| &r.counts)); + self.values.reserve_regions(regions.map(|r| &r.values)); + } +} + +impl HeapSize for RankSelect +where + C: HeapSize, + V: HeapSize, +{ + fn heap_size(&self, mut callback: F) { + self.counts.heap_size(&mut callback); + self.values.heap_size(callback); + } +} + +impl Clear for RankSelect +where + C: Clear, + V: Clear, +{ + fn clear(&mut self) { + self.counts.clear(); + self.values.clear(); + } +} + +impl Len for RankSelect +where + V: Len, +{ + fn len(&self) -> usize { + self.values.len() + } +} + +impl RankSelect +where + C: IndexAs + Len, + V: IndexAs + Len, +{ + pub fn rank(&self, index: usize) -> usize { + let bit = index % 64; + let block = index / 64; + let chunk = block / 16; + let mut count = if chunk > 0 { + self.counts.index_as(chunk - 1) as usize + } else { + 0 + }; + for index in (chunk * 16)..block { + count += self.counts.index_as(index).count_ones() as usize; + } + let word = self.values.last_block().0; + let mask = (1 << bit) - 1; + let bits = word & mask; + count + bits.count_ones() as usize + } + + #[allow(unused)] + pub fn select(&self, rank: u64) -> Option { + let mut chunk = 0; + while chunk < self.counts.len() && self.counts.index_as(chunk) <= rank { + chunk += 1; + } + let mut count = if chunk < self.counts.len() { + self.counts.index_as(chunk) + } else { + 0 + }; + let mut block = chunk * 16; + while block < self.values.blocks() + && count + ::from(self.values.block(block).0.count_ones()) <= rank + { + count += ::from(self.values.block(block).0.count_ones()); + block += 1; + } + + let (last_word, last_bits) = self.values.last_block(); + for shift in 0..last_bits { + if last_word & (1 << shift) != 0 && count + 1 == rank { + return Some(block * 64 + shift as usize); + } + count += last_word & (1 << shift); + } + + None + } +} + +impl Push for RankSelect +where + C: Push + Len + IndexAs, + V: Push + Len + IndexAs, +{ + fn push(&mut self, item: bool) { + self.values.push(item); + while self.counts.len() < self.values.len() / 1024 { + let mut count = if self.counts.is_empty() { + 0 + } else { + self.counts.index_as(self.counts.len() - 1) + }; + let lower = self.counts.len() * 16; + let upper = lower + 16; + for index in lower..upper { + count += self.values.block(index).0.count_ones() as u64; + } + self.counts.push(count); + } + } +} + +impl IndexAs for RankSelect +where + V: IndexAs + Len, +{ + fn index_as(&self, index: usize) -> bool { + self.values.index(index) + } +} + +impl ReserveItems for RankSelect +where + C: Reserve, + V: Reserve, +{ + fn reserve_items(&mut self, items: I) + where + I: Iterator + Clone, + { + self.counts.reserve((items.clone().count() + 1023) / 1024); + self.values.reserve_items(items.clone()); + } +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_rank() { + let mut rs = ::default(); + rs.push(true); + assert_eq!(rs.rank(0), 0); + assert_eq!(rs.select(0), None); + assert_eq!(rs.select(1), None); + rs.push(true); + assert_eq!(rs.rank(0), 0); + assert_eq!(rs.select(0), None); + assert_eq!(rs.select(1), Some(0)); + } +} From 429e4db69306c37768639a14b3e78a4cb96c1373 Mon Sep 17 00:00:00 2001 From: Moritz Hoffmann Date: Fri, 8 Nov 2024 17:35:48 +0100 Subject: [PATCH 3/5] Result works Signed-off-by: Moritz Hoffmann --- README.md | 4 +- src/impls.rs | 2 +- src/impls/result.rs | 145 ++++++++++++++++++++++++++++++-------------- src/impls/slice.rs | 4 +- src/lib.rs | 49 +++++++-------- 5 files changed, 127 insertions(+), 77 deletions(-) diff --git a/README.md b/README.md index 0f5dda5..952aa5e 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,12 @@ flatcontainer = "0.6" ## Example ```rust -use flatcontainer::{Index, RegionPreference}; +use flatcontainer::{Index, Push, RegionPreference}; let r: Result<_, u16> = Ok("abc"); let mut c = < as RegionPreference>::Region>::default(); c.push(&r); -assert_eq!(r, c.index(0)); +assert_eq!(Ok("abc"), c.index(0)); ``` ## Details diff --git a/src/impls.rs b/src/impls.rs index 9380937..d0a2c61 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -7,7 +7,7 @@ // pub mod index; // pub mod mirror; pub mod option; -// pub mod result; +pub mod result; pub mod slice; pub mod slice_owned; pub mod string; diff --git a/src/impls/result.rs b/src/impls/result.rs index 99ea871..5e92f5a 100644 --- a/src/impls/result.rs +++ b/src/impls/result.rs @@ -3,7 +3,10 @@ #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use crate::{IntoOwned, Push, Region, RegionPreference, ReserveItems}; +use crate::rank_select::RankSelect; +use crate::{ + Clear, HeapSize, Index, IndexAs, IntoOwned, Len, Push, Region, RegionPreference, ReserveItems, +}; impl RegionPreference for Result { type Owned = Result; @@ -16,93 +19,130 @@ impl RegionPreference for Result /// /// Add results to a result region: /// ``` -/// use flatcontainer::{RegionPreference, Push, Region, ResultRegion}; -/// let mut r = -/// ::Region, ::Region>>::default(); +/// use flatcontainer::{RegionPreference, Push, Region, ResultRegion, Index}; +/// let mut r = as RegionPreference>::Region::default(); /// -/// let ok_index = r.push(Result::<(), String>::Ok(())); -/// let err_index = r.push(Result::<(), String>::Err("Error".to_string())); +/// r.push(Result::<(), String>::Ok(())); +/// r.push(Result::<(), String>::Err("Error".to_string())); /// -/// assert_eq!(Ok(()), r.index(ok_index)); -/// assert_eq!(Err("Error"), r.index(err_index)); +/// assert_eq!(Ok(&()), r.index(0)); +/// assert_eq!(Err("Error"), r.index(1)); /// ``` #[derive(Default, Debug)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct ResultRegion { +pub struct ResultRegion, RV = Vec> { + ranks: RankSelect, oks: T, errs: E, } -impl Clone for ResultRegion { +impl Clone for ResultRegion { fn clone(&self) -> Self { Self { + ranks: self.ranks.clone(), oks: self.oks.clone(), errs: self.errs.clone(), } } fn clone_from(&mut self, source: &Self) { + self.ranks.clone_from(&source.ranks); self.oks.clone_from(&source.oks); self.errs.clone_from(&source.errs); } } -impl Region for ResultRegion +impl Region for ResultRegion where T: Region, E: Region, + RC: Region, + RV: Region, { - type Owned = Result; - type ReadItem<'a> = Result, E::ReadItem<'a>> where Self: 'a; - type Index = Result; - #[inline] fn merge_regions<'a>(regions: impl Iterator + Clone) -> Self where Self: 'a, { Self { + ranks: RankSelect::merge_regions(regions.clone().map(|r| &r.ranks)), oks: T::merge_regions(regions.clone().map(|r| &r.oks)), errs: E::merge_regions(regions.map(|r| &r.errs)), } } - #[inline] - fn index(&self, index: Self::Index) -> Self::ReadItem<'_> { - match index { - Ok(index) => Ok(self.oks.index(index)), - Err(index) => Err(self.errs.index(index)), - } - } - #[inline] fn reserve_regions<'a, I>(&mut self, regions: I) where Self: 'a, I: Iterator + Clone, { + self.ranks + .reserve_regions(regions.clone().map(|r| &r.ranks)); self.oks.reserve_regions(regions.clone().map(|r| &r.oks)); self.errs.reserve_regions(regions.map(|r| &r.errs)); } +} + +impl Index for ResultRegion +where + T: Index, + E: Index, + RC: IndexAs + Len, + RV: IndexAs + Len, +{ + type Owned = Result; + type ReadItem<'a> = Result, E::ReadItem<'a>> where Self: 'a; + + #[inline] + fn index(&self, index: usize) -> Self::ReadItem<'_> { + if self.ranks.index_as(index) { + Ok(self.oks.index(self.ranks.rank(index))) + } else { + Err(self.errs.index(index - self.ranks.rank(index))) + } + } + #[inline] + fn reborrow<'b, 'a: 'b>(item: Self::ReadItem<'a>) -> Self::ReadItem<'b> + where + Self: 'a, + { + item.map(T::reborrow).map_err(E::reborrow) + } +} + +impl Clear for ResultRegion +where + T: Clear, + E: Clear, +{ #[inline] fn clear(&mut self) { self.oks.clear(); self.errs.clear(); } +} +impl HeapSize for ResultRegion +where + T: HeapSize, + E: HeapSize, +{ #[inline] fn heap_size(&self, mut callback: F) { self.oks.heap_size(&mut callback); self.errs.heap_size(callback); } +} +impl Len for ResultRegion +where + RV: Len, +{ #[inline] - fn reborrow<'b, 'a: 'b>(item: Self::ReadItem<'a>) -> Self::ReadItem<'b> - where - Self: 'a, - { - item.map(T::reborrow).map_err(E::reborrow) + fn len(&self) -> usize { + self.ranks.len() } } @@ -134,35 +174,51 @@ where } } -impl Push> for ResultRegion +impl Push> for ResultRegion where - TC: Region + Push, - EC: Region + Push, + TC: Push, + EC: Push, + RC: IndexAs + Len + Push, + RV: IndexAs + Len + Push, { #[inline] - fn push(&mut self, item: Result) -> as Region>::Index { + fn push(&mut self, item: Result) { match item { - Ok(t) => Ok(self.oks.push(t)), - Err(e) => Err(self.errs.push(e)), + Ok(t) => { + self.ranks.push(true); + self.oks.push(t); + } + Err(r) => { + self.ranks.push(false); + self.errs.push(r); + } } } } -impl<'a, T: 'a, TC, E: 'a, EC> Push<&'a Result> for ResultRegion +impl<'a, T: 'a, TC, E: 'a, EC, RC, RV> Push<&'a Result> for ResultRegion where - TC: Region + Push<&'a T>, - EC: Region + Push<&'a E>, + TC: Push<&'a T>, + EC: Push<&'a E>, + RC: IndexAs + Len + Push, + RV: IndexAs + Len + Push, { #[inline] - fn push(&mut self, item: &'a Result) -> as Region>::Index { + fn push(&mut self, item: &'a Result) { match item { - Ok(t) => Ok(self.oks.push(t)), - Err(e) => Err(self.errs.push(e)), + Ok(t) => { + self.ranks.push(true); + self.oks.push(t); + } + Err(r) => { + self.ranks.push(false); + self.errs.push(r); + } } } } -impl ReserveItems> for ResultRegion +impl ReserveItems> for ResultRegion where TC: Region + ReserveItems, EC: Region + ReserveItems, @@ -177,7 +233,8 @@ where } } -impl<'a, T: 'a, TC, E: 'a, EC> ReserveItems<&'a Result> for ResultRegion +impl<'a, T: 'a, TC, E: 'a, EC, RC, RV> ReserveItems<&'a Result> + for ResultRegion where TC: Region + ReserveItems<&'a T>, EC: Region + ReserveItems<&'a E>, @@ -196,13 +253,13 @@ where #[cfg(test)] mod tests { - use crate::{MirrorRegion, OwnedRegion, Region, ReserveItems}; + use crate::{OwnedRegion, ReserveItems}; use super::*; #[test] fn test_reserve() { - let mut r = , MirrorRegion>>::default(); + let mut r = , Vec>>::default(); ReserveItems::reserve_items(&mut r, [Ok(0), Err(1)].iter()); ReserveItems::reserve_items(&mut r, [Ok(0), Err(1)].into_iter()); diff --git a/src/impls/slice.rs b/src/impls/slice.rs index 4780cb1..1cb49f1 100644 --- a/src/impls/slice.rs +++ b/src/impls/slice.rs @@ -50,13 +50,13 @@ type Idx = u64; /// .split(" ") /// .collect::>(); /// -/// r.push(&panagram_en); /// r.push(&panagram_de); +/// r.push(&panagram_en); /// /// assert!(panagram_de.into_iter().eq(r.index(0))); /// assert!(panagram_en.into_iter().eq(r.index(1))); /// -/// assert_eq!(r.index(1).get(2), "jagen"); +/// assert_eq!(r.index(0).get(2), "jagen"); /// ``` #[derive(Debug)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] diff --git a/src/lib.rs b/src/lib.rs index 2c7c738..008b721 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,7 +13,7 @@ mod rank_select; // pub use impls::columns::ColumnsRegion; // pub use impls::mirror::MirrorRegion; pub use impls::option::OptionRegion; -// pub use impls::result::ResultRegion; +pub use impls::result::ResultRegion; pub use impls::slice::SliceRegion; pub use impls::slice_owned::OwnedRegion; pub use impls::string::StringRegion; @@ -492,13 +492,13 @@ mod tests { use super::*; - // #[test] - // fn test_readme() { - // let r: Result<_, u16> = Ok("abc"); - // let mut c = FlatStack::default_impl::>(); - // c.copy(r); - // assert_eq!(r, c.get(0)); - // } + #[test] + fn test_readme() { + let r: Result<_, u16> = Ok("abc"); + let mut c = as RegionPreference>::Region::default(); + c.push(r); + assert_eq!(Ok("abc"), c.index(0)); + } #[test] fn test_slice_string_onto() { @@ -534,13 +534,13 @@ mod tests { assert!(slice.iter().eq(c.index(0))); } - // #[test] - // fn test_result() { - // let r: Result<_, u16> = Ok("abc"); - // let mut c = >>::default(); - // let idx = copy(&mut c, r); - // assert_eq!(r, c.index(idx)); - // } + #[test] + fn test_result() { + let r: Result<_, u16> = Ok("abc"); + let mut c = >>::default(); + c.push(r); + assert_eq!(Ok("abc"), c.index(0)); + } #[test] fn all_types() { @@ -553,7 +553,8 @@ mod tests { + Index + Clone + Clear - + HeapSize + Len, + + HeapSize + + Len, // Make sure that types are debug, even if we don't use this in the test. for<'a> R::ReadItem<'a>: Debug, { @@ -658,18 +659,10 @@ mod tests { test_copy::<_, OptionRegion>(Option::<&'static str>::None); test_copy::<_, OptionRegion>(&Option::<&'static str>::None); - // test_copy::<_, ResultRegion>>( - // Result::<&'static str, u8>::Ok("abc"), - // ); - // test_copy::<_, ResultRegion>>( - // &Result::<&'static str, u8>::Ok("abc"), - // ); - // test_copy::<_, ResultRegion>>( - // Result::<&'static str, u8>::Err(1), - // ); - // test_copy::<_, ResultRegion>>( - // Result::<&'static str, u8>::Err(2), - // ); + test_copy::<_, ResultRegion>>(Result::<&'static str, u8>::Ok("abc")); + test_copy::<_, ResultRegion>>(&Result::<&'static str, u8>::Ok("abc")); + test_copy::<_, ResultRegion>>(Result::<&'static str, u8>::Err(1)); + test_copy::<_, ResultRegion>>(Result::<&'static str, u8>::Err(2)); } #[test] From fca4279aad879e200c06b0c167a0dc4116c25c45 Mon Sep 17 00:00:00 2001 From: Moritz Hoffmann Date: Fri, 8 Nov 2024 21:10:06 +0100 Subject: [PATCH 4/5] bench Signed-off-by: Moritz Hoffmann --- benches/bench.rs | 149 ++++++++++++++++++++------------------- src/impls.rs | 1 - src/impls/slice.rs | 4 +- src/impls/slice_owned.rs | 14 ++-- src/impls/vec.rs | 22 ++++-- src/lib.rs | 13 ++++ 6 files changed, 112 insertions(+), 91 deletions(-) diff --git a/benches/bench.rs b/benches/bench.rs index d951bff..cdce25b 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -1,12 +1,10 @@ //! A simple benchmark for flatcontainer, adopted from `columnation`'s benchmark. -/* + use codspeed_bencher_compat::{benchmark_group, benchmark_main, Bencher}; -use flatcontainer::impls::deduplicate::{CollapseSequence, ConsecutiveIndexPairs}; -use flatcontainer::impls::index::IndexOptimized; use flatcontainer::impls::tuple::{TupleABCRegion, TupleABRegion}; use flatcontainer::{ - ColumnsRegion, FlatStack, MirrorRegion, OwnedRegion, Push, Region, RegionPreference, - ReserveItems, SliceRegion, StringRegion, + Clear, HeapSize, Index, OwnedRegion, Push, RegionPreference, ReserveItems, SliceRegion, + StringRegion, }; fn empty_copy(bencher: &mut Bencher) { @@ -64,12 +62,12 @@ fn str100_copy_region(bencher: &mut Bencher) { fn string10_copy_region(bencher: &mut Bencher) { _bench_copy_region::, _>(bencher, vec![format!("grawwwwrr!"); 1024]); } -fn string10_copy_region_collapse(bencher: &mut Bencher) { - _bench_copy_region::< - SliceRegion>, IndexOptimized>, - _, - >(bencher, vec![format!("grawwwwrr!"); 1024]); -} +// fn string10_copy_region_collapse(bencher: &mut Bencher) { +// _bench_copy_region::< +// SliceRegion>, IndexOptimized>, +// _, +// >(bencher, vec![format!("grawwwwrr!"); 1024]); +// } fn string20_copy_region(bencher: &mut Bencher) { _bench_copy_region::, _>( bencher, @@ -77,37 +75,37 @@ fn string20_copy_region(bencher: &mut Bencher) { ); } fn vec_u_s_copy_region(bencher: &mut Bencher) { - _bench_copy_region::, StringRegion>>>, _>( + _bench_copy_region::, StringRegion>>>, _>( bencher, vec![vec![(0u64, "grawwwwrr!".to_string()); 32]; 32], ); } fn vec_u_vn_s_copy_region(bencher: &mut Bencher) { _bench_copy_region::< - SliceRegion, OwnedRegion<_>, StringRegion>>>, - _, - >( - bencher, - vec![vec![(0u64, vec![(); 1 << 40], "grawwwwrr!".to_string()); 32]; 32], - ); -} -fn vec_u_vn_s_copy_region_column(bencher: &mut Bencher) { - _bench_copy_region::< - SliceRegion< - ColumnsRegion< - TupleABCRegion< - MirrorRegion<_>, - CollapseSequence>, - CollapseSequence, - >, - >, - >, + SliceRegion, OwnedRegion<()>, StringRegion>>>, _, >( bencher, vec![vec![(0u64, vec![(); 1 << 40], "grawwwwrr!".to_string()); 32]; 32], ); } +// fn vec_u_vn_s_copy_region_column(bencher: &mut Bencher) { +// _bench_copy_region::< +// SliceRegion< +// ColumnsRegion< +// TupleABCRegion< +// MirrorRegion<_>, +// CollapseSequence>, +// CollapseSequence, +// >, +// >, +// >, +// _, +// >( +// bencher, +// vec![vec![(0u64, vec![(); 1 << 40], "grawwwwrr!".to_string()); 32]; 32], +// ); +// } fn empty_clone(bencher: &mut Bencher) { _bench_clone(bencher, vec![(); 1024]); @@ -276,37 +274,37 @@ fn string20_copy_flat_region(bencher: &mut Bencher) { ); } fn vec_u_s_copy_flat_region(bencher: &mut Bencher) { - _bench_copy_flat::, StringRegion>>>, _>( + _bench_copy_flat::, StringRegion>>>, _>( bencher, vec![vec![(0u64, "grawwwwrr!".to_string()); 32]; 32], ); } fn vec_u_vn_s_copy_flat_region(bencher: &mut Bencher) { _bench_copy_flat::< - SliceRegion, OwnedRegion<_>, StringRegion>>>, - _, - >( - bencher, - vec![vec![(0u64, vec![(); 1 << 40], "grawwwwrr!".to_string()); 32]; 32], - ); -} -fn vec_u_vn_s_copy_flat_region_column(bencher: &mut Bencher) { - _bench_copy_flat::< - SliceRegion< - ColumnsRegion< - TupleABCRegion< - MirrorRegion<_>, - CollapseSequence>, - CollapseSequence, - >, - >, - >, + SliceRegion, OwnedRegion<()>, StringRegion>>>, _, >( bencher, vec![vec![(0u64, vec![(); 1 << 40], "grawwwwrr!".to_string()); 32]; 32], ); } +// fn vec_u_vn_s_copy_flat_region_column(bencher: &mut Bencher) { +// _bench_copy_flat::< +// SliceRegion< +// ColumnsRegion< +// TupleABCRegion< +// MirrorRegion<_>, +// CollapseSequence>, +// CollapseSequence, +// >, +// >, +// >, +// _, +// >( +// bencher, +// vec![vec![(0u64, vec![(); 1 << 40], "grawwwwrr!".to_string()); 32]; 32], +// ); +// } fn set_bytes(target: &mut u64, bytes: usize) { if std::env::var("BYTES").is_ok() { @@ -316,15 +314,15 @@ fn set_bytes(target: &mut u64, bytes: usize) { fn _bench_copy(bencher: &mut Bencher, record: T) where - for<'a> ::Region: Push<&'a T>, + for<'a> ::Region: Default + HeapSize + Clear + Push<&'a T>, { // prepare encoded data for bencher.bytes - let mut arena = FlatStack::default_impl::(); + let mut arena = T::Region::default(); bencher.iter(|| { arena.clear(); for _ in 0..1024 { - arena.copy(&record); + arena.push(&record); } }); let (mut siz, mut cap) = (0, 0); @@ -335,17 +333,17 @@ where set_bytes(&mut bencher.bytes, siz); } -fn _bench_copy_region(bencher: &mut Bencher, record: T) +fn _bench_copy_region(bencher: &mut Bencher, record: T) where - for<'a> R: Push<&'a T>, + for<'a> R: Default + HeapSize + Clear + Push<&'a T>, { // prepare encoded data for bencher.bytes - let mut arena = FlatStack::::default(); + let mut arena = R::default(); bencher.iter(|| { arena.clear(); for _ in 0..1024 { - arena.copy(&record); + arena.push(&record); } }); let (mut siz, mut cap) = (0, 0); @@ -370,14 +368,14 @@ fn _bench_clone(bencher: &mut Bencher, record: fn _bench_realloc(bencher: &mut Bencher, record: T) where - for<'a> ::Region: Push<&'a T>, + for<'a> ::Region: Default + HeapSize + Push<&'a T>, { - let mut arena = FlatStack::default_impl::(); + let mut arena = T::Region::default(); bencher.iter(|| { // prepare encoded data for bencher.bytes - arena = FlatStack::default_impl::(); + arena = T::Region::default(); for _ in 0..1024 { - arena.copy(&record); + arena.push(&record); } }); let (mut siz, mut cap) = (0, 0); @@ -389,15 +387,15 @@ where fn _bench_prealloc(bencher: &mut Bencher, record: T) where - for<'a> ::Region: ReserveItems<&'a T> + Push<&'a T>, + for<'a> ::Region: Default + HeapSize + ReserveItems<&'a T> + Push<&'a T>, { - let mut arena = FlatStack::default_impl::(); + let mut arena = T::Region::default(); bencher.iter(|| { - arena = FlatStack::default_impl::(); + arena = T::Region::default(); // prepare encoded data for bencher.bytes arena.reserve_items(std::iter::repeat(&record).take(1024)); for _ in 0..1024 { - arena.copy(&record); + arena.push(&record); } }); let (mut siz, mut cap) = (0, 0); @@ -411,22 +409,26 @@ where fn _bench_copy_flat_preference(bencher: &mut Bencher, record: T) where T: RegionPreference, - for<'a> ::Region: - Push<&'a T> + Push<<::Region as Region>::ReadItem<'a>> + Clone, + for<'a> ::Region: Default + + Index + + HeapSize + + Push<&'a T> + + Push<<::Region as Index>::ReadItem<'a>> + + Clone, { _bench_copy_flat::(bencher, record) } fn _bench_copy_flat(bencher: &mut Bencher, record: T) where - for<'a> R: Region + Push<&'a T> + Push<::ReadItem<'a>> + Clone, + for<'a> R: Default + Index + HeapSize + Push<&'a T> + Push<::ReadItem<'a>> + Clone, { // prepare encoded data for bencher.bytes - let mut arena = FlatStack::::default(); + let mut arena = R::default(); for _ in 0..1024 { - arena.copy(&record); + arena.push(&record); } - let mut target = FlatStack::::default(); + let mut target = R::default(); bencher.iter(|| { target.clone_from(&arena); @@ -486,7 +488,7 @@ benchmark_group!( str10_copy_region, string10_copy_flat_region, string10_copy_region, - string10_copy_region_collapse, + // string10_copy_region_collapse, string20_copy_flat_region, string20_copy_region, u32x2_copy_flat_region, @@ -498,9 +500,9 @@ benchmark_group!( vec_u_s_copy_flat_region, vec_u_s_copy_region, vec_u_vn_s_copy_flat_region, - vec_u_vn_s_copy_flat_region_column, + // vec_u_vn_s_copy_flat_region_column, vec_u_vn_s_copy_region, - vec_u_vn_s_copy_region_column, + // vec_u_vn_s_copy_region_column, ); benchmark_group!( alloc, @@ -524,4 +526,3 @@ benchmark_group!( vec_u_vn_s_realloc, ); benchmark_main!(clone, copy, copy_flat, copy_region, alloc); -*/ diff --git a/src/impls.rs b/src/impls.rs index d0a2c61..0f4c5fc 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -5,7 +5,6 @@ // pub mod deduplicate; // pub mod huffman_container; // pub mod index; -// pub mod mirror; pub mod option; pub mod result; pub mod slice; diff --git a/src/impls/slice.rs b/src/impls/slice.rs index 1cb49f1..65884b6 100644 --- a/src/impls/slice.rs +++ b/src/impls/slice.rs @@ -437,9 +437,7 @@ where { #[inline] fn push(&mut self, items: &'a [T]) { - for item in items.iter() { - self.inner.push(item); - } + self.inner.push_extend(items); self.bounds .push(self.inner.len().try_into().expect("must fit")); } diff --git a/src/impls/slice_owned.rs b/src/impls/slice_owned.rs index 3e34f60..0d34924 100644 --- a/src/impls/slice_owned.rs +++ b/src/impls/slice_owned.rs @@ -6,7 +6,9 @@ use std::marker::PhantomData; use serde::{Deserialize, Serialize}; // use crate::impls::storage::{PushStorage, Storage}; -use crate::{Clear, HeapSize, Index, IndexAs, Len, Push, PushIter, Region, Reserve, ReserveItems}; +use crate::{ + Clear, HeapSize, Index, IndexAs, Len, Push, PushIter, PushSlice, Region, Reserve, ReserveItems, +}; type Idx = u64; @@ -174,9 +176,7 @@ where { #[inline] fn push(&mut self, items: [T; N]) { - for item in items { - self.slices.push(item); - } + self.slices.push_extend(items); self.bounds .push(self.slices.len().try_into().expect("must fit")); } @@ -220,14 +220,12 @@ where impl Push<&[T]> for OwnedRegion where T: Clone, - S: for<'a> Push<&'a T> + Len, + S: PushSlice + Len, B: Push, { #[inline] fn push(&mut self, items: &[T]) { - for item in items { - self.slices.push(item); - } + self.slices.push_slice(items); self.bounds .push(self.slices.len().try_into().expect("must fit")); } diff --git a/src/impls/vec.rs b/src/impls/vec.rs index 3aa1f25..a2dea8b 100644 --- a/src/impls/vec.rs +++ b/src/impls/vec.rs @@ -1,6 +1,6 @@ //! Definitions to use `Vec` as a region. -use crate::{Clear, HeapSize, Index, IndexAs, Len, Push, Region, Reserve, ReserveItems}; +use crate::{Clear, HeapSize, Index, IndexAs, Len, Push, PushSlice, Region, Reserve, ReserveItems}; impl Region for Vec { #[inline(always)] @@ -49,18 +49,30 @@ impl Push for Vec { fn push(&mut self, item: T) { self.push(item); } + + #[inline(always)] + fn push_extend>(&mut self, iter: I) { + Extend::extend(self, iter); + } +} + +impl PushSlice for Vec { + #[inline(always)] + fn push_slice(&mut self, slice: &[T]) { + self.extend_from_slice(slice); + } } -impl Push<&T> for Vec { +impl<'a, T: Clone> Push<&'a T> for Vec { #[inline(always)] - fn push(&mut self, item: &T) { + fn push(&mut self, item: &'a T) { self.push(item.clone()); } } -impl Push<&&T> for Vec { +impl<'a, 'b, T: Clone> Push<&'a &'b T> for Vec { #[inline(always)] - fn push(&mut self, item: &&T) { + fn push(&mut self, item: &'a &'b T) { self.push((*item).clone()); } } diff --git a/src/lib.rs b/src/lib.rs index 008b721..ebb8dfe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -63,6 +63,19 @@ impl RegionPreference for &T { pub trait Push { /// Push `item` into self. fn push(&mut self, item: T); + + /// Pushes many items into self. + fn push_extend>(&mut self, iter: I) { + for item in iter { + self.push(item); + } + } +} + +/// TODO +pub trait PushSlice { + /// TODO + fn push_slice(&mut self, slice: &[T]); } /// Reserve space in the receiving region. From 6a6bac3b9cb8b3967c54154baba695749d43c5ea Mon Sep 17 00:00:00 2001 From: Moritz Hoffmann Date: Fri, 15 Nov 2024 21:25:09 +0100 Subject: [PATCH 5/5] columns work Signed-off-by: Moritz Hoffmann --- src/impls.rs | 2 +- src/impls/columns.rs | 438 ++++++++++++++++++--------------------- src/impls/result.rs | 3 + src/impls/slice.rs | 4 +- src/impls/slice_owned.rs | 60 +++++- src/impls/vec.rs | 4 + src/lib.rs | 14 +- 7 files changed, 275 insertions(+), 250 deletions(-) diff --git a/src/impls.rs b/src/impls.rs index 0f4c5fc..5b1dedc 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -1,7 +1,7 @@ //! Various region implementations. // pub mod codec; -// pub mod columns; +pub mod columns; // pub mod deduplicate; // pub mod huffman_container; // pub mod index; diff --git a/src/impls/columns.rs b/src/impls/columns.rs index 5ccb772..43b02f3 100644 --- a/src/impls/columns.rs +++ b/src/impls/columns.rs @@ -7,10 +7,8 @@ use std::slice::Iter; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use crate::impls::deduplicate::ConsecutiveIndexPairs; -use crate::impls::index::{IndexContainer, IndexOptimized}; -use crate::{IntoOwned, PushIter}; -use crate::{OwnedRegion, Push, Region}; +use crate::{Clear, HeapSize, Index, IntoOwned, Len, PushIter, PushSlice}; +use crate::{Push, Region}; /// A region that can store a variable number of elements per row. /// @@ -25,8 +23,7 @@ use crate::{OwnedRegion, Push, Region}; /// /// Copy a table-like structure: /// ``` -/// # use flatcontainer::impls::deduplicate::ConsecutiveIndexPairs; -/// # use flatcontainer::{ColumnsRegion, Push, Region, StringRegion}; +/// # use flatcontainer::{ColumnsRegion, Index, OwnedRegion, Push, Region, StringRegion}; /// let data = [ /// vec![], /// vec!["1"], @@ -37,45 +34,27 @@ use crate::{OwnedRegion, Push, Region}; /// vec![], /// ]; /// -/// let mut r = >>::default(); -/// -/// let mut indices = Vec::with_capacity(data.len()); +/// let mut r = >>::default(); /// /// for row in &data { -/// let index = r.push(row); -/// indices.push(index); +/// r.push(row); /// } /// -/// for (&index, row) in indices.iter().zip(&data) { +/// for (index, row) in data.iter().enumerate() { /// assert!(row.iter().copied().eq(r.index(index).iter())); /// } /// ``` #[derive(Debug)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr( - feature = "serde", - serde(bound = " - R: Serialize + for<'a> Deserialize<'a>, - R::Index: Serialize + for<'a> Deserialize<'a>, - O: Serialize + for<'a> Deserialize<'a>, - ") -)] -pub struct ColumnsRegion -where - R: Region, -{ +pub struct ColumnsRegion { /// Indices to address rows in `inner`. For each row, we remember /// an index for each column. - indices: ConsecutiveIndexPairs, O>, + indices: O, /// Storage for columns. inner: Vec, } -impl Clone for ColumnsRegion -where - R: Region + Clone, - O: Clone, -{ +impl Clone for ColumnsRegion { fn clone(&self) -> Self { Self { indices: self.indices.clone(), @@ -89,15 +68,7 @@ where } } -impl Region for ColumnsRegion -where - R: Region, - O: IndexContainer, -{ - type Owned = Vec; - type ReadItem<'a> = ReadColumns<'a, R> where Self: 'a; - type Index = , IndexOptimized> as Region>::Index; - +impl Region for ColumnsRegion { fn merge_regions<'a>(regions: impl Iterator + Clone) -> Self where Self: 'a, @@ -112,18 +83,11 @@ where } Self { - indices: ConsecutiveIndexPairs::merge_regions(regions.map(|r| &r.indices)), + indices: O::merge_regions(regions.map(|r| &r.indices)), inner, } } - fn index(&self, index: Self::Index) -> Self::ReadItem<'_> { - ReadColumns(Ok(ReadColumnsInner { - columns: &self.inner, - index: self.indices.index(index), - })) - } - fn reserve_regions<'a, I>(&mut self, regions: I) where Self: 'a, @@ -137,87 +101,100 @@ where for (index, inner) in self.inner.iter_mut().enumerate() { inner.reserve_regions(regions.clone().filter_map(|r| r.inner.get(index))); } + + self.indices.reserve_regions(regions.map(|r| &r.indices)); } +} - fn clear(&mut self) { - for inner in &mut self.inner { - inner.clear(); +impl Default for ColumnsRegion { + fn default() -> Self { + Self { + indices: O::default(), + inner: Vec::default(), } - self.indices.clear(); } +} +impl HeapSize for ColumnsRegion { fn heap_size(&self, mut callback: F) { - let size_of_r = std::mem::size_of::(); - callback( - self.inner.len() * size_of_r, - self.inner.capacity() * size_of_r, - ); + self.inner.heap_size(&mut callback); for inner in &self.inner { inner.heap_size(&mut callback); } self.indices.heap_size(callback); } +} - fn reborrow<'b, 'a: 'b>(item: Self::ReadItem<'a>) -> Self::ReadItem<'b> - where - Self: 'a, - { - item +impl Clear for ColumnsRegion { + fn clear(&mut self) { + for inner in &mut self.inner { + inner.clear(); + } + self.indices.clear(); } } -impl Default for ColumnsRegion +impl Len for ColumnsRegion { + fn len(&self) -> usize { + self.indices.len() + } + + fn is_empty(&self) -> bool { + self.indices.is_empty() + } +} + +impl Index for ColumnsRegion where - R: Region, - O: IndexContainer, + R: Index, + for<'a> O: Index = &'a [usize]> + 'a, { - fn default() -> Self { - Self { - indices: ConsecutiveIndexPairs::default(), - inner: Vec::default(), - } + type Owned = Vec; + type ReadItem<'a> = ReadColumns<'a, R, R::Owned> where Self: 'a; + + fn index(&self, index: usize) -> Self::ReadItem<'_> { + ReadColumns(Ok(ReadColumnsInner { + columns: &self.inner, + index: self.indices.index(index), + })) + } + + fn reborrow<'b, 'a: 'b>(item: Self::ReadItem<'a>) -> Self::ReadItem<'b> + where + Self: 'a, + { + item } } /// Read the values of a row. -pub struct ReadColumns<'a, R>(Result, &'a [R::Owned]>) -where - R: Region; +pub struct ReadColumns<'a, R, O>(Result, &'a [O]>); -struct ReadColumnsInner<'a, R> -where - R: Region, -{ +struct ReadColumnsInner<'a, R> { /// Storage for columns. columns: &'a [R], /// Indices to retrieve values from columns. - index: &'a [R::Index], + index: &'a [usize], } -impl<'a, R> Clone for ReadColumns<'a, R> -where - R: Region, -{ +impl<'a, R, O> Clone for ReadColumns<'a, R, O> { fn clone(&self) -> Self { *self } } -impl<'a, R> Clone for ReadColumnsInner<'a, R> -where - R: Region, -{ +impl<'a, R> Clone for ReadColumnsInner<'a, R> { fn clone(&self) -> Self { *self } } -impl<'a, R> Copy for ReadColumns<'a, R> where R: Region {} -impl<'a, R> Copy for ReadColumnsInner<'a, R> where R: Region {} +impl<'a, R, O> Copy for ReadColumns<'a, R, O> {} +impl<'a, R> Copy for ReadColumnsInner<'a, R> {} -impl<'a, R> Debug for ReadColumns<'a, R> +impl<'a, R, O> Debug for ReadColumns<'a, R, O> where - R: Region, + R: Index, R::ReadItem<'a>: Debug, { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -225,13 +202,13 @@ where } } -impl<'a, R> ReadColumns<'a, R> +impl<'a, R, O> ReadColumns<'a, R, O> where - R: Region, + R: Index, { /// Iterate the individual values of a row. #[must_use] - pub fn iter(&'a self) -> ReadColumnsIter<'a, R> { + pub fn iter(&'a self) -> ReadColumnsIter<'a, R, O> { self.into_iter() } @@ -243,10 +220,10 @@ where Err(slice) => IntoOwned::borrow_as(&slice[offset]), } } - +} +impl<'a, R, O> Len for ReadColumns<'a, R, O> { /// Returns the length of this row. - #[must_use] - pub fn len(&self) -> usize { + fn len(&self) -> usize { match &self.0 { Ok(inner) => inner.len(), Err(slice) => slice.len(), @@ -254,8 +231,7 @@ where } /// Returns `true` if this row is empty. - #[must_use] - pub fn is_empty(&self) -> bool { + fn is_empty(&self) -> bool { match &self.0 { Ok(inner) => inner.is_empty(), Err(slice) => slice.is_empty(), @@ -264,32 +240,29 @@ where } impl<'a, R> ReadColumnsInner<'a, R> where - R: Region, + R: Index, { /// Get the element at `offset`. #[must_use] pub fn get(&self, offset: usize) -> R::ReadItem<'a> { self.columns[offset].index(self.index[offset]) } - - /// Returns the length of this row. - #[must_use] - pub fn len(&self) -> usize { +} +impl<'a, R> Len for ReadColumnsInner<'a, R> { + fn len(&self) -> usize { self.index.len() } - /// Returns `true` if this row is empty. - #[must_use] - pub fn is_empty(&self) -> bool { + fn is_empty(&self) -> bool { self.index.is_empty() } } -impl<'a, R> IntoOwned<'a> for ReadColumns<'a, R> +impl<'a, R, O> IntoOwned<'a> for ReadColumns<'a, R, O> where - R: Region, + R: Index, { - type Owned = Vec; + type Owned = Vec; #[inline] fn into_owned(self) -> Self::Owned { @@ -310,12 +283,12 @@ where } } -impl<'a, R> IntoIterator for &ReadColumns<'a, R> +impl<'a, R, O> IntoIterator for &ReadColumns<'a, R, O> where - R: Region, + R: Index, { type Item = R::ReadItem<'a>; - type IntoIter = ReadColumnsIter<'a, R>; + type IntoIter = ReadColumnsIter<'a, R, O>; fn into_iter(self) -> Self::IntoIter { match self.0 { @@ -328,16 +301,16 @@ where } /// An iterator over the elements of a row. -pub struct ReadColumnsIter<'a, R: Region>(Result, Iter<'a, R::Owned>>); +pub struct ReadColumnsIter<'a, R, O>(Result, Iter<'a, O>>); /// An iterator over the elements of a row. -pub struct ReadColumnsIterInner<'a, R: Region> { - iter: Zip, Iter<'a, R>>, +pub struct ReadColumnsIterInner<'a, R> { + iter: Zip, Iter<'a, R>>, } -impl<'a, R> Iterator for ReadColumnsIter<'a, R> +impl<'a, R, O> Iterator for ReadColumnsIter<'a, R, O> where - R: Region, + R: Index, { type Item = R::ReadItem<'a>; @@ -356,16 +329,19 @@ where } } -impl<'a, R> ExactSizeIterator for ReadColumnsIter<'a, R> where R: Region {} +impl<'a, R, O> ExactSizeIterator for ReadColumnsIter<'a, R, O> where R: Index {} impl<'a, R> Iterator for ReadColumnsIterInner<'a, R> where - R: Region, + R: Index, { type Item = R::ReadItem<'a>; fn next(&mut self) -> Option { - self.iter.next().map(|(&i, r)| r.index(i)) + self.iter.next().map(|(&i, r)| { + println!("i: {i}"); + r.index(i) + }) } fn size_hint(&self) -> (usize, Option) { @@ -373,144 +349,147 @@ where } } -impl Push> for ColumnsRegion +impl Push> for ColumnsRegion where - for<'a> R: Region + Push<::ReadItem<'a>>, - O: IndexContainer, + R: Default + Index + Len + for<'a> Push<::ReadItem<'a>>, + O: PushSlice, { - fn push(&mut self, item: ReadColumns<'_, R>) -> as Region>::Index { + fn push(&mut self, item: ReadColumns<'_, R, Owned>) { // Ensure all required regions exist. while self.inner.len() < item.len() { self.inner.push(R::default()); } - let iter = item - .iter() - .zip(&mut self.inner) - .map(|(value, region)| region.push(value)); - self.indices.push(PushIter(iter)) + for (value, region) in item.iter().zip(&mut self.inner) { + region.push(value); + } + self.indices + .push_iter(self.inner.iter().take(item.len()).map(|r| r.len() - 1)); } } impl<'a, R, O, T> Push<&'a [T]> for ColumnsRegion where - R: Region + Push<&'a T>, - O: IndexContainer, + R: Default + Len + Push<&'a T>, + O: PushSlice, { - fn push(&mut self, item: &'a [T]) -> as Region>::Index { + fn push(&mut self, item: &'a [T]) { // Ensure all required regions exist. while self.inner.len() < item.len() { self.inner.push(R::default()); } - let iter = item - .iter() - .zip(&mut self.inner) - .map(|(value, region)| region.push(value)); - self.indices.push(PushIter(iter)) + for (value, region) in item.iter().zip(&mut self.inner) { + region.push(value); + } + self.indices + .push_iter(self.inner.iter().take(item.len()).map(|r| r.len() - 1)); } } impl Push<[T; N]> for ColumnsRegion where - R: Region + Push, - O: IndexContainer, + R: Default + Len + Push, + O: PushSlice, { - fn push(&mut self, item: [T; N]) -> as Region>::Index { + fn push(&mut self, item: [T; N]) { // Ensure all required regions exist. while self.inner.len() < item.len() { self.inner.push(R::default()); } - let iter = item - .into_iter() - .zip(&mut self.inner) - .map(|(value, region)| region.push(value)); - self.indices.push(PushIter(iter)) + let columns = item.len(); + for (value, region) in item.into_iter().zip(&mut self.inner) { + region.push(value); + } + self.indices + .push_iter(self.inner.iter().take(columns).map(|r| r.len() - 1)); } } impl<'a, R, O, T, const N: usize> Push<&'a [T; N]> for ColumnsRegion where - R: Region + Push<&'a T>, - O: IndexContainer, + R: Default + Len + Push<&'a T>, + O: PushSlice, { - fn push(&mut self, item: &'a [T; N]) -> as Region>::Index { + fn push(&mut self, item: &'a [T; N]) { // Ensure all required regions exist. while self.inner.len() < item.len() { self.inner.push(R::default()); } - let iter = item - .iter() - .zip(&mut self.inner) - .map(|(value, region)| region.push(value)); - self.indices.push(PushIter(iter)) + for (value, region) in item.into_iter().zip(&mut self.inner) { + region.push(value); + } + self.indices + .push_iter(self.inner.iter().take(item.len()).map(|r| r.len() - 1)); } } impl Push> for ColumnsRegion where - R: Region + Push, - O: IndexContainer, + R: Default + Len + Push, + O: PushSlice, { - fn push(&mut self, item: Vec) -> as Region>::Index { + fn push(&mut self, item: Vec) { // Ensure all required regions exist. while self.inner.len() < item.len() { self.inner.push(R::default()); } - let iter = item - .into_iter() - .zip(&mut self.inner) - .map(|(value, region)| region.push(value)); - self.indices.push(PushIter(iter)) + let columns = item.len(); + for (value, region) in item.into_iter().zip(&mut self.inner) { + region.push(value); + } + self.indices + .push_iter(self.inner.iter().take(columns).map(|r| r.len() - 1)); } } impl<'a, R, O, T> Push<&'a Vec> for ColumnsRegion where - R: Region + Push<&'a T>, - O: IndexContainer, + R: Default + Len + Push<&'a T>, + O: PushSlice, { - fn push(&mut self, item: &'a Vec) -> as Region>::Index { + fn push(&mut self, item: &'a Vec) { // Ensure all required regions exist. while self.inner.len() < item.len() { self.inner.push(R::default()); } - let iter = item - .iter() - .zip(&mut self.inner) - .map(|(value, region)| region.push(value)); - self.indices.push(PushIter(iter)) + for (value, region) in item.into_iter().zip(&mut self.inner) { + region.push(value); + } + self.indices + .push_iter(self.inner.iter().take(item.len()).map(|r| r.len() - 1)); } } impl Push> for ColumnsRegion where - R: Region + Push, - O: IndexContainer, + R: Default + Len + Push, I: IntoIterator, - I::IntoIter: ExactSizeIterator, + O: PushSlice, { #[inline] - fn push(&mut self, item: PushIter) -> as Region>::Index { - let iter = item.0.into_iter().enumerate().map(|(index, value)| { + fn push(&mut self, item: PushIter) { + let mut columns = 0; + for (index, value) in item.0.into_iter().enumerate() { // Ensure all required regions exist. if self.inner.len() <= index { self.inner.push(R::default()); } - self.inner[index].push(value) - }); - self.indices.push(PushIter(iter)) + self.inner[index].push(value); + columns += 1; + } + self.indices + .push_iter(self.inner.iter().take(columns).map(|r| r.len() - 1)); } } #[cfg(test)] mod tests { - use crate::impls::deduplicate::{CollapseSequence, ConsecutiveIndexPairs}; - use crate::{MirrorRegion, OwnedRegion, Push, PushIter, Region, StringRegion}; + use crate::{OwnedRegion, Push, PushIter, Region, StringRegion}; use super::*; @@ -518,17 +497,16 @@ mod tests { fn test_matrix() { let data = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; - let mut r = ColumnsRegion::>::default(); - - let mut indices = Vec::with_capacity(data.len()); + let mut r = ColumnsRegion::, OwnedRegion>::default(); for row in &data { - let index = r.push(row.as_slice()); - indices.push(index); + // r.push(row.as_slice()); + Push::push(&mut r, row); + // r.push(row.as_slice()); } - for (index, row) in indices.iter().zip(&data) { - assert!(row.iter().copied().eq(r.index(index).iter())); + for (read, row) in r.iter().zip(&data) { + assert!(row.iter().eq(read.iter())); } } @@ -544,17 +522,14 @@ mod tests { [].as_slice(), ]; - let mut r = ColumnsRegion::>::default(); - - let mut indices = Vec::with_capacity(data.len()); + let mut r = ColumnsRegion::, OwnedRegion>::default(); for row in &data { - let index = r.push(*row); - indices.push(index); + r.push(*row); } - for (index, row) in indices.iter().zip(&data) { - assert!(row.iter().copied().eq(r.index(index).iter())); + for (read, row) in r.iter().zip(&data) { + assert!(row.iter().eq(read.iter())); } println!("{r:?}"); @@ -572,18 +547,14 @@ mod tests { vec![], ]; - let mut r = - ColumnsRegion::>>::default(); - - let mut indices = Vec::with_capacity(data.len()); + let mut r = ColumnsRegion::>::default(); for row in &data { - let index = r.push(row); - indices.push(index); + r.push(row); } - for (index, row) in indices.iter().zip(&data) { - assert!(row.iter().eq(r.index(index).iter())); + for (read, row) in r.iter().zip(&data) { + assert!(row.iter().eq(read.iter())); } println!("{r:?}"); @@ -601,17 +572,14 @@ mod tests { vec![], ]; - let mut r = ColumnsRegion::>::default(); - - let mut indices = Vec::with_capacity(data.len()); + let mut r = ColumnsRegion::>::default(); for row in &data { - let index = r.push(row); - indices.push(index); + r.push(row); } - for (index, row) in indices.iter().zip(&data) { - assert!(row.iter().eq(r.index(index).iter())); + for (read, row) in r.iter().zip(&data) { + assert!(row.iter().copied().eq(read.iter())); } println!("{r:?}"); @@ -629,23 +597,21 @@ mod tests { vec![], ]; - let mut r = ColumnsRegion::>::default(); - - let mut indices = Vec::with_capacity(data.len()); + let mut r = ColumnsRegion::>::default(); for row in &data { - let index = r.push(PushIter(row.iter())); - indices.push(index); + r.push(PushIter(row.iter())); } - for (index, row) in indices.iter().zip(&data) { - assert!(row.iter().eq(r.index(index).iter())); + for (read, row) in r.iter().zip(&data) { + println!("{read:?} {row:?}"); + assert!(row.iter().copied().eq(read.iter())); } - assert_eq!("1", r.index(indices[1]).get(0)); - assert_eq!(1, r.index(indices[1]).len()); - assert!(!r.index(indices[1]).is_empty()); - assert!(r.index(indices[0]).is_empty()); + assert_eq!("1", r.index(1).get(0)); + assert_eq!(1, r.index(1).len()); + assert!(!r.index(1).is_empty()); + assert!(r.index(0).is_empty()); println!("{r:?}"); } @@ -654,13 +620,18 @@ mod tests { fn read_columns_push() { let data = [[[1]; 4]; 4]; - let mut r = >>::default(); - let mut r2 = >>::default(); + let mut r = , OwnedRegion>>::default(); + let mut r2 = , OwnedRegion>>::default(); for row in &data { - let idx = r.push(row); - let idx2 = r2.push(r.index(idx)); - assert!(r.index(idx).iter().eq(r2.index(idx2).iter())); + r.push(row); + println!("{r:?}"); + r2.push(r.index(r.len() - 1)); + println!("{r2:?}"); + assert!(r + .index(r.len() - 1) + .iter() + .eq(r2.index(r2.len() - 1).iter())); } } @@ -669,31 +640,30 @@ mod tests { fn test_clear() { let data = [[[1]; 4]; 4]; - let mut r = >>::default(); + let mut r = , OwnedRegion>>::default(); - let mut idx = None; for row in &data { - idx = Some(r.push(row)); + r.push(row); } r.clear(); - let _ = r.index(idx.unwrap()); + let _ = r.index(0); } #[test] fn copy_reserve_regions() { let data = [[[1]; 4]; 4]; - let mut r = >>::default(); + let mut r = , OwnedRegion>>::default(); for row in &data { - let _ = r.push(row); + r.push(row); } for row in data { - let _ = r.push(row); + r.push(row); } - let mut r2 = >>::default(); + let mut r2 = , OwnedRegion>>::default(); r2.reserve_regions(std::iter::once(&r)); let mut cap = 0; @@ -713,10 +683,10 @@ mod tests { vec![], ]; - let mut r = ColumnsRegion::>::default(); + let mut r = ColumnsRegion::>::default(); for row in &data { - let _ = r.push(PushIter(row.iter())); + r.push(PushIter(row.iter())); } let (mut siz1, mut cap1) = (0, 0); @@ -727,7 +697,7 @@ mod tests { let mut r2 = ColumnsRegion::merge_regions(std::iter::once(&r)); for row in &data { - let _ = r2.push(PushIter(row.iter())); + r2.push(PushIter(row.iter())); } let (mut siz2, mut cap2) = (0, 0); diff --git a/src/impls/result.rs b/src/impls/result.rs index 5e92f5a..7e58298 100644 --- a/src/impls/result.rs +++ b/src/impls/result.rs @@ -116,9 +116,12 @@ impl Clear for ResultRegion where T: Clear, E: Clear, + RC: Clear, + RV: Clear, { #[inline] fn clear(&mut self) { + self.ranks.clear(); self.oks.clear(); self.errs.clear(); } diff --git a/src/impls/slice.rs b/src/impls/slice.rs index 65884b6..ed42b0a 100644 --- a/src/impls/slice.rs +++ b/src/impls/slice.rs @@ -453,7 +453,7 @@ where where I: Iterator + Clone, { - self.bounds.reserve(1); + self.bounds.reserve(items.clone().count()); self.inner.reserve_items(items.flatten()); } } @@ -604,7 +604,7 @@ where where I: Iterator> + Clone, { - self.bounds.reserve(1); + self.bounds.reserve(items.clone().count()); self.inner.reserve_items(items.flatten()); } } diff --git a/src/impls/slice_owned.rs b/src/impls/slice_owned.rs index 0d34924..b5178bf 100644 --- a/src/impls/slice_owned.rs +++ b/src/impls/slice_owned.rs @@ -156,6 +156,7 @@ where .try_into() .expect("must fit") }; + println!("start: {}", start); let end = self.bounds.index_as(index).try_into().expect("must fit"); &self.slices[start..end] } @@ -171,12 +172,12 @@ where impl Push<[T; N]> for OwnedRegion where - S: Push + Len, + S: PushSlice + Len, B: Push, { #[inline] fn push(&mut self, items: [T; N]) { - self.slices.push_extend(items); + self.slices.push_iter(items); self.bounds .push(self.slices.len().try_into().expect("must fit")); } @@ -259,14 +260,25 @@ where impl Push> for OwnedRegion where - S: Push + Len, + S: PushSlice + Len, B: Push, { #[inline] - fn push(&mut self, items: Vec) { - for item in items { - self.slices.push(item); - } + fn push(&mut self, mut items: Vec) { + self.slices.push_owned(&mut items); + self.bounds + .push(self.slices.len().try_into().expect("must fit")); + } +} + +impl Push<&mut Vec> for OwnedRegion +where + S: PushSlice + Len, + B: Push, +{ + #[inline] + fn push(&mut self, items: &mut Vec) { + self.slices.push_owned(items); self.bounds .push(self.slices.len().try_into().expect("must fit")); } @@ -298,14 +310,12 @@ where impl Push> for OwnedRegion where I: IntoIterator, - S: Push + Len, + S: PushSlice + Len, B: Push, { #[inline] fn push(&mut self, items: PushIter) { - for item in items { - self.slices.push(item); - } + self.slices.push_iter(items); self.bounds .push(self.slices.len().try_into().expect("must fit")); } @@ -326,6 +336,34 @@ where } } +impl PushSlice for OwnedRegion +where + T: Clone, + S: PushSlice + Len, + B: Push, +{ + #[inline] + fn push_slice(&mut self, slice: &[T]) { + self.slices.push_slice(slice); + self.bounds + .push(self.slices.len().try_into().expect("must fit")); + } + + #[inline] + fn push_owned(&mut self, owned: &mut Vec) { + self.slices.push_owned(owned); + self.bounds + .push(self.slices.len().try_into().expect("must fit")); + } + + #[inline] + fn push_iter(&mut self, iter: impl IntoIterator) { + self.slices.push_iter(iter); + self.bounds + .push(self.slices.len().try_into().expect("must fit")); + } +} + #[cfg(test)] mod tests { use crate::{Push, PushIter, ReserveItems}; diff --git a/src/impls/vec.rs b/src/impls/vec.rs index a2dea8b..26064ad 100644 --- a/src/impls/vec.rs +++ b/src/impls/vec.rs @@ -61,6 +61,10 @@ impl PushSlice for Vec { fn push_slice(&mut self, slice: &[T]) { self.extend_from_slice(slice); } + + fn push_iter(&mut self, iter: impl IntoIterator) { + self.extend(iter); + } } impl<'a, T: Clone> Push<&'a T> for Vec { diff --git a/src/lib.rs b/src/lib.rs index ebb8dfe..33cf24b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,8 +10,7 @@ mod rank_select; // pub mod storage; // use crate::impls::index::IndexContainer; -// pub use impls::columns::ColumnsRegion; -// pub use impls::mirror::MirrorRegion; +pub use impls::columns::ColumnsRegion; pub use impls::option::OptionRegion; pub use impls::result::ResultRegion; pub use impls::slice::SliceRegion; @@ -76,6 +75,15 @@ pub trait Push { pub trait PushSlice { /// TODO fn push_slice(&mut self, slice: &[T]); + + /// TOOD + fn push_owned(&mut self, owned: &mut Vec) { + self.push_slice(owned); + owned.clear(); + } + + /// TODO + fn push_iter(&mut self, iter: impl IntoIterator); } /// Reserve space in the receiving region. @@ -407,8 +415,10 @@ pub trait IndexAs { /// TODO pub trait Len { /// TODO + #[must_use] fn len(&self) -> usize; /// TODO + #[must_use] fn is_empty(&self) -> bool { self.len() == 0 }