use crate::index::Indexable;
pub trait Store: Filterable {
fn insert(&mut self, key: Self::Key, idx: Self::Index);
fn update(&mut self, old_key: Self::Key, idx: Self::Index, new_key: Self::Key) {
self.delete(old_key, &idx);
self.insert(new_key, idx);
}
fn delete(&mut self, key: Self::Key, idx: &Self::Index);
fn with_capacity(capacity: usize) -> Self;
fn from_list<I>(it: I) -> Self
where
I: IntoIterator<Item = Self::Key>,
<I as IntoIterator>::IntoIter: ExactSizeIterator,
Self: Store<Index = usize>,
Self: Sized,
{
Self::from_map(it.into_iter().enumerate().map(|(x, k)| (k, x)))
}
fn from_map<I>(it: I) -> Self
where
I: IntoIterator<Item = (Self::Key, Self::Index)> + ExactSizeIterator,
Self: Sized,
{
let mut store = Self::with_capacity(it.len());
it.into_iter().for_each(|(k, idx)| store.insert(k, idx));
store
}
}
pub trait Filterable {
type Key;
type Index;
fn contains(&self, key: &Self::Key) -> bool;
fn get(&self, key: &Self::Key) -> &[Self::Index];
fn get_with_check<F>(&self, key: &Self::Key, check: F) -> &[Self::Index]
where
F: Fn(&Self::Key) -> bool,
{
if check(key) {
return self.get(key);
}
&[]
}
fn get_many<'k, K>(&'k self, keys: K) -> Many<'k, Self, <K as IntoIterator>::IntoIter>
where
K: IntoIterator<Item = Self::Key>,
K: 'k,
Self: Sized,
{
Many::new(self, keys.into_iter())
}
}
pub trait MetaData {
type Meta<'m>
where
Self: 'm;
fn meta(&self) -> Self::Meta<'_>;
}
pub struct Many<'m, F, K>
where
F: Filterable,
{
filter: &'m F,
keys: K,
iter: std::slice::Iter<'m, F::Index>,
}
impl<'m, F, K> Many<'m, F, K>
where
F: Filterable,
K: Iterator<Item = F::Key> + 'm,
{
pub fn new(filter: &'m F, mut keys: K) -> Self {
let iter = match keys.next() {
Some(k) => filter.get(&k).iter(),
None => [].iter(),
};
Self { filter, keys, iter }
}
#[inline]
pub fn items<I>(
self,
items: &'m I,
) -> impl Iterator<Item = &'m <I as Indexable<F::Index>>::Output>
where
I: Indexable<F::Index>,
<I as Indexable<F::Index>>::Output: Sized,
{
items.items(self)
}
pub fn items_vec<I>(self, items: &'m I) -> Vec<&'m <I as Indexable<F::Index>>::Output>
where
I: Indexable<F::Index>,
<I as Indexable<F::Index>>::Output: Sized,
{
items.items(self).collect()
}
}
impl<'m, F, K> Iterator for Many<'m, F, K>
where
F: Filterable + 'm,
K: Iterator<Item = F::Key> + 'm,
Self: 'm,
{
type Item = &'m F::Index;
fn next(&mut self) -> Option<Self::Item> {
let idx = self.iter.next();
#[allow(clippy::nonminimal_bool)]
if !idx.is_none() {
return idx;
}
loop {
let key = self.keys.next()?;
let idx = self.filter.get(&key);
if !idx.is_empty() {
self.iter = idx.iter();
return self.iter.next();
}
}
}
}
pub trait ToStore<X, T> {
fn to_store<S, F>(&self, field: F) -> S
where
S: Store<Index = X>,
F: FnMut(&T) -> S::Key;
}
impl<T, const N: usize> ToStore<usize, T> for [T; N] {
fn to_store<S, F>(&self, field: F) -> S
where
S: Store<Index = usize>,
F: FnMut(&T) -> <S>::Key,
{
S::from_list(self.iter().map(field))
}
}
impl<'a, T> ToStore<usize, T> for &'a [T] {
fn to_store<S, F>(&self, field: F) -> S
where
S: Store<Index = usize>,
F: FnMut(&T) -> <S>::Key,
{
S::from_list(self.iter().map(field))
}
}
impl<T> ToStore<usize, T> for Vec<T> {
fn to_store<S, F>(&self, field: F) -> S
where
S: Store<Index = usize>,
F: FnMut(&T) -> <S>::Key,
{
S::from_list(self.iter().map(field))
}
}
impl<T> ToStore<usize, T> for std::collections::VecDeque<T> {
fn to_store<S, F>(&self, field: F) -> S
where
S: Store<Index = usize>,
F: FnMut(&T) -> <S>::Key,
{
S::from_list(self.iter().map(field))
}
}
impl<X, T> ToStore<X, T> for std::collections::HashMap<X, T>
where
X: Clone,
{
fn to_store<S, F>(&self, mut field: F) -> S
where
S: Store<Index = X>,
F: FnMut(&T) -> <S>::Key,
{
S::from_map(self.iter().map(|(idx, item)| (field(item), idx.clone())))
}
}
impl<X, T> ToStore<X, T> for std::collections::BTreeMap<X, T>
where
X: Clone,
{
fn to_store<S, F>(&self, mut field: F) -> S
where
S: Store<Index = X>,
F: FnMut(&T) -> <S>::Key,
{
S::from_map(self.iter().map(|(idx, item)| (field(item), idx.clone())))
}
}
#[cfg(test)]
mod tests {
use super::{super::filter::Filter, *};
use crate::index::{
indices::{Indices, KeyIndices},
map::MapIndex,
};
use rstest::rstest;
use std::collections::HashMap;
struct StrIndex {
idx: HashMap<&'static str, KeyIndices>,
}
impl StrIndex {
fn new() -> Self {
let mut double_a = KeyIndices::new(0);
double_a.add(3);
let mut idx = HashMap::new();
idx.insert("a", double_a);
idx.insert("b", KeyIndices::new(1));
idx.insert("c", KeyIndices::new(2));
idx.insert("s", KeyIndices::new(4));
Self { idx }
}
}
impl Filterable for StrIndex {
type Key = &'static str;
type Index = usize;
fn get(&self, key: &Self::Key) -> &[usize] {
match self.idx.get(key) {
Some(i) => i.as_slice(),
None => &[],
}
}
fn contains(&self, key: &Self::Key) -> bool {
self.idx.contains_key(key)
}
}
trait Or<'f> {
type Key;
fn or(&'f self, key1: &Self::Key, key2: &Self::Key) -> Indices<'f, usize>;
}
impl<'f, F: Filterable<Index = usize>> Or<'f> for Filter<'f, F> {
type Key = F::Key;
fn or(&'f self, key1: &Self::Key, key2: &Self::Key) -> Indices<'f, usize> {
self.eq(key1) | self.eq(key2)
}
}
fn extended_filter<'i>(f: &'i Filter<'i, StrIndex>, key: &'static &str) -> &'i [usize] {
f.0.get(key)
}
#[test]
fn filter() {
let list = StrIndex::new();
let f = Filter(&list);
assert!(f.contains(&"a"));
assert!(!f.contains(&"zz"));
assert_eq!([1], f.eq(&"b"));
assert_eq!([0, 1, 3], (f.eq(&"a") | f.eq(&"b")));
assert_eq!([2], f.eq(&"c"));
assert_eq!([], f.eq(&"zz"));
}
#[test]
fn extend_filter() {
let list = StrIndex::new();
let f = Filter(&list);
assert_eq!([0, 2, 3], f.or(&"c", &"a"));
assert_eq!([0, 3], f.or(&"zz", &"a"));
assert_eq!([], f.or(&"zz", &"xx"));
assert_eq!([2], extended_filter(&f, &"c"));
}
#[rstest]
#[case::empty(vec![], vec![])]
#[case::one_found(vec!["c"], vec![&"c"])]
#[case::one_not_found(vec!["-"], vec![])]
#[case::m_z_a(vec!["m", "z", "a"], vec![&"z", &"a"])]
#[case::a_m_z(vec![ "a","m", "z"], vec![&"a", &"z"])]
#[case::z_m_a(vec![ "z","m", "a"], vec![&"z", &"a"])]
#[case::m_z_a_m(vec!["m", "z", "a", "m"], vec![&"z", &"a"])]
#[case::m_z_a_m_m(vec!["m", "z", "a", "m", "m"], vec![&"z", &"a"])]
#[case::double_x(vec!["x"], vec![&"x", &"x"])]
#[case::a_double_x(vec!["a", "x"], vec![&"a", &"x", &"x"])]
fn view_str(#[case] keys: Vec<&str>, #[case] expected: Vec<&&str>) {
let items = vec!["x", "a", "b", "c", "x", "y", "z"];
let map = MapIndex::from_list(items.clone());
assert_eq!(expected, map.get_many(keys).items_vec(&items));
}
}