Skip to content

Commit

Permalink
flatstack generic over storage
Browse files Browse the repository at this point in the history
Signed-off-by: Moritz Hoffmann <[email protected]>
  • Loading branch information
antiguru committed Jun 10, 2024
1 parent d40491b commit 2ca1990
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 42 deletions.
5 changes: 4 additions & 1 deletion src/impls/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,10 @@ impl<T> Storage<T> for Doubling<T> {
#[inline]
fn heap_size<F: FnMut(usize, usize)>(&self, mut callback: F) {
let size_of_usize = std::mem::size_of::<usize>();
callback(self.offsets.len() * size_of_usize, self.offsets.capacity() * size_of_usize);
callback(
self.offsets.len() * size_of_usize,
self.offsets.capacity() * size_of_usize,
);
let size_of_t = std::mem::size_of::<T>();
for inner in &self.inner {
callback(inner.len() * size_of_t, inner.capacity() * size_of_t);
Expand Down
116 changes: 75 additions & 41 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub use impls::option::OptionRegion;
pub use impls::result::ResultRegion;
pub use impls::slice::SliceRegion;
pub use impls::slice_copy::OwnedRegion;
pub use impls::storage::Storage;
pub use impls::string::StringRegion;

/// An index into a region. Automatically implemented for relevant types.
Expand Down Expand Up @@ -145,51 +146,47 @@ impl<'a, T: ToOwned + ?Sized> IntoOwned<'a> for &'a T {
#[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>"
)
serde(bound = "
R: Serialize + for<'a> Deserialize<'a>,
R::Index: Serialize + for<'a> Deserialize<'a>,
S: Serialize + for<'a> Deserialize<'a>,
")
)]
pub struct FlatStack<R: Region> {
pub struct FlatStack<R: Region, S: Storage<R::Index> = Vec<<R as Region>::Index>> {
/// The indices, which we use to lookup items in the region.
indices: Vec<R::Index>,
indices: S,
/// A region to index into.
region: R,
}

impl<R: Region> Default for FlatStack<R> {
impl<R: Region, S: Storage<<R as Region>::Index>> Default for FlatStack<R, S> {
#[inline]
fn default() -> Self {
Self {
indices: Vec::default(),
indices: S::default(),
region: R::default(),
}
}
}

impl<R: Region> Debug for FlatStack<R>
impl<R: Region, S: Storage<<R as Region>::Index>> Debug for FlatStack<R, S>
where
for<'a> R::ReadItem<'a>: Debug,
for<'a> &'a S: IntoIterator<Item = &'a R::Index>,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_list().entries(self.iter()).finish()
}
}

impl<R: Region> FlatStack<R> {
/// Default implementation based on the preference of type `T`.
#[inline]
#[must_use]
pub fn default_impl<T: Containerized<Region = R>>() -> Self {
Self::default()
}

impl<R: Region, S: Storage<<R as Region>::Index>> FlatStack<R, S> {
/// Returns a flat stack that can absorb `capacity` indices without reallocation.
///
/// Prefer [`Self::merge_capacity`] over this function to also pre-size the regions.
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
Self {
indices: Vec::with_capacity(capacity),
indices: S::with_capacity(capacity),
region: R::default(),
}
}
Expand All @@ -198,10 +195,10 @@ impl<R: Region> FlatStack<R> {
#[must_use]
pub fn merge_capacity<'a, I: Iterator<Item = &'a Self> + Clone + 'a>(stacks: I) -> Self
where
R: 'a,
Self: 'a,
{
Self {
indices: Vec::with_capacity(stacks.clone().map(|s| s.indices.len()).sum()),
indices: S::merge_regions(stacks.clone().map(|s| &s.indices)),
region: R::merge_regions(stacks.map(|r| &r.region)),
}
}
Expand All @@ -213,14 +210,14 @@ impl<R: Region> FlatStack<R> {
R: Push<T>,
{
let index = self.region.push(item);
self.indices.push(index);
self.indices.extend_from_slice(&[index]);
}

/// Returns the element at the `offset` position.
#[inline]
#[must_use]
pub fn get(&self, offset: usize) -> R::ReadItem<'_> {
self.region.index(self.indices[offset])
self.region.index(self.indices.index(offset, offset + 1)[0])
}

/// Returns the number of indices in the stack.
Expand All @@ -237,12 +234,6 @@ impl<R: Region> FlatStack<R> {
self.indices.is_empty()
}

/// Returns the total number of indices the stack can hold without reallocation.
#[must_use]
pub fn capacity(&self) -> usize {
self.indices.capacity()
}

/// Reserves space to hold `additional` indices.
#[inline]
pub fn reserve(&mut self, additional: usize) {
Expand Down Expand Up @@ -274,18 +265,41 @@ impl<R: Region> FlatStack<R> {
self.region.reserve_regions(regions);
}

/// Heap size, size - capacity
#[inline]
pub fn heap_size<F: FnMut(usize, usize)>(&self, mut callback: F) {
self.region.heap_size(&mut callback);
self.indices.heap_size(callback);
}
}

impl<R, S> FlatStack<R, S>
where
R: Region,
S: Storage<<R as Region>::Index>,
{
/// Iterate the items in this stack.
#[inline]
pub fn iter(&self) -> Iter<'_, R> {
pub fn iter<'a>(&'a self) -> Iter<'a, R, <&'a S as IntoIterator>::IntoIter>
where
&'a S: IntoIterator<Item = &'a R::Index>,
{
self.into_iter()
}
}

/// Heap size, size - capacity
impl<R: Region> FlatStack<R> {
/// Default implementation based on the preference of type `T`.
#[inline]
pub fn heap_size<F: FnMut(usize, usize)>(&self, mut callback: F) {
use crate::impls::offsets::OffsetContainer;
self.region.heap_size(&mut callback);
self.indices.heap_size(callback);
#[must_use]
pub fn default_impl<T: Containerized<Region = R>>() -> Self {
Self::default()
}

/// Returns the total number of indices the stack can hold without reallocation.
#[must_use]
pub fn capacity(&self) -> usize {
self.indices.capacity()
}
}

Expand All @@ -299,28 +313,39 @@ impl<T, R: Region + Push<T>> Extend<T> for FlatStack<R> {
}
}

impl<'a, R: Region> IntoIterator for &'a FlatStack<R> {
impl<'a, R: Region, S: Storage<<R as Region>::Index>> IntoIterator for &'a FlatStack<R, S>
where
&'a S: IntoIterator<Item = &'a <R as Region>::Index>,
{
type Item = R::ReadItem<'a>;
type IntoIter = Iter<'a, R>;
type IntoIter = Iter<'a, R, <&'a S as IntoIterator>::IntoIter>;

fn into_iter(self) -> Self::IntoIter {
Iter {
inner: self.indices.iter(),
inner: self.indices.into_iter(),
region: &self.region,
}
}
}

/// An iterator over [`FlatStack`]. The iterator yields [`Region::ReadItem`] elements, which
/// it obtains by looking up indices.
pub struct Iter<'a, R: Region> {
pub struct Iter<'a, R, S>
where
R: Region,
S: Iterator<Item = &'a <R as Region>::Index>,
{
/// Iterator over indices.
inner: std::slice::Iter<'a, R::Index>,
inner: S,
/// Region to map indices to read items.
region: &'a R,
}

impl<'a, R: Region> Iterator for Iter<'a, R> {
impl<'a, R, S> Iterator for Iter<'a, R, S>
where
R: Region,
S: Iterator<Item = &'a <R as Region>::Index>,
{
type Item = R::ReadItem<'a>;

fn next(&mut self) -> Option<Self::Item> {
Expand All @@ -332,9 +357,18 @@ impl<'a, R: Region> Iterator for Iter<'a, R> {
}
}

impl<R: Region> ExactSizeIterator for Iter<'_, R> {}
impl<'a, R, S> ExactSizeIterator for Iter<'a, R, S>
where
R: Region,
S: ExactSizeIterator<Item = &'a <R as Region>::Index>,
{
}

impl<R: Region> Clone for Iter<'_, R> {
impl<'a, R, S> Clone for Iter<'a, R, S>
where
R: Region,
S: Iterator<Item = &'a <R as Region>::Index> + Clone,
{
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
Expand Down

0 comments on commit 2ca1990

Please sign in to comment.