From 61e3894197ab13c886819716d041701b69fd1ef5 Mon Sep 17 00:00:00 2001 From: Frank McSherry Date: Sun, 12 Nov 2023 15:07:32 -0500 Subject: [PATCH] Remove Deref bounds from containers --- src/trace/layers/mod.rs | 113 ++++++++++++++++++------------- src/trace/layers/ordered.rs | 36 +++++----- src/trace/layers/ordered_leaf.rs | 8 +-- 3 files changed, 88 insertions(+), 69 deletions(-) diff --git a/src/trace/layers/mod.rs b/src/trace/layers/mod.rs index e0d26088a..255033c86 100644 --- a/src/trace/layers/mod.rs +++ b/src/trace/layers/mod.rs @@ -118,13 +118,64 @@ 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 advancebool>(&self, start: usize, end: usize, function: F) -> usize { + + let small_limit = start + 8; + + // Exponential seach if the answer isn't within `small_limit`. + if end > small_limit && function(self.index(small_limit)) { + + // start with no advance + let mut index = small_limit + 1; + if index < end && function(self.index(index)) { + + // advance in exponentially growing steps. + let mut step = 1; + while index + step < end && function(self.index(index + step)) { + index += step; + step = step << 1; + } + + // advance in exponentially shrinking steps. + step = step >> 1; + while step > 0 { + if index + step < end && function(self.index(index + step)) { + index += step; + } + step = step >> 1; + } + + index += 1; + } + + index + } + else { + let limit = std::cmp::min(end, small_limit); + (start..limit).filter(|x| function(self.index(*x))).count() + } + } + } impl BatchContainer for Vec { @@ -135,8 +186,8 @@ impl BatchContainer for Vec { 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) @@ -147,6 +198,12 @@ impl BatchContainer for Vec { 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 BatchContainer for TimelyStack { @@ -157,7 +214,8 @@ impl BatchContainer for TimelyStack { 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); @@ -173,49 +231,10 @@ impl BatchContainer for TimelyStack { 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 advancebool>(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() } } diff --git a/src/trace/layers/ordered.rs b/src/trace/layers/ordered.rs index 87f4e5352..dd0cb6442 100644 --- a/src/trace/layers/ordered.rs +++ b/src/trace/layers/ordered.rs @@ -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 @@ -23,7 +23,7 @@ where pub struct OrderedLayer> where K: Ord, - C: BatchContainer+Deref, + C: BatchContainer, O: OrdOffset { /// The keys of the layer. @@ -40,7 +40,7 @@ where impl Trie for OrderedLayer where K: Ord, - C: BatchContainer+Deref, + C: BatchContainer, L: Trie, O: OrdOffset { @@ -77,7 +77,7 @@ where pub struct OrderedBuilder> where K: Ord, - C: BatchContainer+Deref, + C: BatchContainer, O: OrdOffset { /// Keys @@ -91,7 +91,7 @@ where impl Builder for OrderedBuilder where K: Ord, - C: BatchContainer+Deref, + C: BatchContainer, L: Builder, O: OrdOffset { @@ -115,7 +115,7 @@ where impl MergeBuilder for OrderedBuilder where K: Ord, - C: BatchContainer+Deref, + C: BatchContainer, L: MergeBuilder, O: OrdOffset { @@ -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).ok().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); } @@ -162,7 +162,7 @@ where impl OrderedBuilder where K: Ord, - C: BatchContainer+Deref, + C: BatchContainer, L: MergeBuilder, O: OrdOffset { @@ -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; @@ -189,7 +189,7 @@ where (&trie2.vals, trie2.offs[*lower2].try_into().ok().unwrap(), trie2.offs[*lower2 + 1].try_into().ok().unwrap()) ); if upper > lower { - self.keys.copy(&trie1.keys[*lower1]); + self.keys.copy(&trie1.keys.index(*lower1)); self.offs.push(O::try_from(upper).ok().unwrap()); } @@ -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; @@ -210,7 +210,7 @@ where impl TupleBuilder for OrderedBuilder where K: Ord, - C: BatchContainer+Deref, + C: BatchContainer, L: TupleBuilder, O: OrdOffset { @@ -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().ok().unwrap() != 0 || self.keys[self.keys.len()-1] != key { + if self.keys.len() == 0 || self.offs[self.keys.len()].try_into().ok().unwrap() != 0 || self.keys.index(self.keys.len()-1) != &key { if self.keys.len() > 0 && self.offs[self.keys.len()].try_into().ok().unwrap() == 0 { self.offs[self.keys.len()] = O::try_from(self.vals.boundary()).ok().unwrap(); } @@ -252,12 +252,12 @@ pub struct OrderedCursor { impl Cursor> for OrderedCursor where K: Ord, - C: BatchContainer+Deref, + C: BatchContainer, L: Trie, O: OrdOffset { type Key = K; - fn key<'a>(&self, storage: &'a OrderedLayer) -> &'a Self::Key { &storage.keys[self.pos] } + fn key<'a>(&self, storage: &'a OrderedLayer) -> &'a Self::Key { &storage.keys.index(self.pos) } fn step(&mut self, storage: &OrderedLayer) { self.pos += 1; if self.valid(storage) { @@ -268,7 +268,7 @@ where } } fn seek(&mut self, storage: &OrderedLayer, 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().ok().unwrap(), storage.offs[self.pos + 1].try_into().ok().unwrap()); } diff --git a/src/trace/layers/ordered_leaf.rs b/src/trace/layers/ordered_leaf.rs index 9e7727669..39aec7592 100644 --- a/src/trace/layers/ordered_leaf.rs +++ b/src/trace/layers/ordered_leaf.rs @@ -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. @@ -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 { @@ -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); as MergeBuilder>::copy_range(self, trie1, lower1, lower1 + step); lower1 += step; @@ -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); as MergeBuilder>::copy_range(self, trie2, lower2, lower2 + step); lower2 += step;