#[cfg(test)]
#[macro_use]
extern crate proptest;
use std::cmp::{self, Ordering};
use std::collections::BinaryHeap;
use std::mem;
#[cfg(test)]
mod tests;
pub trait SkippingSearch {
type Item : Ord;
#[inline]
fn suggest_next(&self) -> Option<Self::Item>;
#[inline]
fn find_and_advance(&mut self, item : &Self::Item) -> bool;
#[inline]
fn size_hint(&self) -> (usize, Option<usize>);
}
pub struct SkippingIterator<S>(S) where S : SkippingSearch;
impl<S> SkippingIterator<S> where S : SkippingSearch {
pub fn new(s : S) -> Self {
SkippingIterator(s)
}
}
impl<S> Iterator for SkippingIterator<S> where S : SkippingSearch {
type Item = S::Item;
fn next(&mut self) -> Option<Self::Item> {
while let Some(item) = self.0.suggest_next() {
if self.0.find_and_advance(&item) {
return Some(item);
}
}
None
}
}
fn none_largest_cmp<T>(item1 : &Option<T>, item2 : &Option<T>) -> Ordering where T : Ord {
match (item1, item2) {
(None, None) => Ordering::Equal,
(None, _) => Ordering::Greater,
(_, None) => Ordering::Less,
(Some(v1), Some(v2)) => v1.cmp(v2),
}
}
#[derive(Debug, PartialEq, Eq)]
struct NoneLargest<V>(Option<V>) where V : Ord;
impl<V> PartialOrd for NoneLargest<V> where V : Ord {
fn partial_cmp(&self, other : &Self) -> Option<Ordering> {
Some(none_largest_cmp(&self.0, &other.0))
}
}
impl<V> Ord for NoneLargest<V> where V : Ord {
fn cmp(&self, other : &Self) -> Ordering {
none_largest_cmp(&self.0, &other.0)
}
}
#[inline]
fn exponential_search<'a, T>(slice : &'a[T], item : &T) -> Result<&'a[T], &'a[T]> where T : Ord {
let mut search_index = 1;
let bin_search_result = loop {
match slice.get(search_index - 1).map(|element|{item.cmp(element)}) {
Some(Ordering::Equal) => return Ok(&slice[search_index..]),
Some(Ordering::Greater) => {
search_index *= 2;
},
Some(Ordering::Less) => break slice[search_index/2..search_index-1].binary_search(item),
None => break slice[search_index/2..].binary_search(item),
}
};
bin_search_result.map(|idx|{
&slice[search_index/2+idx+1..]
}).map_err(|idx|{
&slice[search_index/2+idx..]
})
}
impl<'a, T> SkippingSearch for &'a [T] where T : Ord + 'a {
type Item = &'a T;
fn suggest_next(&self) -> Option<&'a T> {
self.first()
}
fn find_and_advance(&mut self, item : &&'a T) -> bool {
let result = exponential_search(self, item);
let found = result.is_ok();
*self = result.unwrap_or_else(|s|{s});
found
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.len();
(len, Some(len))
}
}
pub struct PairIntersection<Left, Right> where Left : SkippingSearch, Right : SkippingSearch<Item=Left::Item> {
left : Left,
right : Right,
}
impl<Left, Right> PairIntersection<Left, Right> where Left : SkippingSearch, Right : SkippingSearch<Item=Left::Item> {
pub fn new(left : Left, right : Right) -> Self {
Self {
left,
right,
}
}
}
impl<Left, Right> SkippingSearch for PairIntersection<Left, Right> where Left : SkippingSearch, Right : SkippingSearch<Item=Left::Item> {
type Item = Left::Item;
fn suggest_next(&self) -> Option<Self::Item> {
cmp::max(
NoneLargest(self.left.suggest_next()),
NoneLargest(self.right.suggest_next()),
).0
}
fn find_and_advance(&mut self, item : &Self::Item) -> bool {
self.left.find_and_advance(item) &&
self.right.find_and_advance(item)
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, left_max) = self.left.size_hint();
let (_, right_max) = self.right.size_hint();
(
0,
cmp::min(
NoneLargest(left_max),
NoneLargest(right_max),
).0,
)
}
}
pub struct MultiIntersection<S> where S : SkippingSearch {
sub_searches : Vec<S>,
}
impl<S> MultiIntersection<S> where S : SkippingSearch {
pub fn new(mut sub_searches : Vec<S>) -> Self {
assert!(sub_searches.len() > 0);
sub_searches.sort_by_key(|s|{
NoneLargest(s.size_hint().1)
});
Self {
sub_searches,
}
}
}
impl<S> SkippingSearch for MultiIntersection<S> where S : SkippingSearch {
type Item = S::Item;
fn suggest_next(&self) -> Option<Self::Item> {
self.sub_searches.iter().map(|s|{
NoneLargest(s.suggest_next())
}).max().and_then(|o|{o.0})
}
fn find_and_advance(&mut self, item : &Self::Item) -> bool {
self.sub_searches.iter_mut().all(|s|{
s.find_and_advance(item)
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
let max = self.sub_searches.iter().map(|s|{
NoneLargest(s.size_hint().1)
}).max().expect("We ensured there was at least one sub search").0;
(0, max)
}
}
pub struct CountingIntersection<S> where S : SkippingSearch {
sub_searches : Vec<S>,
allowed_failures : usize,
}
impl<S> CountingIntersection<S> where S : SkippingSearch {
pub fn new(mut sub_searches : Vec<S>, target_count : usize) -> Self {
assert!(target_count > 0);
assert!(sub_searches.len() >= target_count);
sub_searches.sort_by_key(|s|{
NoneLargest(s.size_hint().1)
});
let allowed_failures = sub_searches.len() - target_count;
Self {
sub_searches,
allowed_failures,
}
}
}
impl<S> SkippingSearch for CountingIntersection<S> where S : SkippingSearch {
type Item = S::Item;
fn suggest_next(&self) -> Option<Self::Item> {
let capacity = self.allowed_failures + 1;
let mut n_largest = BinaryHeap::with_capacity(capacity);
self.sub_searches.iter().map(|s|{cmp::Reverse(NoneLargest(s.suggest_next()))}).for_each(|candidate|{
if n_largest.len() < capacity {
n_largest.push(candidate);
} else {
let mut smallest_of_largest = n_largest.peek_mut().expect("len() >= capacity > 0");
if candidate.0 > smallest_of_largest.0 {
mem::replace(&mut *smallest_of_largest, candidate);
}
}
});
n_largest.into_iter().map(|r|{r.0}).min().expect("len() == capacity > 0").0
}
fn find_and_advance(&mut self, item : &Self::Item) -> bool {
let mut failures_left = self.allowed_failures;
self.sub_searches.iter_mut().all(|s|{
s.find_and_advance(item) || if failures_left > 0 {
failures_left -= 1;
true
} else {
false
}
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
let capacity = self.allowed_failures + 1;
let mut n_smallest_maxes = BinaryHeap::with_capacity(capacity);
self.sub_searches.iter().map(|s|{
let (_, max) = s.size_hint();
NoneLargest(max)
}).for_each(|max| {
if n_smallest_maxes.len() < capacity {
n_smallest_maxes.push(max);
} else {
let mut largest_of_smallest = n_smallest_maxes.peek_mut().expect("len() >= capacity > 0");
if max < *largest_of_smallest {
mem::replace(&mut *largest_of_smallest, max);
}
}
});
(
0,
n_smallest_maxes.into_iter().max().expect("len() == capacity > 0").0,
)
}
}