Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add docs, utility features, option region #4

Merged
merged 5 commits into from
Feb 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 86 additions & 1 deletion benches/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@

extern crate test;

use flatcontainer::{Containerized, CopyOnto, FlatStack, ReserveItems};
use flatcontainer::impls::tuple::TupleABCRegion;
use flatcontainer::{
Containerized, CopyOnto, CopyRegion, FlatStack, MirrorRegion, Region, ReserveItems,
SliceRegion, StringRegion,
};
use test::Bencher;

#[bench]
Expand All @@ -24,6 +28,10 @@ fn u8_u64_copy(bencher: &mut Bencher) {
_bench_copy(bencher, vec![(0u8, 0u64); 512]);
}
#[bench]
fn str10_copy(bencher: &mut Bencher) {
_bench_copy(bencher, vec!["grawwwwrr!"; 1024]);
}
#[bench]
fn string10_copy(bencher: &mut Bencher) {
_bench_copy(bencher, vec![format!("grawwwwrr!"); 1024]);
}
Expand All @@ -46,6 +54,56 @@ fn vec_u_vn_s_copy(bencher: &mut Bencher) {
);
}

#[bench]
fn empty_copy_region(bencher: &mut Bencher) {
_bench_copy_region::<CopyRegion<_>, _>(bencher, vec![(); 1024]);
}
#[bench]
fn u64_copy_region(bencher: &mut Bencher) {
_bench_copy_region::<CopyRegion<_>, _>(bencher, vec![0u64; 1024]);
}
#[bench]
fn u32x2_copy_region(bencher: &mut Bencher) {
_bench_copy_region::<CopyRegion<_>, _>(bencher, vec![(0u32, 0u32); 1024]);
}
#[bench]
fn u8_u64_copy_region(bencher: &mut Bencher) {
_bench_copy_region::<CopyRegion<_>, _>(bencher, vec![(0u8, 0u64); 512]);
}
#[bench]
fn str10_copy_region(bencher: &mut Bencher) {
_bench_copy_region::<CopyRegion<_>, _>(bencher, vec!["grawwwwrr!"; 1024]);
}
#[bench]
fn str100_copy_region(bencher: &mut Bencher) {
_bench_copy_region::<CopyRegion<_>, _>(bencher, vec!["grawwwwrrgrawwwwrrgrawwwwrrgrawwwwrrgrawwwwrrgrawwwwrrgrawwwwrrgrawwwwrrgrawwwwrr!!!!!!!!!grawwwwrr!"; 1024]);
}
#[bench]
fn string10_copy_region(bencher: &mut Bencher) {
_bench_copy_region::<SliceRegion<_>, _>(bencher, vec![format!("grawwwwrr!"); 1024]);
}
#[bench]
fn string20_copy_region(bencher: &mut Bencher) {
_bench_copy_region::<SliceRegion<_>, _>(bencher, vec![format!("grawwwwrr!!!!!!!!!!!"); 512]);
}
#[bench]
fn vec_u_s_copy_region(bencher: &mut Bencher) {
_bench_copy_region::<SliceRegion<_>, _>(
bencher,
vec![vec![(0u64, "grawwwwrr!".to_string()); 32]; 32],
);
}
#[bench]
fn vec_u_vn_s_copy_region(bencher: &mut Bencher) {
_bench_copy_region::<
SliceRegion<SliceRegion<TupleABCRegion<MirrorRegion<_>, CopyRegion<_>, StringRegion>>>,
_,
>(
bencher,
vec![vec![(0u64, vec![(); 1 << 40], "grawwwwrr!".to_string()); 32]; 32],
);
}

#[bench]
fn empty_clone(bencher: &mut Bencher) {
_bench_clone(bencher, vec![(); 1024]);
Expand All @@ -63,6 +121,10 @@ fn u8_u64_clone(bencher: &mut Bencher) {
_bench_clone(bencher, vec![(0u8, 0u64); 512]);
}
#[bench]
fn str10_clone(bencher: &mut Bencher) {
_bench_clone(bencher, vec!["grawwwwrr!"; 1024]);
}
#[bench]
fn string10_clone(bencher: &mut Bencher) {
_bench_clone(bencher, vec![format!("grawwwwrr!"); 1024]);
}
Expand Down Expand Up @@ -102,6 +164,10 @@ fn u8_u64_realloc(bencher: &mut Bencher) {
_bench_realloc(bencher, vec![(0u8, 0u64); 512]);
}
#[bench]
fn str10_realloc(bencher: &mut Bencher) {
_bench_realloc(bencher, vec!["grawwwwrr!"; 1024]);
}
#[bench]
fn string10_realloc(bencher: &mut Bencher) {
_bench_realloc(bencher, vec![format!("grawwwwrr!"); 1024]);
}
Expand Down Expand Up @@ -141,6 +207,10 @@ fn u8_u64_prealloc(bencher: &mut Bencher) {
_bench_prealloc(bencher, vec![(0u8, 0u64); 512]);
}
#[bench]
fn str10_prealloc(bencher: &mut Bencher) {
_bench_prealloc(bencher, vec!["grawwwwrr!"; 1024]);
}
#[bench]
fn string10_prealloc(bencher: &mut Bencher) {
_bench_prealloc(bencher, vec![format!("grawwwwrr!"); 1024]);
}
Expand Down Expand Up @@ -178,6 +248,21 @@ where
});
}

fn _bench_copy_region<R: Region, T>(bencher: &mut Bencher, record: T)
where
for<'a> &'a T: CopyOnto<R>,
{
// prepare encoded data for bencher.bytes
let mut arena = FlatStack::<R>::default();

bencher.iter(|| {
arena.clear();
for _ in 0..1024 {
arena.copy(&record);
}
});
}

fn _bench_clone<T: Containerized + Eq + Clone>(bencher: &mut Bencher, record: T) {
// prepare encoded data for bencher.bytes
let mut arena = Vec::new();
Expand Down
17 changes: 17 additions & 0 deletions src/impls/mirror.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! A region that copies its inputs.

use std::marker::PhantomData;

#[cfg(feature = "serde")]
Expand All @@ -6,6 +8,21 @@ use serde::{Deserialize, Serialize};
use crate::{Containerized, CopyOnto, Index, Region, ReserveItems};

/// A region for types where the read item type is equal to the index type.
///
/// This region is useful where the type is not larger than roughly two `usize`s (or 1.5x with
/// some optimizations), or looking up the value is too costly. For larger copy types, the memory
/// required to store the copy type and an index is only marginally bigger, with the benefit
/// that the index remains compact.
///
/// # Examples
///
/// For [`MirrorRegion`]s, we can index with a copy type:
/// ```
/// # use flatcontainer::{MirrorRegion, Region};
/// let r = MirrorRegion::<u8>::default();
/// let output: u8 = r.index(42);
/// assert_eq!(output, 42);
/// ```
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct MirrorRegion<T>(PhantomData<*const T>);
Expand Down
15 changes: 9 additions & 6 deletions src/impls/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
pub(crate) mod mirror;
pub(crate) mod result;
pub(crate) mod slice;
pub(crate) mod slice_copy;
pub(crate) mod string;
pub(crate) mod tuple;
//! Various region implementations.

pub mod mirror;
pub mod option;
pub mod result;
pub mod slice;
pub mod slice_copy;
pub mod string;
pub mod tuple;
92 changes: 92 additions & 0 deletions src/impls/option.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
//! A region that stores options.

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

use crate::{Containerized, CopyOnto, Region, ReserveItems};

impl<T: Containerized> Containerized for Option<T> {
type Region = OptionRegion<T::Region>;
}

/// A region to hold [`Option`]s.
///
/// # Examples
///
/// The region can hold options:
/// ```
/// # use flatcontainer::{Containerized, CopyOnto, OptionRegion, Region};
/// let mut r = OptionRegion::<<u8 as Containerized>::Region>::default();
///
/// let some_index = Some(123).copy_onto(&mut r);
/// // Type annotations required for `None`:
/// let none_index = Option::<u8>::None.copy_onto(&mut r);
///
/// assert_eq!(Some(123), r.index(some_index));
/// assert_eq!(None, r.index(none_index));
/// ```
#[derive(Default, Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct OptionRegion<R> {
inner: R,
}

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

#[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<Item = &'a Self> + Clone,
{
self.inner
.reserve_regions(regions.clone().map(|r| &r.inner));
}

#[inline]
fn clear(&mut self) {
self.inner.clear();
}
}

impl<T, TR> CopyOnto<OptionRegion<TR>> for Option<T>
where
TR: Region,
T: CopyOnto<TR>,
{
#[inline]
fn copy_onto(self, target: &mut OptionRegion<TR>) -> <OptionRegion<TR> as Region>::Index {
self.map(|t| t.copy_onto(&mut target.inner))
}
}

impl<'a, T: 'a, TR> CopyOnto<OptionRegion<TR>> for &'a Option<T>
where
TR: Region,
&'a T: CopyOnto<TR>,
{
#[inline]
fn copy_onto(self, target: &mut OptionRegion<TR>) -> <OptionRegion<TR> as Region>::Index {
self.as_ref().map(|t| t.copy_onto(&mut target.inner))
}
}

impl<'a, T: 'a, TR> ReserveItems<OptionRegion<TR>> for &'a Option<T>
where
TR: Region,
&'a T: ReserveItems<TR>,
{
fn reserve_items<I>(target: &mut OptionRegion<TR>, items: I)
where
I: Iterator<Item = Self> + Clone,
{
ReserveItems::reserve_items(&mut target.inner, items.clone().flat_map(|r| r.as_ref()));
}
}
18 changes: 18 additions & 0 deletions src/impls/result.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! A region that stores results.

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

Expand All @@ -7,6 +9,22 @@ impl<T: Containerized, E: Containerized> Containerized for Result<T, E> {
type Region = ResultRegion<T::Region, E::Region>;
}

/// A region to hold [`Result`]s.
///
/// # Examples
///
/// Add results to a result region:
/// ```
/// use flatcontainer::{Containerized, CopyOnto, Region, ResultRegion};
/// let mut r =
/// ResultRegion::<<() as Containerized>::Region, <String as Containerized>::Region>::default();
///
/// let ok_index = Result::<(), String>::Ok(()).copy_onto(&mut r);
/// let err_index = Result::<(), String>::Err("Error".to_string()).copy_onto(&mut r);
///
/// assert_eq!(Ok(()), r.index(ok_index));
/// assert_eq!(Err("Error"), r.index(err_index));
/// ```
#[derive(Default, Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ResultRegion<T, E> {
Expand Down
Loading
Loading