This commit changes the ToStr trait to: impl<T: fmt::Show> ToStr for T { fn to_str(&self) -> ~str { format!("{}", *self) } } The ToStr trait has been on the chopping block for quite awhile now, and this is the final nail in its coffin. The trait and the corresponding method are not being removed as part of this commit, but rather any implementations of the `ToStr` trait are being forbidden because of the generic impl. The new way to get the `to_str()` method to work is to implement `fmt::Show`. Formatting into a `&mut Writer` (as `format!` does) is much more efficient than `ToStr` when building up large strings. The `ToStr` trait forces many intermediate allocations to be made while the `fmt::Show` trait allows incremental buildup in the same heap allocated buffer. Additionally, the `fmt::Show` trait is much more extensible in terms of interoperation with other `Writer` instances and in more situations. By design the `ToStr` trait requires at least one allocation whereas the `fmt::Show` trait does not require any allocations. Closes #8242 Closes #9806
295 lines
7.2 KiB
Rust
295 lines
7.2 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.
|
|
|
|
//! A structure for holding a set of enum variants
|
|
//!
|
|
//! This module defines a container which uses an efficient bit mask
|
|
//! representation to hold C-like enum variants.
|
|
|
|
use std::num::Bitwise;
|
|
|
|
#[deriving(Clone, Eq, Hash, Show, Encodable, Decodable)]
|
|
/// 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) -> Items<E> {
|
|
Items::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 Items<E> {
|
|
priv index: uint,
|
|
priv bits: uint,
|
|
}
|
|
|
|
impl<E:CLike> Items<E> {
|
|
fn new(bits: uint) -> Items<E> {
|
|
Items { index: 0, bits: bits }
|
|
}
|
|
}
|
|
|
|
impl<E:CLike> Iterator<E> for Items<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.count_ones();
|
|
(exact, Some(exact))
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
|
|
use std::cast;
|
|
|
|
use enum_set::{EnumSet, CLike};
|
|
|
|
#[deriving(Eq)]
|
|
#[repr(uint)]
|
|
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)
|
|
}
|
|
}
|