The trait will keep the `Iterator` naming, but a more concise module name makes using the free functions less verbose. The module will define iterables in addition to iterators, as it deals with iteration in general.
287 lines
7.0 KiB
Rust
287 lines
7.0 KiB
Rust
// 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.
|
|
|
|
#[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 interface for casting C-like enum to uint and back.
|
|
pub trait CLike {
|
|
/// Converts C-like enum to uint.
|
|
fn to_uint(&self) -> uint;
|
|
/// Converts uint to C-like enum.
|
|
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 {
|
|
fn to_uint(&self) -> uint {
|
|
*self as uint
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|