use std::cmp::{max};
use tree::{Node, NodeInfo, TreeBuilder};
use interval::Interval;
#[derive(Clone, Default)]
pub struct Subset(Vec<(usize, usize)>);
#[derive(Default)]
pub struct SubsetBuilder {
dels: Vec<(usize, usize)>,
b: usize,
e: usize,
}
impl SubsetBuilder {
pub fn new() -> SubsetBuilder {
SubsetBuilder::default()
}
pub fn add_deletion(&mut self, beg: usize, end: usize) {
if beg > self.e {
if self.e > self.b {
self.dels.push((self.b, self.e));
}
self.b = beg
}
self.e = end;
}
pub fn build(mut self) -> Subset {
if self.e > self.b {
self.dels.push((self.b, self.e));
}
Subset(self.dels)
}
}
impl Subset {
pub fn apply_to_string(&self, s: &str) -> String {
let mut result = String::new();
for (b, e) in self.range_iter(s.len()) {
result.push_str(&s[b..e]);
}
result
}
pub fn apply<N: NodeInfo>(&self, s: &Node<N>) -> Node<N> {
let mut b = TreeBuilder::new();
for (beg, end) in self.range_iter(s.len()) {
s.push_subseq(&mut b, Interval::new_closed_open(beg, end));
}
b.build()
}
pub fn len(&self, base_len: usize) -> usize {
self.0.iter().fold(base_len, |acc, &(b, e)| acc - (e - b))
}
pub fn is_trivial(&self) -> bool {
self.0.is_empty()
}
#[doc(hidden)]
pub fn _deletions(&self) -> &[(usize, usize)] {
&self.0
}
pub fn intersect(&self, other: &Subset) -> Subset {
let mut sb = SubsetBuilder::new();
let mut i = 0;
let mut j = 0;
loop {
let (next_beg, mut next_end) = if i == self.0.len() {
if j == other.0.len() {
break;
} else {
let del = other.0[j];
j += 1;
del
}
} else if j == other.0.len() || self.0[i].0 < other.0[j].0 {
let del = self.0[i];
i += 1;
del
} else {
let del = other.0[j];
j += 1;
del
};
loop {
if i < self.0.len() && self.0[i].0 <= next_end {
next_end = max(next_end, self.0[i].1);
i += 1;
continue;
} else if j < other.0.len() && other.0[j].0 <= next_end {
next_end = max(next_end, other.0[j].1);
j += 1;
continue;
} else {
break;
}
}
sb.add_deletion(next_beg, next_end);
}
sb.build()
}
pub fn transform_expand(&self, other: &Subset) -> Subset {
let mut sb = SubsetBuilder::new();
let mut last = 0;
let mut i = 0;
let mut delta = 0;
for &(b, e) in &other.0 {
loop {
if i >= self.0.len() {
return sb.build();
}
if self.0[i].1 + delta < b {
sb.add_deletion(max(last, self.0[i].0 + delta), self.0[i].1 + delta);
i += 1;
} else {
break;
}
}
if self.0[i].0 + delta < b {
sb.add_deletion(max(last, self.0[i].0 + delta), b);
}
last = e;
delta += e - b;
}
if i < self.0.len() && self.0[i].0 + delta < last {
sb.add_deletion(last, self.0[i].1 + delta);
i += 1;
}
for &(b, e) in &self.0[i..] {
sb.add_deletion(b + delta, e + delta);
}
sb.build()
}
pub fn transform_intersect(&self, other: &Subset) -> Subset {
let mut sb = SubsetBuilder::new();
let mut last = 0;
let mut i = 0;
let mut delta = 0;
for &(b, e) in &other.0 {
while i < self.0.len() && self.0[i].1 + delta < b {
sb.add_deletion(max(last, self.0[i].0 + delta), self.0[i].1 + delta);
i += 1;
}
if i < self.0.len() && self.0[i].0 + delta < b {
sb.add_deletion(max(last, self.0[i].0 + delta), b);
}
sb.add_deletion(b, e);
last = e;
delta += e - b;
}
if i < self.0.len() && self.0[i].0 + delta < last {
sb.add_deletion(last, self.0[i].1 + delta);
i += 1;
}
for &(b, e) in &self.0[i..] {
sb.add_deletion(b + delta, e + delta);
}
sb.build()
}
pub fn transform_shrink(&self, other: &Subset) -> Subset {
let mut sb = SubsetBuilder::new();
let mut last = 0;
let mut i = 0;
let mut y = 0;
for &(b, e) in &self.0 {
if i < other.0.len() && other.0[i].0 < last && other.0[i].1 < b {
sb.add_deletion(y, other.0[i].1 + y - last);
i += 1;
}
while i < other.0.len() && other.0[i].1 < b {
sb.add_deletion(other.0[i].0 + y - last, other.0[i].1 + y - last);
i += 1;
}
if i < other.0.len() && other.0[i].0 < b {
sb.add_deletion(max(last, other.0[i].0) + y - last, b + y - last);
}
while i < other.0.len() && other.0[i].1 < e {
i += 1;
}
y += b - last;
last = e;
}
if i < other.0.len() && other.0[i].0 < last {
sb.add_deletion(y, other.0[i].1 + y - last);
i += 1;
}
for &(b, e) in &other.0[i..] {
sb.add_deletion(b + y - last, e + y - last);
}
sb.build()
}
pub fn range_iter(&self, base_len: usize) -> RangeIter {
RangeIter {
deletions: &self.0,
base_len: base_len,
i: 0,
last: 0,
}
}
}
pub struct RangeIter<'a> {
deletions: &'a [(usize, usize)],
base_len: usize,
i: usize,
last: usize,
}
impl<'a> Iterator for RangeIter<'a> {
type Item = (usize, usize);
fn next(&mut self) -> Option<(usize, usize)> {
loop {
if self.i == self.deletions.len() {
if self.base_len > self.last {
let beg = self.last;
self.last = self.base_len;
return Some((beg, self.base_len));
} else {
return None;
}
} else {
let beg = self.last;
let (end, last) = self.deletions[self.i];
self.last = last;
self.i += 1;
if end > beg {
return Some((beg, end));
}
}
}
}
}
#[cfg(test)]
mod tests {
use subset::{Subset, SubsetBuilder};
const TEST_STR: &'static str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
fn mk_subset(substr: &str, s: &str) -> Subset {
let mut sb = SubsetBuilder::new();
let mut j = 0;
for i in 0..s.len() {
if j < substr.len() && substr.as_bytes()[j] == s.as_bytes()[i] {
j += 1;
} else {
sb.add_deletion(i, i + 1);
}
}
sb.build()
}
#[test]
fn test_apply() {
let mut sb = SubsetBuilder::new();
for &(b, e) in &[(0, 1), (2, 4), (6, 11), (13, 14), (15, 18), (19, 23), (24, 26), (31, 32),
(33, 35), (36, 37), (40, 44), (45, 48), (49, 51), (52, 57), (58, 59)] {
sb.add_deletion(b, e);
}
let s = sb.build();
assert_eq!("145BCEINQRSTUWZbcdimpvxyz", s.apply_to_string(TEST_STR));
}
#[test]
fn trivial() {
let s = SubsetBuilder::new().build();
assert!(s.is_trivial());
}
#[test]
fn test_mk_subset() {
let substr = "015ABDFHJOPQVYdfgloprsuvz";
let s = mk_subset(substr, TEST_STR);
assert_eq!(substr, s.apply_to_string(TEST_STR));
assert!(!s.is_trivial())
}
#[test]
fn intersect() {
let s1 = mk_subset("024AEGHJKNQTUWXYZabcfgikqrvy", TEST_STR);
let s2 = mk_subset("14589DEFGIKMOPQRUXZabcdefglnpsuxyz", TEST_STR);
assert_eq!("4EGKQUXZabcfgy", s1.intersect(&s2).apply_to_string(TEST_STR));
}
fn transform_case(str1: &str, str2: &str, result: &str) {
let s1 = mk_subset(str1, TEST_STR);
let s2 = mk_subset(str2, str1);
let s3 = s2.transform_expand(&s1);
let str3 = s3.apply_to_string(TEST_STR);
assert_eq!(result, str3);
assert_eq!(str2, s3.transform_shrink(&s1).apply_to_string(&str3));
assert_eq!(str2, s2.transform_intersect(&s1).apply_to_string(TEST_STR));
}
#[test]
fn transform() {
transform_case("02345678BCDFGHKLNOPQRTUVXZbcefghjlmnopqrstwx", "027CDGKLOTUbcegopqrw",
"01279ACDEGIJKLMOSTUWYabcdegikopqruvwyz");
transform_case("01234678DHIKLMNOPQRUWZbcdhjostvy", "136KLPQZvy",
"13569ABCEFGJKLPQSTVXYZaefgiklmnpqruvwxyz");
transform_case("0125789BDEFIJKLMNPVXabdjmrstuwy", "12BIJVXjmrstu",
"12346ABCGHIJOQRSTUVWXYZcefghijklmnopqrstuvxz");
transform_case("12456789ABCEFGJKLMNPQRSTUVXYadefghkrtwxz", "15ACEFGKLPRUVYdhrtx",
"0135ACDEFGHIKLOPRUVWYZbcdhijlmnopqrstuvxy");
transform_case("0128ABCDEFGIJMNOPQXYZabcfgijkloqruvy", "2CEFGMZabijloruvy",
"2345679CEFGHKLMRSTUVWZabdehijlmnoprstuvwxyz");
transform_case("01245689ABCDGJKLMPQSTWXYbcdfgjlmnosvy", "01245ABCDJLQSWXYgsv",
"0123457ABCDEFHIJLNOQRSUVWXYZaeghikpqrstuvwxz");
}
}