+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::iterator::Iterator;
+
+#[deriving(Clone, Eq, IterBytes, ToStr)]
+/// A specialized Set implementation to use enum types.
+pub struct EnumSet<E> {
+ // We must maintain the invariant that no bits are set
+ // for which no variant exists
+ priv bits: uint
+}
+
+/// An iterface for casting C-like enum to uint and back.
+pub trait CLike {
+ /// Converts C-like enum to uint.
+ pub fn to_uint(&self) -> uint;
+ /// Converts uint to C-like enum.
+ pub fn from_uint(uint) -> Self;
+}
+
+fn bit<E:CLike>(e: E) -> uint {
+ 1 << e.to_uint()
+}
+
+impl<E:CLike> EnumSet<E> {
+ /// Returns an empty EnumSet.
+ pub fn empty() -> EnumSet<E> {
+ EnumSet {bits: 0}
+ }
+
+ /// Returns true if an EnumSet is empty.
+ pub fn is_empty(&self) -> bool {
+ self.bits == 0
+ }
+
+ /// Returns true if an EnumSet contains any enum of a given EnumSet
+ pub fn intersects(&self, e: EnumSet<E>) -> bool {
+ (self.bits & e.bits) != 0
+ }
+
+ /// Returns an intersection of both EnumSets.
+ pub fn intersection(&self, e: EnumSet<E>) -> EnumSet<E> {
+ EnumSet {bits: self.bits & e.bits}
+ }
+
+ /// Returns true if a given EnumSet is included in an EnumSet.
+ pub fn contains(&self, e: EnumSet<E>) -> bool {
+ (self.bits & e.bits) == e.bits
+ }
+
+ /// Returns a union of both EnumSets.
+ pub fn union(&self, e: EnumSet<E>) -> EnumSet<E> {
+ EnumSet {bits: self.bits | e.bits}
+ }
+
+ /// Add an enum to an EnumSet
+ pub fn add(&mut self, e: E) {
+ self.bits |= bit(e);
+ }
+
+ /// Returns true if an EnumSet contains a given enum
+ pub fn contains_elem(&self, e: E) -> bool {
+ (self.bits & bit(e)) != 0
+ }
+
+ /// Returns an iterator over an EnumSet
+ pub fn iter(&self) -> EnumSetIterator<E> {
+ EnumSetIterator::new(self.bits)
+ }
+}
+
+impl<E:CLike> Sub<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
+ fn sub(&self, e: &EnumSet<E>) -> EnumSet<E> {
+ EnumSet {bits: self.bits & !e.bits}
+ }
+}
+
+impl<E:CLike> BitOr<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
+ fn bitor(&self, e: &EnumSet<E>) -> EnumSet<E> {
+ EnumSet {bits: self.bits | e.bits}
+ }
+}
+
+impl<E:CLike> BitAnd<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
+ fn bitand(&self, e: &EnumSet<E>) -> EnumSet<E> {
+ EnumSet {bits: self.bits & e.bits}
+ }
+}
+
+/// An iterator over an EnumSet
+pub struct EnumSetIterator<E> {
+ priv index: uint,
+ priv bits: uint,
+}
+
+impl<E:CLike> EnumSetIterator<E> {
+ fn new(bits: uint) -> EnumSetIterator<E> {
+ EnumSetIterator { index: 0, bits: bits }
+ }
+}
+
+impl<E:CLike> Iterator<E> for EnumSetIterator<E> {
+ fn next(&mut self) -> Option<E> {
+ if (self.bits == 0) {
+ return None;
+ }
+
+ while (self.bits & 1) == 0 {
+ self.index += 1;
+ self.bits >>= 1;
+ }
+ let elem = CLike::from_uint(self.index);
+ self.index += 1;
+ self.bits >>= 1;
+ Some(elem)
+ }
+
+ fn size_hint(&self) -> (uint, Option<uint>) {
+ let exact = self.bits.population_count();
+ (exact, Some(exact))
+ }
+}
+
+#[cfg(test)]
+mod test {
+
+ use std::cast;
+
+ use enum_set::*;
+
+ #[deriving(Eq)]
+ enum Foo {
+ A, B, C
+ }
+
+ impl CLike for Foo {
+ pub fn to_uint(&self) -> uint {
+ *self as uint
+ }
+
+ pub fn from_uint(v: uint) -> Foo {
+ unsafe { cast::transmute(v) }
+ }
+ }
+
+ #[test]
+ fn test_empty() {
+ let e: EnumSet<Foo> = EnumSet::empty();
+ assert!(e.is_empty());
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // intersect
+
+ #[test]
+ fn test_two_empties_do_not_intersect() {
+ let e1: EnumSet<Foo> = EnumSet::empty();
+ let e2: EnumSet<Foo> = EnumSet::empty();
+ assert!(!e1.intersects(e2));
+ }
+
+ #[test]
+ fn test_empty_does_not_intersect_with_full() {
+ let e1: EnumSet<Foo> = EnumSet::empty();
+
+ let mut e2: EnumSet<Foo> = EnumSet::empty();
+ e2.add(A);
+ e2.add(B);
+ e2.add(C);
+
+ assert!(!e1.intersects(e2));
+ }
+
+ #[test]
+ fn test_disjoint_intersects() {
+ let mut e1: EnumSet<Foo> = EnumSet::empty();
+ e1.add(A);
+
+ let mut e2: EnumSet<Foo> = EnumSet::empty();
+ e2.add(B);
+
+ assert!(!e1.intersects(e2));
+ }
+
+ #[test]
+ fn test_overlapping_intersects() {
+ let mut e1: EnumSet<Foo> = EnumSet::empty();
+ e1.add(A);
+
+ let mut e2: EnumSet<Foo> = EnumSet::empty();
+ e2.add(A);
+ e2.add(B);
+
+ assert!(e1.intersects(e2));
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // contains and contains_elem
+
+ #[test]
+ fn test_contains() {
+ let mut e1: EnumSet<Foo> = EnumSet::empty();
+ e1.add(A);
+
+ let mut e2: EnumSet<Foo> = EnumSet::empty();
+ e2.add(A);
+ e2.add(B);
+
+ assert!(!e1.contains(e2));
+ assert!(e2.contains(e1));
+ }
+
+ #[test]
+ fn test_contains_elem() {
+ let mut e1: EnumSet<Foo> = EnumSet::empty();
+ e1.add(A);
+ assert!(e1.contains_elem(A));
+ assert!(!e1.contains_elem(B));
+ assert!(!e1.contains_elem(C));
+
+ e1.add(A);
+ e1.add(B);
+ assert!(e1.contains_elem(A));
+ assert!(e1.contains_elem(B));
+ assert!(!e1.contains_elem(C));
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // iter
+
+ #[test]
+ fn test_iterator() {
+ let mut e1: EnumSet<Foo> = EnumSet::empty();
+
+ let elems: ~[Foo] = e1.iter().collect();
+ assert_eq!(~[], elems)
+
+ e1.add(A);
+ let elems: ~[Foo] = e1.iter().collect();
+ assert_eq!(~[A], elems)
+
+ e1.add(C);
+ let elems: ~[Foo] = e1.iter().collect();
+ assert_eq!(~[A,C], elems)
+
+ e1.add(C);
+ let elems: ~[Foo] = e1.iter().collect();
+ assert_eq!(~[A,C], elems)
+
+ e1.add(B);
+ let elems: ~[Foo] = e1.iter().collect();
+ assert_eq!(~[A,B,C], elems)
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // operators
+
+ #[test]
+ fn test_operators() {
+ let mut e1: EnumSet<Foo> = EnumSet::empty();
+ e1.add(A);
+ e1.add(C);
+
+ let mut e2: EnumSet<Foo> = EnumSet::empty();
+ e2.add(B);
+ e2.add(C);
+
+ let e_union = e1 | e2;
+ let elems: ~[Foo] = e_union.iter().collect();
+ assert_eq!(~[A,B,C], elems)
+
+ let e_intersection = e1 & e2;
+ let elems: ~[Foo] = e_intersection.iter().collect();
+ assert_eq!(~[C], elems)
+
+ let e_subtract = e1 - e2;
+ let elems: ~[Foo] = e_subtract.iter().collect();
+ assert_eq!(~[A], elems)
+ }
+}