tag_search_all

master
Avril 4 years ago
parent 5c4c4bc08a
commit 5ad1b69f5a
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -9,21 +9,30 @@ use std::collections::{
use smallvec::SmallVec; use smallvec::SmallVec;
#[derive(Debug)] #[derive(Debug)]
pub struct StoreSearchIter<'a, T: ?Sized>(&'a Store, Option<Range<'a, String, ArenaIndex>>, VecDeque<&'a sha256::Sha256Hash>, PhantomData<T>); pub struct StoreSearchAnyIter<'a, T: ?Sized>(&'a Store, Option<Range<'a, String, ArenaIndex>>, VecDeque<&'a sha256::Sha256Hash>, PhantomData<T>);
#[derive(Debug)]
pub struct StoreSearchAllIter<'a, T: ?Sized>(&'a Store, Option<Range<'a, String, ArenaIndex>>, VecDeque<&'a Entry>, SmallVec<[&'a T; 8]>);
// Accessing // Accessing
impl Store impl Store
{ {
/// Search for all entries with *all* of these provided tags.
///
/// # Notes
/// This is allowed to produce duplicate entries, if either:
/// * An entry has multiple of the same tag set
/// * An entry has multiple of the tags provided to this function set
//TODO: Parallelize this with futures::Stream ver to do the `tag_search` lookups in parallel. //TODO: Parallelize this with futures::Stream ver to do the `tag_search` lookups in parallel.
pub fn tag_search_all<'a, T: ?Sized + Ord + 'a>(&'a self, tags: impl IntoIterator<Item= &'a T>) -> impl Iterator<Item = &'a Entry> + 'a pub fn tag_search_all<'a, T: ?Sized + Ord + 'a>(&'a self, tags: impl IntoIterator<Item= &'a T>) -> StoreSearchAllIter<'_, T>
where String: Borrow<T> where String: Borrow<T>
{ {
let tags: SmallVec<[_; 5]> = tags.into_iter().collect(); let mut sorted: SmallVec<[_; 8]> = tags.into_iter().collect();
sorted.sort();
tags.iter().flat_map(|&tag| self.tag_search(tag)).dedup_ref() StoreSearchAllIter(self, Some(match (sorted.first(), sorted.last()) {
.filter(|x| x.tags.iter().map(|x| x.borrow()).filter(|tx| !tags.contains(tx)).count() == 0) (Some(&low), Some(&high)) => self.tags.range::<T, _>((std::ops::Bound::Included(low), std::ops::Bound::Included(high))),
_ => return StoreSearchAllIter(self, None, Default::default(), sorted),
/* TODO: get rid of this ,replace `impl Iterator` return with its own type. */ .collect::<Vec<_>>().into_iter() }), VecDeque::new(), sorted)
} }
/// Search for all entries with *any* of these provided tags. /// Search for all entries with *any* of these provided tags.
/// ///
@ -31,34 +40,74 @@ impl Store
/// This is allowed to produce duplicate entries, if either: /// This is allowed to produce duplicate entries, if either:
/// * An entry has multiple of the same tag set /// * An entry has multiple of the same tag set
/// * An entry has multiple of the tags provided to this function set /// * An entry has multiple of the tags provided to this function set
pub fn tag_search_any<'a, T: ?Sized + Ord + 'a>(&self, tags: impl IntoIterator<Item= &'a T>) -> StoreSearchIter<'_, T> pub fn tag_search_any<'a, T: ?Sized + Ord + 'a>(&self, tags: impl IntoIterator<Item= &'a T>) -> StoreSearchAnyIter<'_, T>
where String: Borrow<T> where String: Borrow<T>
{ {
let mut sorted: SmallVec<[_; 5]> = tags.into_iter().collect(); let mut sorted: SmallVec<[_; 8]> = tags.into_iter().collect();
sorted.sort(); sorted.sort();
StoreSearchIter(self, Some(match (sorted.first(), sorted.last()) { StoreSearchAnyIter(self, Some(match (sorted.first(), sorted.last()) {
(Some(&low), Some(&high)) => self.tags.range::<T, _>((std::ops::Bound::Included(low), std::ops::Bound::Included(high))), (Some(&low), Some(&high)) => self.tags.range::<T, _>((std::ops::Bound::Included(low), std::ops::Bound::Included(high))),
_ => return StoreSearchIter(self, None, Default::default(), PhantomData), _ => return StoreSearchAnyIter(self, None, Default::default(), PhantomData),
}), VecDeque::new(), PhantomData) }), VecDeque::new(), PhantomData)
} }
/// Search for all items with this provided tag. /// Search for all items with this provided tag.
/// ///
/// # Notes /// # Notes
/// This is allowed to produce duplicate entries, if an entry has two of the same tags set. /// This is allowed to produce duplicate entries, if an entry has two of the same tags set.
pub fn tag_search<'a, T: ?Sized + Ord>(&'a self, tag: &T) -> StoreSearchIter<'a, T> pub fn tag_search<'a, T: ?Sized + Ord>(&'a self, tag: &T) -> StoreSearchAnyIter<'a, T>
where String: Borrow<T> where String: Borrow<T>
{ {
let r= (std::ops::Bound::Included(tag), std::ops::Bound::Included(tag)); let r= (std::ops::Bound::Included(tag), std::ops::Bound::Included(tag));
StoreSearchIter(self, Some(self.tags.range::<T, _>(r)), VecDeque::new(), PhantomData) StoreSearchAnyIter(self, Some(self.tags.range::<T, _>(r)), VecDeque::new(), PhantomData)
} }
fn _assert_test_search(&self) fn _assert_test_search(&self)
{ {
let _x: Vec<_> = self.tag_search("hello").dedup_ref().collect();
let _x: Vec<_> = self.tag_search_any(vec!["hello", "one", "two"]).dedup_ref().collect(); let _x: Vec<_> = self.tag_search_any(vec!["hello", "one", "two"]).dedup_ref().collect();
let _x: Vec<_> = self.tag_search_all(vec!["hello", "one", "two"]).dedup_ref().collect();
} }
} }
impl<'a, T: ?Sized> Iterator for StoreSearchIter<'a, T> impl<'a, T: ?Sized> Iterator for StoreSearchAllIter<'a, T>
where T: Ord,
String: Borrow<T>
{
type Item = &'a Entry;
fn next(&mut self) -> Option<Self::Item>
{
if let Some(range) = &mut self.1 {
if let Some((_, &ti)) = range.next() {
// tag index get
let data_hashes = &self.0.data_hashes;
let data = &self.0.data;
let tags = &self.3;
let iter = self.0.tag_mappings.get(ti)
.map_into_iter()
.filter_map(move |&idx| data_hashes.get(idx))
.filter_map(move |x| data.get(x))
// Ensure all our `tags` are present in the entry's tags
.filter(move |entry| tags.iter()
.filter(move |&x| entry.tags
.binary_search_by_key(x, |t: &String| -> &T { t.borrow() })
.is_err())
.count() == 0);
self.2.extend(iter);
}
} else {
return None;
}
self.2.pop_front()
}
fn size_hint(&self) -> (usize, Option<usize>) {
match self.1 {
None => (0, Some(0)),
Some(_) => (0, None),
}
}
}
impl<'a, T: ?Sized> Iterator for StoreSearchAnyIter<'a, T>
{ {
type Item = &'a Entry; type Item = &'a Entry;
fn next(&mut self) -> Option<Self::Item> fn next(&mut self) -> Option<Self::Item>
@ -84,4 +133,4 @@ impl<'a, T: ?Sized> Iterator for StoreSearchIter<'a, T>
} }
} }
} }
impl<'a, T: ?Sized> iter::FusedIterator for StoreSearchIter<'a, T>{} impl<'a, T: ?Sized> iter::FusedIterator for StoreSearchAnyIter<'a, T>{}

@ -137,23 +137,20 @@ where I: Iterator<Item = &'a T> + DoubleEndedIterator
impl<'a, I, T:?Sized + 'a> FusedIterator for DedupedRefIter<'a, I, T> impl<'a, I, T:?Sized + 'a> FusedIterator for DedupedRefIter<'a, I, T>
where I: Iterator<Item = &'a T> + FusedIterator{} where I: Iterator<Item = &'a T> + FusedIterator{}
pub trait ContainsAllExt<T, U, I> pub trait ContainsAllExt<T>
where U: AsRef<T>,
I: IntoIterator<Item = U>,
{ {
fn contains_all(&self, items: I) -> bool; fn contains_all<V: AsRef<[T]>>(&self, items: V) -> bool;
} }
impl<T, U, S, I> ContainsAllExt<T, U, I> for S impl<T, S> ContainsAllExt<T> for S
where S: AsRef<[T]>, where S: AsRef<[T]>,
U: AsRef<T>,
I: IntoIterator<Item = U>,
T: PartialEq, T: PartialEq,
{ {
fn contains_all(&self, items: I) -> bool { fn contains_all<V: AsRef<[T]>>(&self, items: V) -> bool {
for x in items.into_iter() let s = self.as_ref();
for x in items.as_ref().iter()
{ {
if !self.as_ref().contains(x.as_ref()) { if !s.contains(x) {
return false; return false;
} }
} }

Loading…
Cancel
Save