From bcefc47158cb39688bec662eeffcf574807c4ccd Mon Sep 17 00:00:00 2001 From: Moritz Hoffmann Date: Tue, 13 Feb 2024 10:26:24 -0500 Subject: [PATCH] Experiment: allow mutable access This adds an `index_mut` API to regions, which permits mutable access if the region is capable of it. Regions that cannot permit mutable access can default to delegating to `index` instead. Signed-off-by: Moritz Hoffmann --- src/codec.rs | 9 +++-- src/impls/columns.rs | 74 ++++++++++++++++++++++++++++++++++++++++ src/impls/deduplicate.rs | 20 +++++++++-- src/impls/mirror.rs | 5 +++ src/impls/option.rs | 5 +++ src/impls/result.rs | 8 +++++ src/impls/slice.rs | 5 +++ src/impls/slice_copy.rs | 24 +++++++++++++ src/impls/string.rs | 12 +++++++ src/impls/tuple.rs | 8 +++++ src/lib.rs | 14 ++++++++ 11 files changed, 178 insertions(+), 6 deletions(-) diff --git a/src/codec.rs b/src/codec.rs index f8fb40d..df3a31c 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -83,9 +83,8 @@ where for<'a> R: Region = &'a [u8]> + 'a, for<'a> &'a [u8]: CopyOnto, { - type ReadItem<'a> = &'a [u8] - where - Self: 'a; + type ReadItem<'a> = &'a [u8] where Self: 'a; + type ReadItemMut<'a> = Self::ReadItem<'a> where Self: 'a; type Index = R::Index; @@ -106,6 +105,10 @@ where self.codec.decode(self.inner.index(index)) } + fn index_mut(&mut self, index: Self::Index) -> Self::ReadItemMut<'_> { + self.index(index) + } + fn reserve_regions<'a, I>(&mut self, regions: I) where Self: 'a, diff --git a/src/impls/columns.rs b/src/impls/columns.rs index 618939d..1919721 100644 --- a/src/impls/columns.rs +++ b/src/impls/columns.rs @@ -40,6 +40,7 @@ where Idx: Index, { type ReadItem<'a> = ReadColumns<'a, R, Idx> where Self: 'a; + type ReadItemMut<'a> = ReadColumnsMut<'a, R, Idx> where Self: 'a; type Index = usize; fn merge_regions<'a>(regions: impl Iterator + Clone) -> Self @@ -68,6 +69,13 @@ where } } + fn index_mut(&mut self, index: Self::Index) -> Self::ReadItemMut<'_> { + ReadColumnsMut { + columns: &mut self.inner, + index: self.indices.index(index), + } + } + fn reserve_regions<'a, I>(&mut self, regions: I) where Self: 'a, @@ -104,6 +112,72 @@ where } } +/// Read the values of a row. +pub struct ReadColumnsMut<'a, R, Idx> +where + R: Region, + Idx: Index, +{ + /// Storage for columns. + columns: &'a mut [R], + /// Indices to retrieve values from columns. + index: &'a [Idx], +} + +impl<'a, R, Idx> ReadColumnsMut<'a, R, Idx> +where + R: Region, + Idx: Index, +{ + /// Iterate the individual values of a row. + pub fn iter(&'a mut self) -> impl Iterator> { + self.index + .iter() + .zip(self.columns.iter_mut()) + .map(|(idx, r)| r.index_mut(*idx)) + } + + /// Get the element at `offset`. + pub fn get(&'a mut self, offset: usize) -> R::ReadItemMut<'a> { + self.columns[offset].index_mut(self.index[offset]) + } + + /// Returns the length of this row. + pub fn len(&self) -> usize { + self.index.len() + } + + /// Returns `true` if this row is empty. + pub fn is_empty(&self) -> bool { + self.index.is_empty() + } +} + +impl<'a, R, Idx> CopyOnto> for ReadColumnsMut<'a, R, Idx> +where + R: Region, + Idx: Index, +{ + fn copy_onto( + self, + target: &mut ColumnsRegion, + ) -> as Region>::Index { + // Ensure all required regions exist. + while target.inner.len() < self.len() { + target.inner.push(R::default()); + } + + let iter = self + .index + .iter() + .zip(self.columns.iter_mut()) + .map(|(idx, r)| r.index_mut(*idx)) + .zip(&mut target.inner) + .map(|(value, region)| value.copy_onto(region)); + CopyIter(iter).copy_onto(&mut target.indices) + } +} + /// Read the values of a row. #[derive(Copy)] pub struct ReadColumns<'a, R, Idx> diff --git a/src/impls/deduplicate.rs b/src/impls/deduplicate.rs index 2f4cda2..055c94b 100644 --- a/src/impls/deduplicate.rs +++ b/src/impls/deduplicate.rs @@ -26,6 +26,11 @@ where for<'a, 'b> R::ReadItem<'a>: PartialEq>, { type ReadItem<'a> = R::ReadItem<'a> where Self: 'a; + + // Important: We do not permit mutable access to our contents because multiple + // indices can reference the same data. + type ReadItemMut<'a> = R::ReadItem<'a> where Self: 'a; + type Index = R::Index; fn merge_regions<'a>(regions: impl Iterator + Clone) -> Self @@ -42,6 +47,10 @@ where self.inner.index(index) } + fn index_mut(&mut self, index: Self::Index) -> Self::ReadItemMut<'_> { + self.index(index) + } + fn reserve_regions<'a, I>(&mut self, regions: I) where Self: 'a, @@ -109,9 +118,9 @@ impl, O: OffsetContainer> Default impl, O: OffsetContainer> Region for ConsecutiveOffsetPairs { - type ReadItem<'a> = R::ReadItem<'a> - where - Self: 'a; + type ReadItem<'a> = R::ReadItem<'a> where Self: 'a; + + type ReadItemMut<'a> = R::ReadItemMut<'a> where Self: 'a; type Index = usize; @@ -133,6 +142,11 @@ impl, O: OffsetContainer> Region .index((self.offsets.index(index), self.offsets.index(index + 1))) } + fn index_mut(&mut self, index: Self::Index) -> Self::ReadItemMut<'_> { + self.inner + .index_mut((self.offsets.index(index), self.offsets.index(index + 1))) + } + fn reserve_regions<'a, I>(&mut self, regions: I) where Self: 'a, diff --git a/src/impls/mirror.rs b/src/impls/mirror.rs index a4f8520..f488cd7 100644 --- a/src/impls/mirror.rs +++ b/src/impls/mirror.rs @@ -42,6 +42,7 @@ impl Debug for MirrorRegion { impl> Region for MirrorRegion { type ReadItem<'a> = T where T: 'a; + type ReadItemMut<'a> = T where Self: 'a; type Index = T; fn merge_regions<'a>(_regions: impl Iterator + Clone) -> Self @@ -56,6 +57,10 @@ impl> Region for MirrorRegion { index } + fn index_mut(&mut self, index: Self::Index) -> Self::ReadItemMut<'_> { + index + } + #[inline(always)] fn reserve_regions<'a, I>(&mut self, _regions: I) where diff --git a/src/impls/option.rs b/src/impls/option.rs index ae476c2..e38c2d8 100644 --- a/src/impls/option.rs +++ b/src/impls/option.rs @@ -33,6 +33,7 @@ pub struct OptionRegion { impl Region for OptionRegion { type ReadItem<'a> = Option> where Self: 'a; + type ReadItemMut<'a> = Option> where Self: 'a; type Index = Option; fn merge_regions<'a>(regions: impl Iterator + Clone) -> Self @@ -49,6 +50,10 @@ impl Region for OptionRegion { index.map(|t| self.inner.index(t)) } + fn index_mut(&mut self, index: Self::Index) -> Self::ReadItemMut<'_> { + index.map(|t| self.inner.index_mut(t)) + } + #[inline] fn reserve_regions<'a, I>(&mut self, regions: I) where diff --git a/src/impls/result.rs b/src/impls/result.rs index 79bb2b9..c20f70c 100644 --- a/src/impls/result.rs +++ b/src/impls/result.rs @@ -38,6 +38,7 @@ where E: Region, { type ReadItem<'a> = Result, E::ReadItem<'a>> where Self: 'a; + type ReadItemMut<'a> = Result, E::ReadItemMut<'a>> where Self: 'a; type Index = Result; fn merge_regions<'a>(regions: impl Iterator + Clone) -> Self @@ -58,6 +59,13 @@ where } } + fn index_mut(&mut self, index: Self::Index) -> Self::ReadItemMut<'_> { + match index { + Ok(index) => Ok(self.oks.index_mut(index)), + Err(index) => Err(self.errs.index_mut(index)), + } + } + #[inline] fn reserve_regions<'a, I>(&mut self, regions: I) where diff --git a/src/impls/slice.rs b/src/impls/slice.rs index 0545dc6..e1a32b2 100644 --- a/src/impls/slice.rs +++ b/src/impls/slice.rs @@ -61,6 +61,7 @@ pub struct SliceRegion = Vec<> Region for SliceRegion { type ReadItem<'a> = ReadSlice<'a, C, O> where Self: 'a; + type ReadItemMut<'a> = ReadSlice<'a, C, O> where Self: 'a; type Index = (usize, usize); fn merge_regions<'a>(regions: impl Iterator + Clone) -> Self @@ -82,6 +83,10 @@ impl> Region for SliceRegion { } } + fn index_mut(&mut self, index: Self::Index) -> Self::ReadItemMut<'_> { + self.index(index) + } + #[inline] fn reserve_regions<'a, I>(&mut self, regions: I) where diff --git a/src/impls/slice_copy.rs b/src/impls/slice_copy.rs index 9309c53..04bad43 100644 --- a/src/impls/slice_copy.rs +++ b/src/impls/slice_copy.rs @@ -30,6 +30,7 @@ pub struct CopyRegion { impl Region for CopyRegion { type ReadItem<'a> = &'a [T] where Self: 'a; + type ReadItemMut<'a> = &'a mut [T] where Self: 'a; type Index = (usize, usize); fn merge_regions<'a>(regions: impl Iterator + Clone) -> Self @@ -46,6 +47,10 @@ impl Region for CopyRegion { &self.slices[start..end] } + fn index_mut(&mut self, (start, end): Self::Index) -> Self::ReadItemMut<'_> { + &mut self.slices[start..end] + } + fn reserve_regions<'a, I>(&mut self, regions: I) where Self: 'a, @@ -89,6 +94,25 @@ impl ReserveItems> for &[T] { } } +impl CopyOnto> for &mut [T] +where + T: Copy, +{ + #[inline] + fn copy_onto(self, target: &mut CopyRegion) -> as Region>::Index { + (&*self).copy_onto(target) + } +} + +impl ReserveItems> for &mut [T] { + fn reserve_items(target: &mut CopyRegion, items: I) + where + I: Iterator + Clone, + { + ReserveItems::reserve_items(target, items.map(|r| &*r)); + } +} + impl CopyOnto> for &Vec where T: Copy, diff --git a/src/impls/string.rs b/src/impls/string.rs index 693ae00..2702433 100644 --- a/src/impls/string.rs +++ b/src/impls/string.rs @@ -32,6 +32,7 @@ pub struct StringRegion { impl Region for StringRegion { type ReadItem<'a> = &'a str where Self: 'a ; + type ReadItemMut<'a> = &'a mut str where Self: 'a; type Index = as Region>::Index; fn merge_regions<'a>(regions: impl Iterator + Clone) -> Self @@ -48,6 +49,10 @@ impl Region for StringRegion { unsafe { std::str::from_utf8_unchecked(self.inner.index(index)) } } + fn index_mut(&mut self, index: Self::Index) -> Self::ReadItemMut<'_> { + unsafe { std::str::from_utf8_unchecked_mut(self.inner.index_mut(index)) } + } + fn reserve_regions<'a, I>(&mut self, regions: I) where Self: 'a, @@ -100,6 +105,13 @@ impl CopyOnto for &str { } } +impl CopyOnto for &mut str { + #[inline] + fn copy_onto(self, target: &mut StringRegion) -> ::Index { + <&str as CopyOnto>::copy_onto(self, target) + } +} + impl CopyOnto for &&str { #[inline] fn copy_onto(self, target: &mut StringRegion) -> ::Index { diff --git a/src/impls/tuple.rs b/src/impls/tuple.rs index c143a96..cdadc24 100644 --- a/src/impls/tuple.rs +++ b/src/impls/tuple.rs @@ -28,6 +28,7 @@ macro_rules! tuple_flatcontainer { $(<$name as Region>::Index: crate::Index),* { type ReadItem<'a> = ($($name::ReadItem<'a>,)*) where Self: 'a; + type ReadItemMut<'a> = ($($name::ReadItemMut<'a>,)*) where Self: 'a; type Index = ($($name::Index,)*); @@ -46,6 +47,13 @@ macro_rules! tuple_flatcontainer { ) } + #[inline] fn index_mut(&mut self, index: Self::Index) -> Self::ReadItemMut<'_> { + let ($($name,)*) = index; + ( + $(self.[].index_mut($name),)* + ) + } + #[inline(always)] fn reserve_regions<'a, It>(&mut self, regions: It) where diff --git a/src/lib.rs b/src/lib.rs index 387cb0b..bfc84d7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -71,6 +71,11 @@ pub trait Region: Default { where Self: 'a; + /// The type of the data that one gets out of the container. + type ReadItemMut<'a>: CopyOnto + where + Self: 'a; + /// The type to index into the container. Should be treated /// as an opaque type, even if known. type Index: Index; @@ -84,6 +89,10 @@ pub trait Region: Default { /// pushing data into the container. fn index(&self, index: Self::Index) -> Self::ReadItem<'_>; + /// Index into the container. The index must be obtained by + /// pushing data into the container. + fn index_mut(&mut self, index: Self::Index) -> Self::ReadItemMut<'_>; + /// Ensure that the region can absorb the items of `regions` without reallocation fn reserve_regions<'a, I>(&mut self, regions: I) where @@ -381,6 +390,7 @@ mod tests { impl Region for PersonRegion { type ReadItem<'a> = PersonRef<'a> where Self: 'a; + type ReadItemMut<'a> = PersonRef<'a>where Self: 'a; type Index = ( <::Region as Region>::Index, <::Region as Region>::Index, @@ -412,6 +422,10 @@ mod tests { } } + fn index_mut(&mut self, index: Self::Index) -> Self::ReadItemMut<'_> { + self.index(index) + } + fn reserve_regions<'a, I>(&mut self, regions: I) where Self: 'a,