Skip to content

Commit

Permalink
Remove Deref bounds from containers
Browse files Browse the repository at this point in the history
  • Loading branch information
frankmcsherry committed Nov 11, 2023
1 parent 0673ecd commit 44f756b
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 69 deletions.
114 changes: 67 additions & 47 deletions src/trace/layers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,65 @@ pub trait BatchContainer: Default {
/// Inserts a borrowed item.
fn copy(&mut self, item: &Self::Item);
/// Extends from a slice of items.
fn copy_slice(&mut self, slice: &[Self::Item]);
fn copy_range(&mut self, other: &Self, start: usize, end: usize);
/// Creates a new container with sufficient capacity.
fn with_capacity(size: usize) -> Self;
/// Reserves additional capacity.
fn reserve(&mut self, additional: usize);
/// Creates a new container with sufficient capacity.
fn merge_capacity(cont1: &Self, cont2: &Self) -> Self;

/// Roughly the `std::ops::Index` trait.
fn index(&self, index: usize) -> &Self::Item;
/// Number of elements contained.
fn len(&self) -> usize;


/// Reports the number of elements satisfing the predicate.
///
/// This methods *relies strongly* on the assumption that the predicate
/// stays false once it becomes false, a joint property of the predicate
/// and the slice. This allows `advance` to use exponential search to
/// count the number of elements in time logarithmic in the result.
fn advance<F: Fn(&Self::Item)->bool>(&self, start: usize, end: usize, function: F) -> usize {

let length = end - start;
let small_limit = 8;

// Exponential seach if the answer isn't within `small_limit`.
if length > small_limit && function(self.index(small_limit)) {

// start with no advance
let mut index = start + small_limit + 1;
if index < length && function(self.index(index)) {

// advance in exponentially growing steps.
let mut step = 1;
while index + step < length && function(self.index(index + step)) {
index += step;
step = step << 1;
}

// advance in exponentially shrinking steps.
step = step >> 1;
while step > 0 {
if index + step < length && function(self.index(index + step)) {
index += step;
}
step = step >> 1;
}

index += 1;
}

index
}
else {
let limit = std::cmp::min(length, small_limit);
(0..limit).filter(|x| function(self.index(*x))).count()
}
}

}

impl<T: Clone> BatchContainer for Vec<T> {
Expand All @@ -135,8 +187,8 @@ impl<T: Clone> BatchContainer for Vec<T> {
fn copy(&mut self, item: &T) {
self.push(item.clone());
}
fn copy_slice(&mut self, slice: &[T]) {
self.extend_from_slice(slice);
fn copy_range(&mut self, other: &Self, start: usize, end: usize) {
self.extend_from_slice(&other[start .. end]);
}
fn with_capacity(size: usize) -> Self {
Vec::with_capacity(size)
Expand All @@ -147,6 +199,12 @@ impl<T: Clone> BatchContainer for Vec<T> {
fn merge_capacity(cont1: &Self, cont2: &Self) -> Self {
Vec::with_capacity(cont1.len() + cont2.len())
}
fn index(&self, index: usize) -> &Self::Item {
&self[index]
}
fn len(&self) -> usize {
self.len()
}
}

impl<T: Columnation> BatchContainer for TimelyStack<T> {
Expand All @@ -157,7 +215,8 @@ impl<T: Columnation> BatchContainer for TimelyStack<T> {
fn copy(&mut self, item: &T) {
self.copy(item);
}
fn copy_slice(&mut self, slice: &[T]) {
fn copy_range(&mut self, other: &Self, start: usize, end: usize) {
let slice = &other[start .. end];
self.reserve_items(slice.iter());
for item in slice.iter() {
self.copy(item);
Expand All @@ -173,49 +232,10 @@ impl<T: Columnation> BatchContainer for TimelyStack<T> {
new.reserve_regions(std::iter::once(cont1).chain(std::iter::once(cont2)));
new
}
}


/// Reports the number of elements satisfing the predicate.
///
/// This methods *relies strongly* on the assumption that the predicate
/// stays false once it becomes false, a joint property of the predicate
/// and the slice. This allows `advance` to use exponential search to
/// count the number of elements in time logarithmic in the result.
pub fn advance<T, F: Fn(&T)->bool>(slice: &[T], function: F) -> usize {

let small_limit = 8;

// Exponential seach if the answer isn't within `small_limit`.
if slice.len() > small_limit && function(&slice[small_limit]) {

// start with no advance
let mut index = small_limit + 1;
if index < slice.len() && function(&slice[index]) {

// advance in exponentially growing steps.
let mut step = 1;
while index + step < slice.len() && function(&slice[index + step]) {
index += step;
step = step << 1;
}

// advance in exponentially shrinking steps.
step = step >> 1;
while step > 0 {
if index + step < slice.len() && function(&slice[index + step]) {
index += step;
}
step = step >> 1;
}

index += 1;
}

index
fn index(&self, index: usize) -> &Self::Item {
&self[index]
}
else {
let limit = std::cmp::min(slice.len(), small_limit);
slice[..limit].iter().filter(|x| function(*x)).count()
fn len(&self) -> usize {
self[..].len()
}
}
36 changes: 18 additions & 18 deletions src/trace/layers/ordered.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
//! Implementation using ordered keys and exponential search.

use super::{Trie, Cursor, Builder, MergeBuilder, TupleBuilder, BatchContainer, advance};
use super::{Trie, Cursor, Builder, MergeBuilder, TupleBuilder, BatchContainer};
use std::convert::{TryFrom, TryInto};
use std::fmt::Debug;
use std::ops::{Sub,Add,Deref};
use std::ops::{Sub,Add};

/// Trait for types used as offsets into an ordered layer.
/// This is usually `usize`, but `u32` can also be used in applications
Expand All @@ -23,7 +23,7 @@ where
pub struct OrderedLayer<K, L, O=usize, C=Vec<K>>
where
K: Ord,
C: BatchContainer<Item=K>+Deref<Target=[K]>,
C: BatchContainer<Item=K>,
O: OrdOffset, <O as TryFrom<usize>>::Error: Debug, <O as TryInto<usize>>::Error: Debug
{
/// The keys of the layer.
Expand All @@ -40,7 +40,7 @@ where
impl<K, L, O, C> Trie for OrderedLayer<K, L, O, C>
where
K: Ord+Clone,
C: BatchContainer<Item=K>+Deref<Target=[K]>,
C: BatchContainer<Item=K>,
L: Trie,
O: OrdOffset, <O as TryFrom<usize>>::Error: Debug, <O as TryInto<usize>>::Error: Debug
{
Expand Down Expand Up @@ -77,7 +77,7 @@ where
pub struct OrderedBuilder<K, L, O=usize, C=Vec<K>>
where
K: Ord+Clone,
C: BatchContainer<Item=K>+Deref<Target=[K]>,
C: BatchContainer<Item=K>,
O: OrdOffset, <O as TryFrom<usize>>::Error: Debug, <O as TryInto<usize>>::Error: Debug
{
/// Keys
Expand All @@ -91,7 +91,7 @@ where
impl<K, L, O, C> Builder for OrderedBuilder<K, L, O, C>
where
K: Ord+Clone,
C: BatchContainer<Item=K>+Deref<Target=[K]>,
C: BatchContainer<Item=K>,
L: Builder,
O: OrdOffset, <O as TryFrom<usize>>::Error: Debug, <O as TryInto<usize>>::Error: Debug
{
Expand All @@ -115,7 +115,7 @@ where
impl<K, L, O, C> MergeBuilder for OrderedBuilder<K, L, O, C>
where
K: Ord+Clone,
C: BatchContainer<Item=K>+Deref<Target=[K]>,
C: BatchContainer<Item=K>,
L: MergeBuilder,
O: OrdOffset, <O as TryFrom<usize>>::Error: Debug, <O as TryInto<usize>>::Error: Debug
{
Expand All @@ -134,7 +134,7 @@ where
let other_basis = other.offs[lower];
let self_basis = self.offs.last().map(|&x| x).unwrap_or(O::try_from(0).unwrap());

self.keys.copy_slice(&other.keys[lower .. upper]);
self.keys.copy_range(&other.keys, lower, upper);
for index in lower .. upper {
self.offs.push((other.offs[index + 1] + self_basis) - other_basis);
}
Expand Down Expand Up @@ -162,7 +162,7 @@ where
impl<K, L, O, C> OrderedBuilder<K, L, O, C>
where
K: Ord+Clone,
C: BatchContainer<Item=K>+Deref<Target=[K]>,
C: BatchContainer<Item=K>,
L: MergeBuilder,
O: OrdOffset, <O as TryFrom<usize>>::Error: Debug, <O as TryInto<usize>>::Error: Debug
{
Expand All @@ -173,10 +173,10 @@ where
let (trie1, lower1, upper1) = other1;
let (trie2, lower2, upper2) = other2;

match trie1.keys[*lower1].cmp(&trie2.keys[*lower2]) {
match trie1.keys.index(*lower1).cmp(&trie2.keys.index(*lower2)) {
::std::cmp::Ordering::Less => {
// determine how far we can advance lower1 until we reach/pass lower2
let step = 1 + advance(&trie1.keys[(1 + *lower1)..upper1], |x| x < &trie2.keys[*lower2]);
let step = 1 + trie1.keys.advance(1 + *lower1, upper1, |x| x < &trie2.keys.index(*lower2));
let step = std::cmp::min(step, 1_000);
self.copy_range(trie1, *lower1, *lower1 + step);
*lower1 += step;
Expand All @@ -189,7 +189,7 @@ where
(&trie2.vals, trie2.offs[*lower2].try_into().unwrap(), trie2.offs[*lower2 + 1].try_into().unwrap())
);
if upper > lower {
self.keys.copy(&trie1.keys[*lower1]);
self.keys.copy(&trie1.keys.index(*lower1));
self.offs.push(O::try_from(upper).unwrap());
}

Expand All @@ -198,7 +198,7 @@ where
},
::std::cmp::Ordering::Greater => {
// determine how far we can advance lower2 until we reach/pass lower1
let step = 1 + advance(&trie2.keys[(1 + *lower2)..upper2], |x| x < &trie1.keys[*lower1]);
let step = 1 + trie2.keys.advance(1 + *lower2, upper2, |x| x < &trie1.keys.index(*lower1));
let step = std::cmp::min(step, 1_000);
self.copy_range(trie2, *lower2, *lower2 + step);
*lower2 += step;
Expand All @@ -210,7 +210,7 @@ where
impl<K, L, O, C> TupleBuilder for OrderedBuilder<K, L, O, C>
where
K: Ord+Clone,
C: BatchContainer<Item=K>+Deref<Target=[K]>,
C: BatchContainer<Item=K>,
L: TupleBuilder,
O: OrdOffset, <O as TryFrom<usize>>::Error: Debug, <O as TryInto<usize>>::Error: Debug
{
Expand All @@ -229,7 +229,7 @@ where
fn push_tuple(&mut self, (key, val): (K, L::Item)) {

// if first element, prior element finish, or different element, need to push and maybe punctuate.
if self.keys.len() == 0 || self.offs[self.keys.len()].try_into().unwrap() != 0 || self.keys[self.keys.len()-1] != key {
if self.keys.len() == 0 || self.offs[self.keys.len()].try_into().unwrap() != 0 || self.keys.index(self.keys.len()-1) != &key {
if self.keys.len() > 0 && self.offs[self.keys.len()].try_into().unwrap() == 0 {
self.offs[self.keys.len()] = O::try_from(self.vals.boundary()).unwrap();
}
Expand All @@ -252,12 +252,12 @@ pub struct OrderedCursor<L: Trie> {
impl<K, L, O, C> Cursor<OrderedLayer<K, L, O, C>> for OrderedCursor<L>
where
K: Ord+Clone,
C: BatchContainer<Item=K>+Deref<Target=[K]>,
C: BatchContainer<Item=K>,
L: Trie,
O: OrdOffset, <O as TryFrom<usize>>::Error: Debug, <O as TryInto<usize>>::Error: Debug
{
type Key = K;
fn key<'a>(&self, storage: &'a OrderedLayer<K, L, O, C>) -> &'a Self::Key { &storage.keys[self.pos] }
fn key<'a>(&self, storage: &'a OrderedLayer<K, L, O, C>) -> &'a Self::Key { &storage.keys.index(self.pos) }
fn step(&mut self, storage: &OrderedLayer<K, L, O, C>) {
self.pos += 1;
if self.valid(storage) {
Expand All @@ -268,7 +268,7 @@ where
}
}
fn seek(&mut self, storage: &OrderedLayer<K, L, O, C>, key: &Self::Key) {
self.pos += advance(&storage.keys[self.pos .. self.bounds.1], |k| k.lt(key));
self.pos += storage.keys.advance(self.pos, self.bounds.1, |k| k.lt(key));
if self.valid(storage) {
self.child.reposition(&storage.vals, storage.offs[self.pos].try_into().unwrap(), storage.offs[self.pos + 1].try_into().unwrap());
}
Expand Down
8 changes: 4 additions & 4 deletions src/trace/layers/ordered_leaf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use ::difference::Semigroup;

use super::{Trie, Cursor, Builder, MergeBuilder, TupleBuilder, BatchContainer, advance};
use super::{Trie, Cursor, Builder, MergeBuilder, TupleBuilder, BatchContainer};
use std::ops::Deref;

/// A layer of unordered values.
Expand Down Expand Up @@ -62,7 +62,7 @@ where
}
#[inline]
fn copy_range(&mut self, other: &Self::Trie, lower: usize, upper: usize) {
self.vals.copy_slice(&other.vals[lower .. upper]);
self.vals.copy_range(&other.vals, lower, upper);
}
fn push_merge(&mut self, other1: (&Self::Trie, usize, usize), other2: (&Self::Trie, usize, usize)) -> usize {

Expand All @@ -77,7 +77,7 @@ where
match trie1.vals[lower1].0.cmp(&trie2.vals[lower2].0) {
::std::cmp::Ordering::Less => {
// determine how far we can advance lower1 until we reach/pass lower2
let step = 1 + advance(&trie1.vals[(1+lower1)..upper1], |x| x.0 < trie2.vals[lower2].0);
let step = 1 + trie1.vals.advance(1+lower1, upper1, |x| x.0 < trie2.vals[lower2].0);
let step = std::cmp::min(step, 1000);
<OrderedLeafBuilder<K, R, C> as MergeBuilder>::copy_range(self, trie1, lower1, lower1 + step);
lower1 += step;
Expand All @@ -95,7 +95,7 @@ where
}
::std::cmp::Ordering::Greater => {
// determine how far we can advance lower2 until we reach/pass lower1
let step = 1 + advance(&trie2.vals[(1+lower2)..upper2], |x| x.0 < trie1.vals[lower1].0);
let step = 1 + trie2.vals.advance(1+lower2, upper2, |x| x.0 < trie1.vals[lower1].0);
let step = std::cmp::min(step, 1000);
<OrderedLeafBuilder<K, R, C> as MergeBuilder>::copy_range(self, trie2, lower2, lower2 + step);
lower2 += step;
Expand Down

0 comments on commit 44f756b

Please sign in to comment.