use crate::TagVec;
use crate::BitField;
use std::hash::Hash;
pub mod expressions {
use crate::query::Expression;
use std::hash::Hash;
pub fn tag<'a, Q>(tag: &'a Q) -> Expression<'a, Q>
where Q: ?Sized + Eq + Hash {
Expression::Tag(tag)
}
pub fn and<'a, Q>(a: Expression<'a, Q>, b: Expression<'a, Q>) -> Expression<'a, Q>
where Q: ?Sized + Eq + Hash {
Expression::And(Box::new(a), Box::new(b))
}
pub fn or<'a, Q>(a: Expression<'a, Q>, b: Expression<'a, Q>) -> Expression<'a, Q>
where Q: ?Sized + Eq + Hash {
Expression::Or(Box::new(a), Box::new(b))
}
pub fn not<'a, Q>(a: Expression<'a, Q>) -> Expression<'a, Q>
where Q: ?Sized + Eq + Hash {
Expression::Not(Box::new(a))
}
}
pub enum Expression<'a, Q> where Q: ?Sized + Hash + Eq + 'a {
And(Box<Expression<'a, Q>>, Box<Expression<'a, Q>>),
Or(Box<Expression<'a, Q>>, Box<Expression<'a, Q>>),
Not(Box<Expression<'a, Q>>),
Tag(&'a Q),
}
impl<'a, Q: ?Sized + Hash + Eq + 'a> Expression<'a, Q> {
fn command_size(&self) -> usize {
use Expression::*;
match self {
And(a, b) => 1 + a.command_size() + b.command_size(),
Or(a, b) => 1 + a.command_size() + b.command_size(),
Not(a) => 1 + a.command_size(),
Tag(_) => 1,
}
}
fn to_commands(self, tag_requests: &mut Vec<&'a Q>, commands: &mut Vec<u16>) {
use Expression::*;
match self {
And(a, b) => {
a.to_commands(tag_requests, commands);
b.to_commands(tag_requests, commands);
commands.push(QUERY_CMD_AND);
},
Or(a, b) => {
a.to_commands(tag_requests, commands);
b.to_commands(tag_requests, commands);
commands.push(QUERY_CMD_OR);
},
Not(a) => {
a.to_commands(tag_requests, commands);
commands.push(QUERY_CMD_NOT);
},
Tag(tag) => {
let id = tag_requests.len() as u16;
assert!(id < QUERY_CMD_TAG);
tag_requests.push(tag);
commands.push(id);
},
}
}
}
const QUERY_CMD_AND: u16 = 0xFFFF;
const QUERY_CMD_OR: u16 = 0xFFFD;
const QUERY_CMD_NOT: u16 = 0xFFFC;
const QUERY_CMD_TAG: u16 = 0xFFFC;
pub struct Query<'a, F>
where
F: BitField {
tag_data: Vec<Option<&'a [F]>>,
commands: Vec<u16>,
bit_ctr: usize,
total_bits: usize,
data: F,
stack: Vec<F>,
}
impl<'a, F> Query<'a, F>
where
F: BitField
{
pub(crate) fn create_from<T, Q>(vec: &'a TagVec<T, F>, expr: Expression<'a, Q>)
-> Query<'a, F>
where T: Eq + Hash + Clone + std::borrow::Borrow<Q>,
Q: ?Sized + Eq + Hash + 'a {
let mut tag_requests = Vec::new();
let mut commands = Vec::with_capacity(expr.command_size());
expr.to_commands(&mut tag_requests, &mut commands);
let tag_data: Vec<_> = tag_requests.into_iter()
.map(|request| vec.tag_fields.get(request).map(|v| v.data())).collect();
Query {
tag_data,
commands,
bit_ctr: 0,
total_bits: vec.len(),
data: F::empty(),
stack: Vec::new(),
}
}
fn sloppy_next(&mut self) -> bool {
let local_index = self.bit_ctr % F::n_bits();
if local_index == 0 {
let data_index = self.bit_ctr / F::n_bits();
self.stack.clear();
let stack = &mut self.stack;
let commands = &self.commands;
let tag_data = &self.tag_data;
for cmd in commands.iter() {
match *cmd {
QUERY_CMD_AND => {
let a = stack.pop().unwrap();
let b = stack.pop().unwrap();
stack.push(a & b);
},
QUERY_CMD_OR => {
let a = stack.pop().unwrap();
let b = stack.pop().unwrap();
stack.push(a | b);
},
QUERY_CMD_NOT => {
let a = stack.pop().unwrap();
stack.push(!a);
},
tag => {
stack.push(tag_data[tag as usize].map_or(F::empty(), |v| v[data_index]));
},
}
}
self.data = stack[0];
}
self.bit_ctr += 1;
self.data.get_bit(local_index)
}
}
impl<'a, F> Iterator for Query<'a, F> where F: BitField {
type Item = usize;
fn next(&mut self) -> Option<usize> {
while self.bit_ctr < self.total_bits {
if self.sloppy_next() {
return Some(self.bit_ctr - 1);
}
}
None
}
}