ICFP 2007 Contest: https://web.archive.org/web/20090301164728/https://save-endo.cs.uu.nl/

Use Add trait instead of concatenating

Changed files
+88 -84
dna2rna
src
+88 -84
dna2rna/src/dna.rs
···
use std::collections::VecDeque;
+
use std::ops::Add;
use std::ops::Deref;
use std::rc::Rc;
···
len: usize,
depth: usize,
children: (DnaRef, DnaRef, DnaRef),
-
}
-
-
enum ConcatState {
-
One(DnaRef),
-
Two(DnaRef, DnaRef),
}
impl DnaRef {
···
}
}
-
pub fn depth(&self) -> usize {
+
fn depth(&self) -> usize {
match &**self {
Dna::Empty => 0,
Dna::Leaf(_) => 1,
···
let (a, b) = &node.children;
if n < a.len() {
let (x, y) = a.split(n);
-
(x, Self::concat(y, b.clone()))
+
(x, y + b.clone())
} else if n == a.len() {
(a.clone(), b.clone())
} else {
let (x, y) = b.split(n - a.len());
-
(Self::concat(a.clone(), x), y)
+
(a.clone() + x, y)
}
}
Dna::ThreeNode(node) => {
let (a, b, c) = &node.children;
if n < a.len() {
let (x, y) = a.split(n);
-
(x, Self::concat(Self::concat(y, b.clone()), c.clone()))
+
(x, y + b.clone() + c.clone())
} else if n == a.len() {
-
(a.clone(), Self::concat(b.clone(), c.clone()))
+
(a.clone(), b.clone() + c.clone())
} else if n - a.len() < b.len() {
let (x, y) = b.split(n - a.len());
-
(Self::concat(a.clone(), x), Self::concat(y, c.clone()))
+
(a.clone() + x, y + c.clone())
} else if n == a.len() + b.len() {
-
(Self::concat(a.clone(), b.clone()), c.clone())
+
(a.clone() + b.clone(), c.clone())
} else {
let (x, y) = c.split(n - a.len() - b.len());
-
(Self::concat(a.clone(), Self::concat(b.clone(), x)), y)
-
}
-
}
-
}
-
}
-
-
fn concat_helper(lhs: DnaRef, rhs: DnaRef) -> ConcatState {
-
if lhs.depth() == rhs.depth() {
-
ConcatState::Two(lhs, rhs)
-
} else if lhs.depth() < rhs.depth() {
-
match &*rhs {
-
Dna::Empty => unreachable!(),
-
Dna::Leaf(_) => unreachable!(),
-
Dna::TwoNode(node) => {
-
let (a, b) = &node.children;
-
match Self::concat_helper(lhs, a.clone()) {
-
ConcatState::One(x) => {
-
ConcatState::One(Self::from_two_children(x, b.clone()))
-
}
-
ConcatState::Two(x, y) => {
-
ConcatState::One(Self::from_three_children(x, y, b.clone()))
-
}
-
}
-
}
-
Dna::ThreeNode(node) => {
-
let (a, b, c) = &node.children;
-
match Self::concat_helper(lhs, a.clone()) {
-
ConcatState::One(x) => {
-
ConcatState::One(Self::from_three_children(x, b.clone(), c.clone()))
-
}
-
ConcatState::Two(x, y) => ConcatState::Two(
-
Self::from_two_children(x, y),
-
Self::from_two_children(b.clone(), c.clone()),
-
),
-
}
-
}
-
}
-
} else {
-
match &*lhs {
-
Dna::Empty => unreachable!(),
-
Dna::Leaf(_) => unreachable!(),
-
Dna::TwoNode(node) => {
-
let (a, b) = &node.children;
-
match Self::concat_helper(b.clone(), rhs) {
-
ConcatState::One(x) => {
-
ConcatState::One(Self::from_two_children(a.clone(), x))
-
}
-
ConcatState::Two(x, y) => {
-
ConcatState::One(Self::from_three_children(a.clone(), x, y))
-
}
-
}
-
}
-
Dna::ThreeNode(node) => {
-
let (a, b, c) = &node.children;
-
match Self::concat_helper(c.clone(), rhs) {
-
ConcatState::One(x) => {
-
ConcatState::One(Self::from_three_children(a.clone(), b.clone(), x))
-
}
-
ConcatState::Two(x, y) => ConcatState::Two(
-
Self::from_two_children(a.clone(), b.clone()),
-
Self::from_two_children(x, y),
-
),
-
}
+
(a.clone() + b.clone() + x, y)
}
}
}
}
-
// Use Add trait instead
-
pub fn concat(lhs: DnaRef, rhs: DnaRef) -> Self {
-
match Self::concat_helper(lhs, rhs) {
-
ConcatState::One(a) => a,
-
ConcatState::Two(a, b) => Self::from_two_children(a, b),
-
}
-
}
-
pub fn iter<'a>(&'a self) -> DnaIterator<'a> {
let mut stack = Vec::new();
stack.push(self);
···
}
}
+
enum AddState {
+
One(DnaRef),
+
Two(DnaRef, DnaRef),
+
}
+
+
fn add_helper(lhs: DnaRef, rhs: DnaRef) -> AddState {
+
if lhs.depth() == rhs.depth() {
+
AddState::Two(lhs, rhs)
+
} else if lhs.depth() < rhs.depth() {
+
match &*rhs {
+
Dna::Empty => unreachable!(),
+
Dna::Leaf(_) => unreachable!(),
+
Dna::TwoNode(node) => {
+
let (a, b) = &node.children;
+
match add_helper(lhs, a.clone()) {
+
AddState::One(x) => {
+
AddState::One(DnaRef::from_two_children(x, b.clone()))
+
}
+
AddState::Two(x, y) => {
+
AddState::One(DnaRef::from_three_children(x, y, b.clone()))
+
}
+
}
+
}
+
Dna::ThreeNode(node) => {
+
let (a, b, c) = &node.children;
+
match add_helper(lhs, a.clone()) {
+
AddState::One(x) => {
+
AddState::One(DnaRef::from_three_children(x, b.clone(), c.clone()))
+
}
+
AddState::Two(x, y) => AddState::Two(
+
DnaRef::from_two_children(x, y),
+
DnaRef::from_two_children(b.clone(), c.clone()),
+
),
+
}
+
}
+
}
+
} else {
+
match &*lhs {
+
Dna::Empty => unreachable!(),
+
Dna::Leaf(_) => unreachable!(),
+
Dna::TwoNode(node) => {
+
let (a, b) = &node.children;
+
match add_helper(b.clone(), rhs) {
+
AddState::One(x) => {
+
AddState::One(DnaRef::from_two_children(a.clone(), x))
+
}
+
AddState::Two(x, y) => {
+
AddState::One(DnaRef::from_three_children(a.clone(), x, y))
+
}
+
}
+
}
+
Dna::ThreeNode(node) => {
+
let (a, b, c) = &node.children;
+
match add_helper(c.clone(), rhs) {
+
AddState::One(x) => {
+
AddState::One(DnaRef::from_three_children(a.clone(), b.clone(), x))
+
}
+
AddState::Two(x, y) => AddState::Two(
+
DnaRef::from_two_children(a.clone(), b.clone()),
+
DnaRef::from_two_children(x, y),
+
),
+
}
+
}
+
}
+
}
+
}
+
+
impl Add for DnaRef {
+
type Output = Self;
+
+
fn add(self, other: Self) -> Self {
+
match add_helper(self, other) {
+
AddState::One(a) => a,
+
AddState::Two(a, b) => Self::from_two_children(a, b),
+
}
+
}
+
}
+
#[cfg(test)]
mod tests {
use super::*;
···
let lhs = DnaRef::from_string("ABCD");
let rhs = DnaRef::from_string("WXYZ");
assert_eq!(
-
DnaRef::concat(lhs, rhs).iter().collect::<String>(),
+
(lhs + rhs).iter().collect::<String>(),
"ABCDWXYZ"
);
}