Skip to content

Introduce container for default values #452

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

Merged
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
22 changes: 15 additions & 7 deletions src/trace/implementations/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ pub use self::merge_batcher::MergeBatcher as Batcher;
pub mod ord_neu;
pub mod rhh;
pub mod huffman_container;
pub mod option_container;

// Opinionated takes on default spines.
pub use self::ord_neu::OrdValSpine as ValSpine;
Expand Down Expand Up @@ -320,7 +321,7 @@ pub mod containers {

use timely::container::columnation::{Columnation, TimelyStack};

use std::borrow::{Borrow, ToOwned};
use std::borrow::ToOwned;
use crate::trace::MyTrait;

/// A general-purpose container resembling `Vec<T>`.
Expand All @@ -332,13 +333,21 @@ pub mod containers {
/// The type that can be read back out of the container.
type ReadItem<'a>: Copy + MyTrait<'a, Owned = Self::PushItem> + for<'b> PartialOrd<Self::ReadItem<'b>>;
/// Inserts an owned item.
fn push(&mut self, item: Self::PushItem);
fn push(&mut self, item: Self::PushItem) {
self.copy_push(&item);
}
/// Inserts an owned item.
fn copy_push(&mut self, item: &Self::PushItem);
fn copy_push(&mut self, item: &Self::PushItem) {
self.copy(MyTrait::borrow_as(item));
}
/// Inserts a borrowed item.
fn copy(&mut self, item: Self::ReadItem<'_>);
/// Extends from a range of items in another`Self`.
fn copy_range(&mut self, other: &Self, start: usize, end: usize);
fn copy_range(&mut self, other: &Self, start: usize, end: usize) {
for index in start .. end {
self.copy(other.index(index));
}
}
/// Creates a new container with sufficient capacity.
fn with_capacity(size: usize) -> Self;
/// Creates a new container with sufficient capacity.
Expand All @@ -357,6 +366,8 @@ pub mod containers {
None
}
}
/// Indicates if the length is zero.
fn is_empty(&self) -> bool { self.len() == 0 }

/// Reports the number of elements satisfing the predicate.
///
Expand Down Expand Up @@ -441,9 +452,6 @@ pub mod containers {
type PushItem = T;
type ReadItem<'a> = &'a Self::PushItem;

fn push(&mut self, item: Self::PushItem) {
self.copy(item.borrow());
}
fn copy_push(&mut self, item: &Self::PushItem) {
self.copy(item);
}
Expand Down
151 changes: 151 additions & 0 deletions src/trace/implementations/option_container.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
//! A container optimized for identical contents.

use crate::trace::cursor::MyTrait;
use crate::trace::implementations::BatchContainer;

/// A container that effectively represents default values.
///
/// This container is meant to be a minimal non-trivial container,
/// and may be useful in unifying `OrdVal` and `OrdKey` spines.
pub struct OptionContainer<C> {
/// Number of default items pushed.
defaults: usize,
/// Spill-over for non-empty rows.
container: C,
}

impl<C> BatchContainer for OptionContainer<C>
where
C: BatchContainer,
C::PushItem: Default + Ord,
{
type PushItem = C::PushItem;
type ReadItem<'a> = OptionWrapper<'a, C>;

fn push(&mut self, item: Self::PushItem) {
if item == Default::default() && self.container.is_empty() {
self.defaults += 1;
}
else {
self.container.push(item)
}
}
fn copy<'a>(&mut self, item: Self::ReadItem<'a>) {
if item.equals(&Default::default()) && self.container.is_empty() {
self.defaults += 1;
}
else {
if let Some(item) = item.inner {
self.container.copy(item);
}
else {
self.container.push(Default::default());
}
}
}
fn with_capacity(size: usize) -> Self {
Self {
defaults: 0,
container: C::with_capacity(size),
}
}
fn merge_capacity(cont1: &Self, cont2: &Self) -> Self {
Self {
defaults: 0,
container: C::merge_capacity(&cont1.container, &cont2.container),
}
}
fn index(&self, index: usize) -> Self::ReadItem<'_> {
if index < self.defaults {
OptionWrapper { inner: None }
}
else {
OptionWrapper { inner: Some(self.container.index(index - self.defaults))}
}
}
fn len(&self) -> usize {
self.container.len() + self.defaults
}
}

/// A read wrapper capable of cheaply representing a default value.
pub struct OptionWrapper<'a, C: BatchContainer> {
inner: Option<C::ReadItem<'a>>,
}

impl<'a, C: BatchContainer> Copy for OptionWrapper<'a, C> { }
impl<'a, C: BatchContainer> Clone for OptionWrapper<'a, C> {
fn clone(&self) -> Self { *self }
}


use std::cmp::Ordering;
impl<'a, 'b, C: BatchContainer> PartialEq<OptionWrapper<'a, C>> for OptionWrapper<'b, C>
where
C::PushItem: Default + Ord,
{
fn eq(&self, other: &OptionWrapper<'a, C>) -> bool {
match (&self.inner, &other.inner) {
(None, None) => true,
(None, Some(item2)) => item2.equals(&Default::default()),
(Some(item1), None) => item1.equals(&Default::default()),
(Some(item1), Some(item2)) => item1.eq(item2)
}
}
}
impl<'a, C: BatchContainer> Eq for OptionWrapper<'a, C> where
C::PushItem: Default + Ord
{ }
impl<'a, 'b, C: BatchContainer> PartialOrd<OptionWrapper<'a, C>> for OptionWrapper<'b, C> where
C::PushItem: Default + Ord,
{
fn partial_cmp(&self, other: &OptionWrapper<'a, C>) -> Option<Ordering> {
let default = Default::default();
match (&self.inner, &other.inner) {
(None, None) => Some(Ordering::Equal),
(None, Some(item2)) => item2.partial_cmp(&C::ReadItem::<'_>::borrow_as(&default)).map(|x| x.reverse()),
(Some(item1), None) => item1.partial_cmp(&C::ReadItem::<'_>::borrow_as(&default)),
(Some(item1), Some(item2)) => item1.partial_cmp(item2)
}
}
}
impl<'a, C: BatchContainer> Ord for OptionWrapper<'a, C> where
C::PushItem: Default + Ord,
{
fn cmp(&self, other: &Self) -> Ordering {
self.partial_cmp(other).unwrap()
}
}


impl<'a, C: BatchContainer> MyTrait<'a> for OptionWrapper<'a, C>
where
C::PushItem : Default + Ord,
{
type Owned = C::PushItem;

fn into_owned(self) -> Self::Owned {
self.inner.map(|r| r.into_owned()).unwrap_or_else(Default::default)
}
fn clone_onto(&self, other: &mut Self::Owned) {
if let Some(item) = &self.inner {
item.clone_onto(other)
}
else {
*other = Default::default();
}
}
fn compare(&self, other: &Self::Owned) -> std::cmp::Ordering {
if let Some(item) = &self.inner {
item.compare(other)
}
else {
<C::PushItem>::default().cmp(other)
}
}
fn borrow_as(other: &'a Self::Owned) -> Self {
Self {
inner: Some(<_>::borrow_as(other))
}
}
}