diff --git a/config.json b/config.json index 49888fed4..6bdf3f9fb 100644 --- a/config.json +++ b/config.json @@ -14,7 +14,8 @@ "bob", "grade-school", "phone-number", - "beer-song" + "beer-song", + "custom-set" ], "deprecated": [ diff --git a/custom-set/custom-set_test.rs b/custom-set/custom-set_test.rs new file mode 100644 index 000000000..51a5f2d1a --- /dev/null +++ b/custom-set/custom-set_test.rs @@ -0,0 +1,201 @@ +#![crate_name = "custom-set_test"] +#![crate_type = "lib"] + +use std::collections::{Collection, Set, MutableSet}; + +mod set; + +fn make_set(vec: Vec) -> set::CustomSet { + vec.into_iter().collect() +} + +#[test] +#[ignore] +fn test_empty_set() { + let set = set::CustomSet::<()>::new(); + assert_eq!(set.len(), 0); + assert_eq!(set.is_empty(), true); +} + +#[test] +#[ignore] +fn test_from_iter() { + let set = make_set(vec!(1, 2, 3, 2)); + assert_eq!(set.len(), 3); + assert!(!set.is_empty()); + assert!(set.contains(&1)); + assert!(set.contains(&3)); + assert!(!set.contains(&4)); +} + +#[test] +#[ignore] +fn test_is_disjoint() { + assert!(make_set(vec!()).is_disjoint(&make_set(vec!()))); + assert!(make_set(vec!(1)).is_disjoint(&make_set(vec!()))); + assert!(make_set(vec!()).is_disjoint(&make_set(vec!(1)))); + assert!(make_set(vec!(1, 2)).is_disjoint(&make_set(vec!(3, 4)))); + assert!(!make_set(vec!(1, 2)).is_disjoint(&make_set(vec!(2, 4)))); +} + +#[test] +#[ignore] +fn test_is_subset() { + // Technically improper subset + assert!(make_set(vec!()).is_subset(&make_set(vec!()))); + assert!(!make_set(vec!(1)).is_subset(&make_set(vec!()))); + assert!(make_set(vec!()).is_subset(&make_set(vec!(1)))); + assert!(!make_set(vec!(1, 2)).is_subset(&make_set(vec!(3, 4)))); + assert!(!make_set(vec!(1, 2)).is_subset(&make_set(vec!(2, 4)))); + assert!(make_set(vec!(1, 2)).is_subset(&make_set(vec!(1, 2, 4)))); +} + +#[test] +#[ignore] +fn test_is_superset() { + assert!(make_set(vec!()).is_superset(&make_set(vec!()))); + assert!(make_set(vec!(1)).is_superset(&make_set(vec!()))); + assert!(!make_set(vec!()).is_superset(&make_set(vec!(1)))); + assert!(!make_set(vec!(1, 2)).is_superset(&make_set(vec!(3, 4)))); + assert!(!make_set(vec!(1, 2)).is_superset(&make_set(vec!(2, 4)))); + assert!(!make_set(vec!(1, 2)).is_superset(&make_set(vec!(1, 2, 4)))); + assert!(make_set(vec!(1, 2, 3)).is_superset(&make_set(vec!(1, 2)))); +} + +fn difference(a: Vec, b: Vec) -> Vec { + let mut v = make_set(a).difference(&make_set(b)).map(|n| n.clone()).collect::>(); + v.sort(); + v +} + +#[test] +#[ignore] +fn test_difference() { + assert_eq!(difference(vec!(), vec!()), vec!()); + assert_eq!(difference(vec!(), vec!(3, 2, 5)), vec!()); + assert_eq!(difference(vec!(1, 2, 3, 4), vec!()), vec!(1, 2, 3, 4)); + assert_eq!(difference(vec!(1, 2, 3, 4), vec!(3, 2, 5)), vec!(1, 4)); +} + +fn intersection(a: Vec, b: Vec) -> Vec { + let mut v = make_set(a).intersection(&make_set(b)).map(|n| n.clone()).collect::>(); + v.sort(); + v +} + +#[test] +#[ignore] +fn test_intersection() { + assert_eq!(intersection(vec!(), vec!()), vec!()); + assert_eq!(intersection(vec!(), vec!(3, 2, 5)), vec!()); + assert_eq!(intersection(vec!(1, 2, 3, 4), vec!()), vec!()); + assert_eq!(intersection(vec!(1, 2, 3, 4), vec!(3, 2, 5)), vec!(2, 3)); +} + +fn union(a: Vec, b: Vec) -> Vec { + let mut v = make_set(a).union(&make_set(b)).map(|n| n.clone()).collect::>(); + v.sort(); + v +} + +#[test] +#[ignore] +fn test_union() { + assert_eq!(union(vec!(), vec!()), vec!()); + assert_eq!(union(vec!(), vec!(3, 2, 5)), vec!(2, 3, 5)); + assert_eq!(union(vec!(1, 2, 3, 4), vec!()), vec!(1, 2, 3, 4)); + assert_eq!(union(vec!(1, 2, 3, 4), vec!(3, 2, 5)), vec!(1, 2, 3, 4, 5)); +} + +#[test] +#[ignore] +fn test_insert() { + let mut set = make_set(vec!(1, 2, 3)); + assert!(set.contains(&2)); + assert!(!set.insert(2)); + assert!(set.contains(&2)); + assert!(!set.contains(&4)); + assert!(set.insert(4)); + assert!(set.contains(&4)); +} + +// Equality on this is modulo 3. +#[deriving(Eq, Show)] +struct Modulo3(uint); + +impl PartialEq for Modulo3 { + fn eq(&self, other: &Modulo3) -> bool { + let &Modulo3(ref a) = self; + let &Modulo3(ref b) = other; + a % 3 == b % 3 + } +} + +impl PartialOrd for Modulo3 { + fn partial_cmp(&self, other: &Modulo3) -> Option { + let &Modulo3(ref a) = self; + let &Modulo3(ref b) = other; + (a % 3).partial_cmp(&(b % 3)) + } +} + +impl Ord for Modulo3 { + fn cmp(&self, other: &Modulo3) -> Ordering { + let &Modulo3(ref a) = self; + let &Modulo3(ref b) = other; + (a % 3).cmp(&(b % 3)) + } +} + +#[test] +#[ignore] +fn test_insert_no_double() { + // This test abuses the ord and eq mechanisms a bit to check that a set doesn't replace + // existing elements with new elements, which could lead to interesting bugs if the programmer + // triggers that behaviour. + let mut set = vec!(Modulo3(1)).into_iter().collect::>(); + assert!(set.contains(&Modulo3(1))); + assert!(set.contains(&Modulo3(4))); + assert!(set.insert(Modulo3(2))); + assert!(set.contains(&Modulo3(5))); + assert!(!set.insert(Modulo3(8))); + let mut v = set.iter().collect::>(); + v.sort(); + let &Modulo3(ref v0) = v[0]; + let &Modulo3(ref v1) = v[1]; + assert_eq!(v0, &1); + assert_eq!(v1, &2); +} + +#[test] +#[ignore] +fn test_remove() { + let mut set = make_set(vec!(1, 2, 3)); + assert!(set.contains(&2)); + assert!(set.remove(&2)); + assert!(!set.contains(&2)); + assert!(!set.remove(&4)); + assert!(!set.contains(&4)); +} + +#[test] +#[ignore] +fn test_clear() { + let mut set = make_set(vec!(1, 2, 3)); + assert!(set.contains(&2)); + assert_eq!(set.len(), 3); + assert!(!set.is_empty()); + set.clear(); + assert!(!set.contains(&2)); + assert_eq!(set.len(), 0); + assert!(set.is_empty()); +} + +#[test] +#[ignore] +fn test_traits() { + let s: set::CustomSet<()> = set::CustomSet::<()>::new(); + let _ = &s as &Collection; + let _ = &s as &Set<()>; + let _ = &s as &MutableSet<()>; +} diff --git a/custom-set/example.rs b/custom-set/example.rs new file mode 100644 index 000000000..766e4cbb2 --- /dev/null +++ b/custom-set/example.rs @@ -0,0 +1,268 @@ +use std::collections::{Collection, Set, MutableSet}; +use std::slice; + +#[deriving(Show)] +pub struct CustomSet(Vec); + +/// Create an empty set. +impl CustomSet { + pub fn new() -> CustomSet { + CustomSet(vec!()) + } + + pub fn iter(&self) -> Items { + let &CustomSet(ref v) = self; + Items(v.iter()) + } +} + +pub struct Items<'a, T: 'a>(slice::Items<'a, T>); + +impl<'a, T> Iterator<&'a T> for Items<'a, T> { + fn next(&mut self) -> Option<&'a T> { + let &Items(ref mut iter) = self; + iter.next() + } +} + +impl CustomSet { + fn find_index(&self, value: &T) -> Option { + let &CustomSet(ref v) = self; + for (idx, x) in v.iter().enumerate() { + if x == value { + return Some(idx) + } + } + return None + } +} + +impl CustomSet { + /// Visit the values representing the difference, in ascending order. + /// + /// The difference between set A and set B is all the items in set A that are not in set B. + pub fn difference<'a>(&'a self, other: &'a CustomSet) -> DifferenceItems { + DifferenceItems(box self + .diff_iter(other) + .filter(|&(_, diff)| diff == OnlyA) + .map(|(v, _)| v)) + } + + /// Visit the values representing the intersection, in ascending order. + /// + /// The intersection of set A and set B is all the items in set A that are also in set B. + pub fn intersection<'a>(&'a self, other: &'a CustomSet) -> IntersectionItems { + IntersectionItems(box self + .diff_iter(other) + .filter(|&(_, diff)| diff == Both) + .map(|(v, _)| v)) + } + + /// Visit the values representing the union, in ascending order. + /// + /// The union of set A and set B is all the items in both sets (with doubles removed). + pub fn union<'a>(&'a self, other: &'a CustomSet) -> UnionItems { + UnionItems(box self.diff_iter(other).map(|(v, _)| v)) + } + + fn diff_iter<'a>(&'a self, other: &'a CustomSet) -> DiffIter { + let &CustomSet(ref self_v) = self; + let &CustomSet(ref other_v) = other; + DiffIter { a: CachingWrapper::wrap(self_v.iter()), + b: CachingWrapper::wrap(other_v.iter()) } + } +} + +// Those boxes are used just to avoid having to specify a complex Map<..., Filter<..., DiffIter>> +// nested iterator type. +pub struct DifferenceItems<'a, T>(Box + 'a>); +pub struct IntersectionItems<'a, T>(Box + 'a>); +pub struct UnionItems<'a, T>(Box + 'a>); + +impl<'a, T> Iterator<&'a T> for DifferenceItems<'a, T> { + fn next(&mut self) -> Option<&'a T> { + let &DifferenceItems(ref mut iter) = self; + iter.next() + } +} + +impl<'a, T> Iterator<&'a T> for IntersectionItems<'a, T> { + fn next(&mut self) -> Option<&'a T> { + let &IntersectionItems(ref mut iter) = self; + iter.next() + } +} + +impl<'a, T> Iterator<&'a T> for UnionItems<'a, T> { + fn next(&mut self) -> Option<&'a T> { + let &UnionItems(ref mut iter) = self; + iter.next() + } +} + +impl Collection for CustomSet { + fn len(&self) -> uint { + let &CustomSet(ref v) = self; + v.len() + } + + fn is_empty(&self) -> bool { + let &CustomSet(ref v) = self; + v.is_empty() + } +} + +impl Set for CustomSet { + fn contains(&self, value: &T) -> bool { + self.find_index(value).is_some() + } + + fn is_disjoint(&self, other: &CustomSet) -> bool { + // Traverse the ordered vectors, the big benefit of this over unordered vectors (which + // would make the add method O(1) is that this method is O(n+m) where it would otherwise be + // O(n*m). Not that for the chosen representation performance is actually anywhere near + // decent, the standard lib sets are much much better. + let mut diff_iter = self.diff_iter(other); + for (_, diff) in diff_iter { + match diff { + Both => return false, + _ => {} + } + } + true + } + + fn is_subset(&self, other: &CustomSet) -> bool { + let mut diff_iter = self.diff_iter(other); + for (_, diff) in diff_iter { + match diff { + OnlyA => return false, + _ => {} + } + } + true + } +} + +impl Mutable for CustomSet { + fn clear(&mut self) { + let &CustomSet(ref mut v) = self; + v.clear(); + } +} + +enum InsertPos { + Begin, + Before(uint), + End, +} + +fn find_insert_pos(v: &Vec, value: &T) -> Option { + for (idx, x) in v.iter().enumerate() { + match value.cmp(x) { + Less if idx == 0 => return Some(Begin), + Less => return Some(Before(idx)), + Equal => return None, + Greater => () + } + } + Some(End) +} + +impl MutableSet for CustomSet { + fn insert(&mut self, value: T) -> bool { + let &CustomSet(ref mut v) = self; + match find_insert_pos(v, &value) { + None => false, + Some(Begin) => { v.insert(0, value); true }, + Some(Before(idx)) => { v.insert(idx-1, value); true }, + Some(End) => { v.push(value); true }, + } + } + + fn remove(&mut self, value: &T) -> bool { + let idx = match self.find_index(value) { + None => return false, + Some(idx) => idx + }; + let &CustomSet(ref mut v) = self; + v.remove(idx); + true + } +} + +impl FromIterator for CustomSet { + fn from_iter>(mut iterator: T) -> CustomSet { + let mut set: CustomSet = CustomSet::new(); + for v in iterator { + set.insert(v); + } + set + } +} + +// A wrapper around an iterator so that a single element can be viewed multiple times. +struct CachingWrapper<'a, T: 'a> { + iter: slice::Items<'a, T>, + cache: Option<&'a T>, +} + +impl<'a, T> CachingWrapper<'a, T> { + fn wrap(iter: slice::Items<'a, T>) -> CachingWrapper<'a, T> { + let mut wrapper = CachingWrapper { iter: iter, cache: None }; + wrapper.advance(); + wrapper + } + fn current(&self) -> Option<&'a T> { + self.cache + } + fn advance(&mut self) { + self.cache = self.iter.next(); + } +} + +#[deriving(PartialEq, Eq)] +enum Diff { + OnlyA, + OnlyB, + Both +} + +// Iterator for the differences between two ordered vectors. +struct DiffIter<'a, T: 'a> { + a: CachingWrapper<'a, T>, + b: CachingWrapper<'a, T>, +} + +impl<'a, T: Ord> Iterator<(&'a T, Diff)> for DiffIter<'a, T> { + fn next(&mut self) -> Option<(&'a T, Diff)> { + match (self.a.current(), self.b.current()) { + (None, None) => None, + (Some(a_val), None) => { + self.a.advance(); + Some((a_val, OnlyA)) + }, + (None, Some(b_val)) => { + self.b.advance(); + Some((b_val, OnlyB)) + }, + (Some(a_val), Some(b_val)) => { + match (*a_val).cmp(b_val) { + Less => { + self.a.advance(); + Some((a_val, OnlyA)) + } + Equal => { + self.a.advance(); + self.b.advance(); + Some((a_val, Both)) + } + Greater => { + self.b.advance(); + Some((b_val, OnlyB)) + } + } + } + } + } +}