From 5c4c4bc08ab0f24476fb0eaff4c5bfafbfba9f6c Mon Sep 17 00:00:00 2001 From: Avril Date: Sat, 19 Dec 2020 14:18:24 +0000 Subject: [PATCH] start search_all --- src/data/search.rs | 32 ++++++++++++---- src/ext.rs | 92 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 7 deletions(-) diff --git a/src/data/search.rs b/src/data/search.rs index 841e1ea..7c36083 100644 --- a/src/data/search.rs +++ b/src/data/search.rs @@ -14,29 +14,47 @@ pub struct StoreSearchIter<'a, T: ?Sized>(&'a Store, Option(&'a self, tags: impl IntoIterator) -> impl Iterator + 'a + where String: Borrow + { + let tags: SmallVec<[_; 5]> = tags.into_iter().collect(); + + tags.iter().flat_map(|&tag| self.tag_search(tag)).dedup_ref() + .filter(|x| x.tags.iter().map(|x| x.borrow()).filter(|tx| !tags.contains(tx)).count() == 0) + + /* TODO: get rid of this ,replace `impl Iterator` return with its own type. */ .collect::>().into_iter() + } /// Search for all entries with *any* of these provided tags. /// /// # Notes - /// This is allowed to produce duplicate entries. - pub fn tag_search_many(&self, tags: impl IntoIterator) -> StoreSearchIter<'_, T> + /// 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 + pub fn tag_search_any<'a, T: ?Sized + Ord + 'a>(&self, tags: impl IntoIterator) -> StoreSearchIter<'_, T> where String: Borrow { let mut sorted: SmallVec<[_; 5]> = tags.into_iter().collect(); sorted.sort(); StoreSearchIter(self, Some(match (sorted.first(), sorted.last()) { - (Some(low), Some(high)) => self.tags.range(low..=high), + (Some(&low), Some(&high)) => self.tags.range::((std::ops::Bound::Included(low), std::ops::Bound::Included(high))), _ => return StoreSearchIter(self, None, Default::default(), PhantomData), }), VecDeque::new(), PhantomData) } /// Search for all items with this provided tag. /// /// # Notes - /// This is allowed to produce duplicate entries, if an entry has two of the same tags. - pub fn tag_search<'a, T: Ord>(&'a self, tag: T) -> StoreSearchIter<'a, T> + /// 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> where String: Borrow { - let tag = &tag; - StoreSearchIter(self, Some(self.tags.range(tag..=tag)), VecDeque::new(), PhantomData) + let r= (std::ops::Bound::Included(tag), std::ops::Bound::Included(tag)); + StoreSearchIter(self, Some(self.tags.range::(r)), VecDeque::new(), PhantomData) + } + + fn _assert_test_search(&self) + { + let _x: Vec<_> = self.tag_search_any(vec!["hello", "one", "two"]).dedup_ref().collect(); } } diff --git a/src/ext.rs b/src/ext.rs index 082a3eb..24aa14e 100644 --- a/src/ext.rs +++ b/src/ext.rs @@ -1,4 +1,6 @@ use std::iter::FusedIterator; +use std::collections::BTreeSet; +use std::borrow::Borrow; /// An iterator that may be empty. #[derive(Debug, Clone)] @@ -67,4 +69,94 @@ where I: Iterator + DoubleEndedIterator } } +/// An iterator that deduplicates an iterator over references by pointer identity. +#[derive(Debug, Clone)] +pub struct DedupedRefIter<'a, I, T: ?Sized + 'a>(I, BTreeSet<*const T>) +where I: Iterator; +pub trait DedupIterExt<'a, I, T: ?Sized + 'a> +where I: Iterator +{ + /// Deduplicate this iterator by pointer identity. + fn dedup_ref(self) -> DedupedRefIter<'a, I, T>; +} + +impl<'a, I, T:?Sized+'a, IntoIter> DedupIterExt<'a, I, T> for IntoIter +where IntoIter: IntoIterator, + I: Iterator +{ + fn dedup_ref(self) -> DedupedRefIter<'a, I, T> { + DedupedRefIter(self.into_iter(), BTreeSet::new()) + } +} + +impl<'a, I, T:?Sized + 'a> Iterator for DedupedRefIter<'a, I, T> +where I: Iterator +{ + type Item = &'a T; + fn next(&mut self) -> Option + { + Some(loop { + if let Some(next) = self.0.next() + { + if self.1.insert(next as *const T) { + break next; + } + } else { + return None; + } + }) + } + + fn size_hint(&self) -> (usize, Option) { + match self.0.size_hint() + { + (0, h) => (0, h), + (_, h) => (1, h), + } + } +} + +impl<'a, I, T:?Sized + 'a> DoubleEndedIterator for DedupedRefIter<'a, I, T> +where I: Iterator + DoubleEndedIterator +{ + fn next_back(&mut self) -> Option { + Some(loop { + if let Some(next) = self.0.next_back() + { + if self.1.insert(next as *const T) { + break next; + } + } else { + return None; + } + }) + } +} + +impl<'a, I, T:?Sized + 'a> FusedIterator for DedupedRefIter<'a, I, T> +where I: Iterator + FusedIterator{} + +pub trait ContainsAllExt +where U: AsRef, + I: IntoIterator, +{ + fn contains_all(&self, items: I) -> bool; +} + +impl ContainsAllExt for S +where S: AsRef<[T]>, + U: AsRef, + I: IntoIterator, + T: PartialEq, +{ + fn contains_all(&self, items: I) -> bool { + for x in items.into_iter() + { + if !self.as_ref().contains(x.as_ref()) { + return false; + } + } + true + } +}