use std::collections::HashMap;
use std::hash::Hash;
mod dyn_bit_field;
use dyn_bit_field::DynamicBitField;
mod bit_field;
mod query;
pub use bit_field::BitField;
pub use query::Query;
pub use query::Expression;
pub use query::expressions;
pub struct TagVec<T, F = u32>
where T: Eq + Hash + Clone, F: BitField {
tag_fields: HashMap<T, DynamicBitField<F>>,
len: usize,
}
impl<T: Eq + Hash + Clone, F: BitField> TagVec<T, F> {
pub fn new() -> TagVec<T, F> {
TagVec {
tag_fields: HashMap::new(),
len: 0,
}
}
pub fn len(&self) -> usize { self.len }
pub fn push<'a, I, Q>(&mut self, tags: I)
where I: IntoIterator<Item = &'a Q>,
Q: ?Sized + Hash + Eq + 'a,
T: From<&'a Q> + std::borrow::Borrow<Q> {
let mut skipped_tags: Vec<T> = Vec::new();
for tag in tags {
match self.tag_fields.get_mut(tag) {
Some(field) => field.push(true),
None => skipped_tags.push(tag.into()),
}
}
for tag_field in self.tag_fields.values_mut() {
if tag_field.len() < self.len + 1 {
tag_field.push(false);
}
}
for skipped_tag in skipped_tags {
let mut new_field = DynamicBitField::with_false(self.len());
new_field.push(true); self.tag_fields.insert(skipped_tag, new_field);
}
self.len += 1;
}
pub fn query<'a, Q>(&'a self, expr: query::Expression<'a, Q>) -> query::Query<'a, F>
where Q: ?Sized + Hash + Eq + 'a,
T: std::borrow::Borrow<Q> {
query::Query::create_from(self, expr)
}
pub fn iter_element<'a>(&'a self, index: usize) -> IterElement<'a, T, F>
{
assert!(index < self.len(), "Cannot iter over an element out of bounds");
IterElement {
fields: self.tag_fields.iter(),
element_id: index
}
}
}
#[derive(Clone)]
pub struct IterElement<'a, T, F>
where T: Eq + Hash + Clone, F: BitField {
fields: std::collections::hash_map::Iter<'a, T, DynamicBitField<F>>,
element_id: usize,
}
impl<T: Eq + Hash + Clone, F: BitField> std::iter::FusedIterator for IterElement<'_, T, F> {}
impl<'a, T: Eq + Hash + Clone, F: BitField> Iterator for IterElement<'a, T, F> {
type Item = &'a T;
fn next(&mut self) -> Option<&'a T> {
while let Some((key, field)) = self.fields.next() {
if field.get_unchecked(self.element_id) {
return Some(key);
}
}
None
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pushing() {
let mut tags = TagVec::<String>::new();
assert_eq!(tags.tag_fields.len(), 0);
tags.push(vec!["hello", "sir"]);
tags.push(vec!["other", "sir"]);
assert_eq!(tags.tag_fields.len(), 3);
let tag_vec: Vec<_> = tags.iter_element(0).collect();
assert_eq!(tag_vec.len(), 2);
assert!(tag_vec.iter().any(|v| *v == "hello"));
assert!(tag_vec.iter().any(|v| *v == "sir"));
}
#[test]
fn extreme_queries() {
let mut tags = TagVec::<String, u8>::new();
tags.push(vec!["hi", "yuh"]);
tags.push(vec!["hi2", "yuh"]);
tags.push(vec!["hi", "yuh"]);
tags.push(vec!["hi", "yuh"]);
tags.push(vec!["hi", "yuh"]);
tags.push(vec!["hi", "yuh"]);
tags.push(vec!["hi", "yuh"]);
tags.push(vec!["hi", "yuh"]);
tags.push(vec!["hi", "yuh"]);
tags.push(vec!["hi", "yuh"]);
tags.push(vec!["hi", "yuh"]);
tags.push(vec!["hi", "yuh"]);
tags.push(vec!["hi2", "yuh"]);
tags.push(vec!["hi", "yuh"]);
tags.push(vec!["hi", "yuh"]);
tags.push(vec!["hi", "yuh"]);
tags.push(vec!["hi", "yuh"]);
tags.push(vec!["hi", "yuh"]);
tags.push(vec!["hi", "yuh"]);
tags.push(vec!["hi2", "yuh"]);
tags.push(vec!["hi", "yuh"]);
use super::expressions::*;
let contains: Vec<_> = tags.query(tag("hi2")).collect();
assert_eq!(contains.len(), 3);
assert_eq!(contains[0], 1);
assert_eq!(contains[1], 12);
assert_eq!(contains[2], 19);
}
}