Skip to content

Commit

Permalink
Experiment: allow mutable access
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
antiguru committed Feb 13, 2024
1 parent 549c190 commit bcefc47
Show file tree
Hide file tree
Showing 11 changed files with 178 additions and 6 deletions.
9 changes: 6 additions & 3 deletions src/codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,8 @@ where
for<'a> R: Region<ReadItem<'a> = &'a [u8]> + 'a,
for<'a> &'a [u8]: CopyOnto<R>,
{
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;

Expand All @@ -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,
Expand Down
74 changes: 74 additions & 0 deletions src/impls/columns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Item = &'a Self> + Clone) -> Self
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -104,6 +112,72 @@ where
}
}

/// Read the values of a row.
pub struct ReadColumnsMut<'a, R, Idx>
where
R: Region<Index = Idx>,
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<Index = Idx>,
Idx: Index,
{
/// Iterate the individual values of a row.
pub fn iter(&'a mut self) -> impl Iterator<Item = R::ReadItemMut<'a>> {
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<ColumnsRegion<R, Idx>> for ReadColumnsMut<'a, R, Idx>
where
R: Region<Index = Idx>,
Idx: Index,
{
fn copy_onto(
self,
target: &mut ColumnsRegion<R, Idx>,
) -> <ColumnsRegion<R, Idx> 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>
Expand Down
20 changes: 17 additions & 3 deletions src/impls/deduplicate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ where
for<'a, 'b> R::ReadItem<'a>: PartialEq<R::ReadItem<'b>>,
{
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<Item = &'a Self> + Clone) -> Self
Expand All @@ -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,
Expand Down Expand Up @@ -109,9 +118,9 @@ impl<R: Region<Index = (usize, usize)>, O: OffsetContainer<usize>> Default
impl<R: Region<Index = (usize, usize)>, O: OffsetContainer<usize>> Region
for ConsecutiveOffsetPairs<R, O>
{
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;

Expand All @@ -133,6 +142,11 @@ impl<R: Region<Index = (usize, usize)>, O: OffsetContainer<usize>> 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,
Expand Down
5 changes: 5 additions & 0 deletions src/impls/mirror.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ impl<T> Debug for MirrorRegion<T> {

impl<T: Index + CopyOnto<Self>> Region for MirrorRegion<T> {
type ReadItem<'a> = T where T: 'a;
type ReadItemMut<'a> = T where Self: 'a;
type Index = T;

fn merge_regions<'a>(_regions: impl Iterator<Item = &'a Self> + Clone) -> Self
Expand All @@ -56,6 +57,10 @@ impl<T: Index + CopyOnto<Self>> Region for MirrorRegion<T> {
index
}

fn index_mut(&mut self, index: Self::Index) -> Self::ReadItemMut<'_> {
index
}

#[inline(always)]
fn reserve_regions<'a, I>(&mut self, _regions: I)
where
Expand Down
5 changes: 5 additions & 0 deletions src/impls/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pub struct OptionRegion<R> {

impl<R: Region> Region for OptionRegion<R> {
type ReadItem<'a> = Option<R::ReadItem<'a>> where Self: 'a;
type ReadItemMut<'a> = Option<R::ReadItemMut<'a>> where Self: 'a;
type Index = Option<R::Index>;

fn merge_regions<'a>(regions: impl Iterator<Item = &'a Self> + Clone) -> Self
Expand All @@ -49,6 +50,10 @@ impl<R: Region> Region for OptionRegion<R> {
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
Expand Down
8 changes: 8 additions & 0 deletions src/impls/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ where
E: Region,
{
type ReadItem<'a> = Result<T::ReadItem<'a>, E::ReadItem<'a>> where Self: 'a;
type ReadItemMut<'a> = Result<T::ReadItemMut<'a>, E::ReadItemMut<'a>> where Self: 'a;
type Index = Result<T::Index, E::Index>;

fn merge_regions<'a>(regions: impl Iterator<Item = &'a Self> + Clone) -> Self
Expand All @@ -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
Expand Down
5 changes: 5 additions & 0 deletions src/impls/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ pub struct SliceRegion<C: Region, O: OffsetContainer<C::Index> = Vec<<C as Regio

impl<C: Region, O: OffsetContainer<C::Index>> Region for SliceRegion<C, O> {
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<Item = &'a Self> + Clone) -> Self
Expand All @@ -82,6 +83,10 @@ impl<C: Region, O: OffsetContainer<C::Index>> Region for SliceRegion<C, O> {
}
}

fn index_mut(&mut self, index: Self::Index) -> Self::ReadItemMut<'_> {
self.index(index)
}

#[inline]
fn reserve_regions<'a, I>(&mut self, regions: I)
where
Expand Down
24 changes: 24 additions & 0 deletions src/impls/slice_copy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub struct CopyRegion<T: Copy> {

impl<T: Copy> Region for CopyRegion<T> {
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<Item = &'a Self> + Clone) -> Self
Expand All @@ -46,6 +47,10 @@ impl<T: Copy> Region for CopyRegion<T> {
&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,
Expand Down Expand Up @@ -89,6 +94,25 @@ impl<T: Copy> ReserveItems<CopyRegion<T>> for &[T] {
}
}

impl<T> CopyOnto<CopyRegion<T>> for &mut [T]
where
T: Copy,
{
#[inline]
fn copy_onto(self, target: &mut CopyRegion<T>) -> <CopyRegion<T> as Region>::Index {
(&*self).copy_onto(target)
}
}

impl<T: Copy> ReserveItems<CopyRegion<T>> for &mut [T] {
fn reserve_items<I>(target: &mut CopyRegion<T>, items: I)
where
I: Iterator<Item = Self> + Clone,
{
ReserveItems::reserve_items(target, items.map(|r| &*r));
}
}

impl<T> CopyOnto<CopyRegion<T>> for &Vec<T>
where
T: Copy,
Expand Down
12 changes: 12 additions & 0 deletions src/impls/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = <CopyRegion<u8> as Region>::Index;

fn merge_regions<'a>(regions: impl Iterator<Item = &'a Self> + Clone) -> Self
Expand All @@ -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,
Expand Down Expand Up @@ -100,6 +105,13 @@ impl CopyOnto<StringRegion> for &str {
}
}

impl CopyOnto<StringRegion> for &mut str {
#[inline]
fn copy_onto(self, target: &mut StringRegion) -> <StringRegion as Region>::Index {
<&str as CopyOnto<StringRegion>>::copy_onto(self, target)
}
}

impl CopyOnto<StringRegion> for &&str {
#[inline]
fn copy_onto(self, target: &mut StringRegion) -> <StringRegion as Region>::Index {
Expand Down
8 changes: 8 additions & 0 deletions src/impls/tuple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,)*);

Expand All @@ -46,6 +47,13 @@ macro_rules! tuple_flatcontainer {
)
}

#[inline] fn index_mut(&mut self, index: Self::Index) -> Self::ReadItemMut<'_> {
let ($($name,)*) = index;
(
$(self.[<container $name>].index_mut($name),)*
)
}

#[inline(always)]
fn reserve_regions<'a, It>(&mut self, regions: It)
where
Expand Down
14 changes: 14 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Self>
where
Self: 'a;

/// The type to index into the container. Should be treated
/// as an opaque type, even if known.
type Index: Index;
Expand All @@ -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
Expand Down Expand Up @@ -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 = (
<<String as Containerized>::Region as Region>::Index,
<<u16 as Containerized>::Region as Region>::Index,
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit bcefc47

Please sign in to comment.