use crate::accum_ftzr::{Ftzr, IterFtzr, LinearFixed};
use crate::as_tokens::AsTokens;
use crate::feature_from::FeatureFrom;
use std::cmp;
#[cfg(feature = "serde1")]
use serde::{Deserialize, Serialize};
use std::marker::PhantomData;
#[derive(Hash, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Debug)]
pub struct GapGramIter<A, B, T, U1, U2> {
a: A,
b: B,
gap: usize,
data: T,
idx: usize,
tok2: PhantomData<(U1, U2)>,
total_size: usize,
}
impl<'a, A, B, T, U1: 'a, U2: 'a> GapGramIter<A, B, &'a [T], U1, U2> {
fn new<
AF: LinearFixed + IterFtzr<&'a [T], TokenGroup = U1, Iter = A>,
BF: LinearFixed + IterFtzr<&'a [T], TokenGroup = U2, Iter = B>,
>(
origin: &'a [T],
af: &AF,
gap: usize,
bf: &BF,
) -> Self {
let a = af.iterate_features(origin);
let b_start = cmp::min(af.chunk_size() + gap, origin.len());
let b = bf.iterate_features(&origin[b_start..]);
GapGramIter {
a,
b,
gap,
idx: 0,
data: origin,
tok2: Default::default(),
total_size: af.chunk_size() + gap + bf.chunk_size(),
}
}
}
impl<'a, A, B, T, U1, U2: 'a> Iterator for GapGramIter<A, B, &'a [T], U1, U2>
where
A: Iterator<Item = U1>,
B: Iterator<Item = U2>,
{
type Item = GapPair<U1, U2>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let jdx = self.idx + self.total_size;
if jdx <= self.data.len() {
let a = self.a.next();
let b = self.b.next();
match (a, b) {
(Some(aa), Some(bb)) => {
self.idx += 1;
return Some(GapPair(aa, bb, self.gap as u16));
}
_ => return None,
}
}
None
}
}
#[derive(Hash, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Debug)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct GapGram<A, B> {
a: A,
gap: usize,
b: B,
}
#[derive(Hash, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Debug)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct GapPair<A, B>(pub(crate) A, pub(crate) B, pub(crate) u16);
impl<A1, A2: From<A1>, B1, B2: From<B1>> From<GapPair<A1, B1>> for (A2, B2) {
fn from(sp: GapPair<A1, B1>) -> Self {
(From::from(sp.0), From::from(sp.1))
}
}
impl<A1, A2, B1, B2, C1, C2, D1, D2> FeatureFrom<GapPair<GapPair<A1, B1>, GapPair<C1, D1>>>
for (A2, B2, C2, D2)
where
A2: FeatureFrom<A1>,
B2: FeatureFrom<B1>,
C2: FeatureFrom<C1>,
D2: FeatureFrom<D1>,
{
fn from(t: GapPair<GapPair<A1, B1>, GapPair<C1, D1>>) -> Self {
(
FeatureFrom::from(t.0 .0),
FeatureFrom::from(t.0 .1),
FeatureFrom::from(t.1 .0),
FeatureFrom::from(t.1 .1),
)
}
}
impl<A, B: FeatureFrom<A>> FeatureFrom<GapPair<GapPair<A, A>, GapPair<A, A>>> for [B; 4] {
fn from(t: GapPair<GapPair<A, A>, GapPair<A, A>>) -> Self {
[
FeatureFrom::from(t.0 .0),
FeatureFrom::from(t.0 .1),
FeatureFrom::from(t.1 .0),
FeatureFrom::from(t.1 .1),
]
}
}
impl<A1, A2: FeatureFrom<A1>, B1, B2: FeatureFrom<B1>> FeatureFrom<GapPair<A1, B1>> for (A2, B2) {
fn from(sp: GapPair<A1, B1>) -> Self {
(FeatureFrom::from(sp.0), FeatureFrom::from(sp.1))
}
}
impl<A: LinearFixed, B: LinearFixed> LinearFixed for GapGram<A, B> {
fn chunk_size(&self) -> usize {
self.a.chunk_size() + self.gap + self.b.chunk_size()
}
}
impl<'a, D, T: 'a, A, B, U1: 'a, U2: 'a> IterFtzr<&'a D> for GapGram<A, B>
where
D: AsTokens<Token = T> + ?Sized,
A: LinearFixed + IterFtzr<&'a [T], TokenGroup = U1>,
B: LinearFixed + IterFtzr<&'a [T], TokenGroup = U2>,
{
type TokenGroup = GapPair<U1, U2>;
type Iter = GapGramIter<A::Iter, B::Iter, &'a [T], U1, U2>;
fn iterate_features(&self, origin: &'a D) -> Self::Iter {
GapGramIter::new(origin.as_tokens(), &self.a, self.gap, &self.b)
}
}
pub fn gap_gram<A, B>(a: A, gap: usize, b: B) -> GapGram<A, B> {
GapGram { a, gap, b }
}
impl<Origin, A, B> Ftzr<Origin> for GapGram<A, B>
where
Self: IterFtzr<Origin>,
{
type TokenGroup = <Self as IterFtzr<Origin>>::TokenGroup;
fn push_tokens<Push>(&self, origin: Origin, push: &mut Push)
where
Push: FnMut(Self::TokenGroup),
{
for t in self.iterate_features(origin) {
push(t)
}
}
}