2013-05-07 16:30:21 -05:00
|
|
|
// 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.
|
|
|
|
|
2014-08-04 05:48:39 -05:00
|
|
|
//! A structure for holding a set of enum variants.
|
2013-10-12 21:02:46 -05:00
|
|
|
//!
|
|
|
|
//! This module defines a container which uses an efficient bit mask
|
|
|
|
//! representation to hold C-like enum variants.
|
|
|
|
|
std: Recreate a `collections` module
As with the previous commit with `librand`, this commit shuffles around some
`collections` code. The new state of the world is similar to that of librand:
* The libcollections crate now only depends on libcore and liballoc.
* The standard library has a new module, `std::collections`. All functionality
of libcollections is reexported through this module.
I would like to stress that this change is purely cosmetic. There are very few
alterations to these primitives.
There are a number of notable points about the new organization:
* std::{str, slice, string, vec} all moved to libcollections. There is no reason
that these primitives shouldn't be necessarily usable in a freestanding
context that has allocation. These are all reexported in their usual places in
the standard library.
* The `hashmap`, and transitively the `lru_cache`, modules no longer reside in
`libcollections`, but rather in libstd. The reason for this is because the
`HashMap::new` contructor requires access to the OSRng for initially seeding
the hash map. Beyond this requirement, there is no reason that the hashmap
could not move to libcollections.
I do, however, have a plan to move the hash map to the collections module. The
`HashMap::new` function could be altered to require that the `H` hasher
parameter ascribe to the `Default` trait, allowing the entire `hashmap` module
to live in libcollections. The key idea would be that the default hasher would
be different in libstd. Something along the lines of:
// src/libstd/collections/mod.rs
pub type HashMap<K, V, H = RandomizedSipHasher> =
core_collections::HashMap<K, V, H>;
This is not possible today because you cannot invoke static methods through
type aliases. If we modified the compiler, however, to allow invocation of
static methods through type aliases, then this type definition would
essentially be switching the default hasher from `SipHasher` in libcollections
to a libstd-defined `RandomizedSipHasher` type. This type's `Default`
implementation would randomly seed the `SipHasher` instance, and otherwise
perform the same as `SipHasher`.
This future state doesn't seem incredibly far off, but until that time comes,
the hashmap module will live in libstd to not compromise on functionality.
* In preparation for the hashmap moving to libcollections, the `hash` module has
moved from libstd to libcollections. A previously snapshotted commit enables a
distinct `Writer` trait to live in the `hash` module which `Hash`
implementations are now parameterized over.
Due to using a custom trait, the `SipHasher` implementation has lost its
specialized methods for writing integers. These can be re-added
backwards-compatibly in the future via default methods if necessary, but the
FNV hashing should satisfy much of the need for speedier hashing.
A list of breaking changes:
* HashMap::{get, get_mut} no longer fails with the key formatted into the error
message with `{:?}`, instead, a generic message is printed. With backtraces,
it should still be not-too-hard to track down errors.
* The HashMap, HashSet, and LruCache types are now available through
std::collections instead of the collections crate.
* Manual implementations of hash should be parameterized over `hash::Writer`
instead of just `Writer`.
[breaking-change]
2014-05-29 20:50:12 -05:00
|
|
|
use core::prelude::*;
|
2014-09-13 19:37:03 -05:00
|
|
|
use core::fmt;
|
2014-11-09 23:26:10 -06:00
|
|
|
use core::num::Int;
|
std: Recreate a `collections` module
As with the previous commit with `librand`, this commit shuffles around some
`collections` code. The new state of the world is similar to that of librand:
* The libcollections crate now only depends on libcore and liballoc.
* The standard library has a new module, `std::collections`. All functionality
of libcollections is reexported through this module.
I would like to stress that this change is purely cosmetic. There are very few
alterations to these primitives.
There are a number of notable points about the new organization:
* std::{str, slice, string, vec} all moved to libcollections. There is no reason
that these primitives shouldn't be necessarily usable in a freestanding
context that has allocation. These are all reexported in their usual places in
the standard library.
* The `hashmap`, and transitively the `lru_cache`, modules no longer reside in
`libcollections`, but rather in libstd. The reason for this is because the
`HashMap::new` contructor requires access to the OSRng for initially seeding
the hash map. Beyond this requirement, there is no reason that the hashmap
could not move to libcollections.
I do, however, have a plan to move the hash map to the collections module. The
`HashMap::new` function could be altered to require that the `H` hasher
parameter ascribe to the `Default` trait, allowing the entire `hashmap` module
to live in libcollections. The key idea would be that the default hasher would
be different in libstd. Something along the lines of:
// src/libstd/collections/mod.rs
pub type HashMap<K, V, H = RandomizedSipHasher> =
core_collections::HashMap<K, V, H>;
This is not possible today because you cannot invoke static methods through
type aliases. If we modified the compiler, however, to allow invocation of
static methods through type aliases, then this type definition would
essentially be switching the default hasher from `SipHasher` in libcollections
to a libstd-defined `RandomizedSipHasher` type. This type's `Default`
implementation would randomly seed the `SipHasher` instance, and otherwise
perform the same as `SipHasher`.
This future state doesn't seem incredibly far off, but until that time comes,
the hashmap module will live in libstd to not compromise on functionality.
* In preparation for the hashmap moving to libcollections, the `hash` module has
moved from libstd to libcollections. A previously snapshotted commit enables a
distinct `Writer` trait to live in the `hash` module which `Hash`
implementations are now parameterized over.
Due to using a custom trait, the `SipHasher` implementation has lost its
specialized methods for writing integers. These can be re-added
backwards-compatibly in the future via default methods if necessary, but the
FNV hashing should satisfy much of the need for speedier hashing.
A list of breaking changes:
* HashMap::{get, get_mut} no longer fails with the key formatted into the error
message with `{:?}`, instead, a generic message is printed. With backtraces,
it should still be not-too-hard to track down errors.
* The HashMap, HashSet, and LruCache types are now available through
std::collections instead of the collections crate.
* Manual implementations of hash should be parameterized over `hash::Writer`
instead of just `Writer`.
[breaking-change]
2014-05-29 20:50:12 -05:00
|
|
|
|
2014-11-06 11:24:47 -06:00
|
|
|
// FIXME(contentions): implement union family of methods? (general design may be wrong here)
|
|
|
|
|
2014-09-27 15:47:53 -05:00
|
|
|
#[deriving(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
2014-12-09 16:05:16 -06:00
|
|
|
/// A specialized set implementation to use enum types.
|
2013-05-07 16:30:21 -05:00
|
|
|
pub struct EnumSet<E> {
|
2013-05-10 14:57:27 -05:00
|
|
|
// We must maintain the invariant that no bits are set
|
|
|
|
// for which no variant exists
|
2014-03-27 17:10:04 -05:00
|
|
|
bits: uint
|
2013-05-07 16:30:21 -05:00
|
|
|
}
|
|
|
|
|
librustc: Make `Copy` opt-in.
This change makes the compiler no longer infer whether types (structures
and enumerations) implement the `Copy` trait (and thus are implicitly
copyable). Rather, you must implement `Copy` yourself via `impl Copy for
MyType {}`.
A new warning has been added, `missing_copy_implementations`, to warn
you if a non-generic public type has been added that could have
implemented `Copy` but didn't.
For convenience, you may *temporarily* opt out of this behavior by using
`#![feature(opt_out_copy)]`. Note though that this feature gate will never be
accepted and will be removed by the time that 1.0 is released, so you should
transition your code away from using it.
This breaks code like:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
Change this code to:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
impl Copy for Point2D {}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
This is the backwards-incompatible part of #13231.
Part of RFC #3.
[breaking-change]
2014-12-05 19:01:33 -06:00
|
|
|
impl<E> Copy for EnumSet<E> {}
|
|
|
|
|
2014-09-13 19:37:03 -05:00
|
|
|
impl<E:CLike+fmt::Show> fmt::Show for EnumSet<E> {
|
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
try!(write!(fmt, "{{"));
|
|
|
|
let mut first = true;
|
|
|
|
for e in self.iter() {
|
|
|
|
if !first {
|
|
|
|
try!(write!(fmt, ", "));
|
|
|
|
}
|
|
|
|
try!(write!(fmt, "{}", e));
|
|
|
|
first = false;
|
|
|
|
}
|
|
|
|
write!(fmt, "}}")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-24 19:06:06 -06:00
|
|
|
/// An interface for casting C-like enum to uint and back.
|
|
|
|
/// A typically implementation is as below.
|
|
|
|
///
|
|
|
|
/// ```{rust,ignore}
|
|
|
|
/// #[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 { mem::transmute(v) }
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// ```
|
2013-05-07 16:30:21 -05:00
|
|
|
pub trait CLike {
|
2014-08-04 05:48:39 -05:00
|
|
|
/// Converts a C-like enum to a `uint`.
|
2013-08-09 03:25:24 -05:00
|
|
|
fn to_uint(&self) -> uint;
|
2014-08-04 05:48:39 -05:00
|
|
|
/// Converts a `uint` to a C-like enum.
|
2013-08-09 03:25:24 -05:00
|
|
|
fn from_uint(uint) -> Self;
|
2013-05-07 16:30:21 -05:00
|
|
|
}
|
|
|
|
|
2014-11-06 11:24:47 -06:00
|
|
|
fn bit<E:CLike>(e: &E) -> uint {
|
2014-11-06 17:20:36 -06:00
|
|
|
use core::uint;
|
2014-11-06 17:10:24 -06:00
|
|
|
let value = e.to_uint();
|
2014-11-06 17:20:36 -06:00
|
|
|
assert!(value < uint::BITS,
|
|
|
|
"EnumSet only supports up to {} variants.", uint::BITS - 1);
|
2014-11-06 17:10:24 -06:00
|
|
|
1 << value
|
2013-05-07 16:30:21 -05:00
|
|
|
}
|
|
|
|
|
2013-05-31 17:17:22 -05:00
|
|
|
impl<E:CLike> EnumSet<E> {
|
2014-11-06 11:24:47 -06:00
|
|
|
/// Deprecated: Renamed to `new`.
|
|
|
|
#[deprecated = "Renamed to `new`"]
|
2013-05-31 17:17:22 -05:00
|
|
|
pub fn empty() -> EnumSet<E> {
|
2014-11-06 11:24:47 -06:00
|
|
|
EnumSet::new()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns an empty `EnumSet`.
|
|
|
|
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
|
|
|
pub fn new() -> EnumSet<E> {
|
2013-05-07 16:30:21 -05:00
|
|
|
EnumSet {bits: 0}
|
|
|
|
}
|
|
|
|
|
2014-11-07 11:13:45 -06:00
|
|
|
/// Returns the number of elements in the given `EnumSet`.
|
|
|
|
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
|
|
|
pub fn len(&self) -> uint {
|
|
|
|
self.bits.count_ones()
|
|
|
|
}
|
|
|
|
|
2014-08-04 05:48:39 -05:00
|
|
|
/// Returns true if the `EnumSet` is empty.
|
2014-11-06 11:24:47 -06:00
|
|
|
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
2013-05-31 17:17:22 -05:00
|
|
|
pub fn is_empty(&self) -> bool {
|
2013-05-07 16:30:21 -05:00
|
|
|
self.bits == 0
|
|
|
|
}
|
|
|
|
|
2014-11-06 11:24:47 -06:00
|
|
|
pub fn clear(&mut self) {
|
|
|
|
self.bits = 0;
|
|
|
|
}
|
|
|
|
|
2014-08-04 05:48:39 -05:00
|
|
|
/// Returns `true` if the `EnumSet` contains any enum of the given `EnumSet`.
|
2014-11-06 11:24:47 -06:00
|
|
|
/// Deprecated: Use `is_disjoint`.
|
|
|
|
#[deprecated = "Use `is_disjoint`"]
|
2013-05-31 17:17:22 -05:00
|
|
|
pub fn intersects(&self, e: EnumSet<E>) -> bool {
|
2014-11-06 11:24:47 -06:00
|
|
|
!self.is_disjoint(&e)
|
2013-05-07 16:30:21 -05:00
|
|
|
}
|
|
|
|
|
2014-11-06 11:24:47 -06:00
|
|
|
/// Returns `false` if the `EnumSet` contains any enum of the given `EnumSet`.
|
|
|
|
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
|
|
|
pub fn is_disjoint(&self, other: &EnumSet<E>) -> bool {
|
|
|
|
(self.bits & other.bits) == 0
|
2013-05-10 14:57:27 -05:00
|
|
|
}
|
|
|
|
|
2014-11-06 11:24:47 -06:00
|
|
|
/// Returns `true` if a given `EnumSet` is included in this `EnumSet`.
|
|
|
|
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
|
|
|
pub fn is_superset(&self, other: &EnumSet<E>) -> bool {
|
|
|
|
(self.bits & other.bits) == other.bits
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns `true` if this `EnumSet` is included in the given `EnumSet`.
|
|
|
|
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
|
|
|
pub fn is_subset(&self, other: &EnumSet<E>) -> bool {
|
2014-11-06 17:41:50 -06:00
|
|
|
other.is_superset(self)
|
2013-05-07 16:30:21 -05:00
|
|
|
}
|
|
|
|
|
2014-08-04 05:48:39 -05:00
|
|
|
/// Returns the union of both `EnumSets`.
|
2013-05-31 17:17:22 -05:00
|
|
|
pub fn union(&self, e: EnumSet<E>) -> EnumSet<E> {
|
2013-05-10 14:57:27 -05:00
|
|
|
EnumSet {bits: self.bits | e.bits}
|
|
|
|
}
|
|
|
|
|
2014-11-06 11:24:47 -06:00
|
|
|
/// Returns the intersection of both `EnumSets`.
|
|
|
|
pub fn intersection(&self, e: EnumSet<E>) -> EnumSet<E> {
|
|
|
|
EnumSet {bits: self.bits & e.bits}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Deprecated: Use `insert`.
|
|
|
|
#[deprecated = "Use `insert`"]
|
2013-05-31 17:17:22 -05:00
|
|
|
pub fn add(&mut self, e: E) {
|
2014-11-06 11:24:47 -06:00
|
|
|
self.insert(e);
|
2013-05-07 16:30:21 -05:00
|
|
|
}
|
|
|
|
|
2014-11-06 11:24:47 -06:00
|
|
|
/// Adds an enum to the `EnumSet`, and returns `true` if it wasn't there before
|
|
|
|
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
|
|
|
pub fn insert(&mut self, e: E) -> bool {
|
|
|
|
let result = !self.contains(&e);
|
|
|
|
self.bits |= bit(&e);
|
|
|
|
result
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Removes an enum from the EnumSet
|
|
|
|
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
|
|
|
pub fn remove(&mut self, e: &E) -> bool {
|
|
|
|
let result = self.contains(e);
|
|
|
|
self.bits &= !bit(e);
|
|
|
|
result
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Deprecated: use `contains`.
|
|
|
|
#[deprecated = "use `contains"]
|
2013-05-31 17:17:22 -05:00
|
|
|
pub fn contains_elem(&self, e: E) -> bool {
|
2014-11-06 11:24:47 -06:00
|
|
|
self.contains(&e)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns `true` if an `EnumSet` contains a given enum.
|
|
|
|
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
|
|
|
pub fn contains(&self, e: &E) -> bool {
|
2013-05-07 16:30:21 -05:00
|
|
|
(self.bits & bit(e)) != 0
|
|
|
|
}
|
|
|
|
|
2014-08-04 05:48:39 -05:00
|
|
|
/// Returns an iterator over an `EnumSet`.
|
2014-11-06 11:24:47 -06:00
|
|
|
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
2014-01-14 21:32:24 -06:00
|
|
|
pub fn iter(&self) -> Items<E> {
|
|
|
|
Items::new(self.bits)
|
2013-06-30 13:12:04 -05:00
|
|
|
}
|
2013-05-07 16:30:21 -05:00
|
|
|
}
|
|
|
|
|
2014-12-01 13:10:04 -06:00
|
|
|
// NOTE(stage0): Remove impl after a snapshot
|
|
|
|
#[cfg(stage0)]
|
2013-05-12 19:34:15 -05:00
|
|
|
impl<E:CLike> Sub<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
|
2013-05-07 16:30:21 -05:00
|
|
|
fn sub(&self, e: &EnumSet<E>) -> EnumSet<E> {
|
|
|
|
EnumSet {bits: self.bits & !e.bits}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-01 13:10:04 -06:00
|
|
|
#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot
|
|
|
|
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}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE(stage0): Remove impl after a snapshot
|
|
|
|
#[cfg(stage0)]
|
2013-05-12 19:34:15 -05:00
|
|
|
impl<E:CLike> BitOr<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
|
2013-05-07 16:30:21 -05:00
|
|
|
fn bitor(&self, e: &EnumSet<E>) -> EnumSet<E> {
|
|
|
|
EnumSet {bits: self.bits | e.bits}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-01 13:10:04 -06:00
|
|
|
#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot
|
|
|
|
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}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE(stage0): Remove impl after a snapshot
|
|
|
|
#[cfg(stage0)]
|
2013-05-12 19:34:15 -05:00
|
|
|
impl<E:CLike> BitAnd<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
|
2013-05-07 16:30:21 -05:00
|
|
|
fn bitand(&self, e: &EnumSet<E>) -> EnumSet<E> {
|
|
|
|
EnumSet {bits: self.bits & e.bits}
|
|
|
|
}
|
|
|
|
}
|
2013-05-08 14:10:26 -05:00
|
|
|
|
2014-12-01 13:10:04 -06:00
|
|
|
#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot
|
|
|
|
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}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE(stage0): Remove impl after a snapshot
|
|
|
|
#[cfg(stage0)]
|
2014-11-07 16:51:38 -06:00
|
|
|
impl<E:CLike> BitXor<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
|
|
|
|
fn bitxor(&self, e: &EnumSet<E>) -> EnumSet<E> {
|
|
|
|
EnumSet {bits: self.bits ^ e.bits}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-01 13:10:04 -06:00
|
|
|
#[cfg(not(stage0))] // NOTE(stage0): Remove cfg after a snapshot
|
|
|
|
impl<E:CLike> BitXor<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
|
|
|
|
fn bitxor(self, e: EnumSet<E>) -> EnumSet<E> {
|
|
|
|
EnumSet {bits: self.bits ^ e.bits}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-25 23:53:29 -05:00
|
|
|
/// An iterator over an EnumSet
|
2014-01-14 21:32:24 -06:00
|
|
|
pub struct Items<E> {
|
2014-03-27 17:10:04 -05:00
|
|
|
index: uint,
|
|
|
|
bits: uint,
|
2013-06-30 13:12:04 -05:00
|
|
|
}
|
|
|
|
|
2014-01-14 21:32:24 -06:00
|
|
|
impl<E:CLike> Items<E> {
|
|
|
|
fn new(bits: uint) -> Items<E> {
|
|
|
|
Items { index: 0, bits: bits }
|
2013-06-30 13:12:04 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-14 21:32:24 -06:00
|
|
|
impl<E:CLike> Iterator<E> for Items<E> {
|
2013-06-30 13:12:04 -05:00
|
|
|
fn next(&mut self) -> Option<E> {
|
2014-01-19 02:21:14 -06:00
|
|
|
if self.bits == 0 {
|
2013-06-30 13:12:04 -05:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2013-07-02 20:40:46 -05:00
|
|
|
fn size_hint(&self) -> (uint, Option<uint>) {
|
2014-02-16 17:12:10 -06:00
|
|
|
let exact = self.bits.count_ones();
|
2013-07-02 20:40:46 -05:00
|
|
|
(exact, Some(exact))
|
2013-06-30 13:12:04 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-07 18:40:20 -06:00
|
|
|
impl<E:CLike> FromIterator<E> for EnumSet<E> {
|
|
|
|
fn from_iter<I:Iterator<E>>(iterator: I) -> EnumSet<E> {
|
|
|
|
let mut ret = EnumSet::new();
|
|
|
|
ret.extend(iterator);
|
|
|
|
ret
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<E:CLike> Extend<E> for EnumSet<E> {
|
|
|
|
fn extend<I: Iterator<E>>(&mut self, mut iterator: I) {
|
|
|
|
for element in iterator {
|
|
|
|
self.insert(element);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-08 14:10:26 -05:00
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
2014-05-29 21:03:06 -05:00
|
|
|
use std::prelude::*;
|
2014-11-06 02:05:53 -06:00
|
|
|
use self::Foo::*;
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 12:34:51 -05:00
|
|
|
use std::mem;
|
2013-05-22 21:59:22 -05:00
|
|
|
|
2014-10-30 20:25:08 -05:00
|
|
|
use super::{EnumSet, CLike};
|
2013-05-08 14:10:26 -05:00
|
|
|
|
2014-05-29 19:45:07 -05:00
|
|
|
#[deriving(PartialEq, Show)]
|
2013-09-25 11:41:10 -05:00
|
|
|
#[repr(uint)]
|
2013-05-08 14:10:26 -05:00
|
|
|
enum Foo {
|
|
|
|
A, B, C
|
|
|
|
}
|
|
|
|
|
librustc: Make `Copy` opt-in.
This change makes the compiler no longer infer whether types (structures
and enumerations) implement the `Copy` trait (and thus are implicitly
copyable). Rather, you must implement `Copy` yourself via `impl Copy for
MyType {}`.
A new warning has been added, `missing_copy_implementations`, to warn
you if a non-generic public type has been added that could have
implemented `Copy` but didn't.
For convenience, you may *temporarily* opt out of this behavior by using
`#![feature(opt_out_copy)]`. Note though that this feature gate will never be
accepted and will be removed by the time that 1.0 is released, so you should
transition your code away from using it.
This breaks code like:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
Change this code to:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
impl Copy for Point2D {}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
This is the backwards-incompatible part of #13231.
Part of RFC #3.
[breaking-change]
2014-12-05 19:01:33 -06:00
|
|
|
impl Copy for Foo {}
|
|
|
|
|
2013-05-08 14:10:26 -05:00
|
|
|
impl CLike for Foo {
|
2013-08-09 03:25:24 -05:00
|
|
|
fn to_uint(&self) -> uint {
|
2013-05-08 14:10:26 -05:00
|
|
|
*self as uint
|
|
|
|
}
|
|
|
|
|
2013-08-09 03:25:24 -05:00
|
|
|
fn from_uint(v: uint) -> Foo {
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 12:34:51 -05:00
|
|
|
unsafe { mem::transmute(v) }
|
2013-05-08 14:10:26 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2014-11-06 11:24:47 -06:00
|
|
|
fn test_new() {
|
|
|
|
let e: EnumSet<Foo> = EnumSet::new();
|
2013-05-08 14:10:26 -05:00
|
|
|
assert!(e.is_empty());
|
|
|
|
}
|
|
|
|
|
2014-09-13 19:37:03 -05:00
|
|
|
#[test]
|
|
|
|
fn test_show() {
|
2014-11-06 11:24:47 -06:00
|
|
|
let mut e = EnumSet::new();
|
2014-11-27 10:45:50 -06:00
|
|
|
assert_eq!("{}", e.to_string());
|
2014-11-06 11:24:47 -06:00
|
|
|
e.insert(A);
|
2014-11-27 10:45:50 -06:00
|
|
|
assert_eq!("{A}", e.to_string());
|
2014-11-06 11:24:47 -06:00
|
|
|
e.insert(C);
|
2014-11-27 10:45:50 -06:00
|
|
|
assert_eq!("{A, C}", e.to_string());
|
2014-09-13 19:37:03 -05:00
|
|
|
}
|
|
|
|
|
2014-11-07 11:13:45 -06:00
|
|
|
#[test]
|
|
|
|
fn test_len() {
|
|
|
|
let mut e = EnumSet::new();
|
|
|
|
assert_eq!(e.len(), 0);
|
|
|
|
e.insert(A);
|
|
|
|
e.insert(B);
|
|
|
|
e.insert(C);
|
|
|
|
assert_eq!(e.len(), 3);
|
|
|
|
e.remove(&A);
|
|
|
|
assert_eq!(e.len(), 2);
|
|
|
|
e.clear();
|
|
|
|
assert_eq!(e.len(), 0);
|
|
|
|
}
|
|
|
|
|
2013-05-08 14:10:26 -05:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// intersect
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_two_empties_do_not_intersect() {
|
2014-11-06 11:24:47 -06:00
|
|
|
let e1: EnumSet<Foo> = EnumSet::new();
|
|
|
|
let e2: EnumSet<Foo> = EnumSet::new();
|
|
|
|
assert!(e1.is_disjoint(&e2));
|
2013-05-08 14:10:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_empty_does_not_intersect_with_full() {
|
2014-11-06 11:24:47 -06:00
|
|
|
let e1: EnumSet<Foo> = EnumSet::new();
|
2013-05-08 14:10:26 -05:00
|
|
|
|
2014-11-06 11:24:47 -06:00
|
|
|
let mut e2: EnumSet<Foo> = EnumSet::new();
|
|
|
|
e2.insert(A);
|
|
|
|
e2.insert(B);
|
|
|
|
e2.insert(C);
|
2013-05-08 14:10:26 -05:00
|
|
|
|
2014-11-06 11:24:47 -06:00
|
|
|
assert!(e1.is_disjoint(&e2));
|
2013-05-08 14:10:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_disjoint_intersects() {
|
2014-11-06 11:24:47 -06:00
|
|
|
let mut e1: EnumSet<Foo> = EnumSet::new();
|
|
|
|
e1.insert(A);
|
2013-05-08 14:10:26 -05:00
|
|
|
|
2014-11-06 11:24:47 -06:00
|
|
|
let mut e2: EnumSet<Foo> = EnumSet::new();
|
|
|
|
e2.insert(B);
|
2013-05-08 14:10:26 -05:00
|
|
|
|
2014-11-06 11:24:47 -06:00
|
|
|
assert!(e1.is_disjoint(&e2));
|
2013-05-08 14:10:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_overlapping_intersects() {
|
2014-11-06 11:24:47 -06:00
|
|
|
let mut e1: EnumSet<Foo> = EnumSet::new();
|
|
|
|
e1.insert(A);
|
2013-05-08 14:10:26 -05:00
|
|
|
|
2014-11-06 11:24:47 -06:00
|
|
|
let mut e2: EnumSet<Foo> = EnumSet::new();
|
|
|
|
e2.insert(A);
|
|
|
|
e2.insert(B);
|
2013-05-08 14:10:26 -05:00
|
|
|
|
2014-11-06 11:24:47 -06:00
|
|
|
assert!(!e1.is_disjoint(&e2));
|
2013-05-08 14:10:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// contains and contains_elem
|
|
|
|
|
|
|
|
#[test]
|
2014-11-06 11:24:47 -06:00
|
|
|
fn test_superset() {
|
|
|
|
let mut e1: EnumSet<Foo> = EnumSet::new();
|
|
|
|
e1.insert(A);
|
2013-05-08 14:10:26 -05:00
|
|
|
|
2014-11-06 11:24:47 -06:00
|
|
|
let mut e2: EnumSet<Foo> = EnumSet::new();
|
|
|
|
e2.insert(A);
|
|
|
|
e2.insert(B);
|
2013-05-08 14:10:26 -05:00
|
|
|
|
2014-11-06 17:41:50 -06:00
|
|
|
let mut e3: EnumSet<Foo> = EnumSet::new();
|
|
|
|
e3.insert(C);
|
|
|
|
|
|
|
|
assert!(e1.is_subset(&e2));
|
2014-11-06 11:24:47 -06:00
|
|
|
assert!(e2.is_superset(&e1));
|
2014-11-06 17:41:50 -06:00
|
|
|
assert!(!e3.is_superset(&e2))
|
|
|
|
assert!(!e2.is_superset(&e3))
|
2013-05-08 14:10:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2014-11-06 11:24:47 -06:00
|
|
|
fn test_contains() {
|
|
|
|
let mut e1: EnumSet<Foo> = EnumSet::new();
|
|
|
|
e1.insert(A);
|
|
|
|
assert!(e1.contains(&A));
|
|
|
|
assert!(!e1.contains(&B));
|
|
|
|
assert!(!e1.contains(&C));
|
|
|
|
|
|
|
|
e1.insert(A);
|
|
|
|
e1.insert(B);
|
|
|
|
assert!(e1.contains(&A));
|
|
|
|
assert!(e1.contains(&B));
|
|
|
|
assert!(!e1.contains(&C));
|
2013-05-08 14:10:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
2013-07-25 23:53:29 -05:00
|
|
|
// iter
|
2013-06-30 13:12:04 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_iterator() {
|
2014-11-06 11:24:47 -06:00
|
|
|
let mut e1: EnumSet<Foo> = EnumSet::new();
|
2013-06-30 13:12:04 -05:00
|
|
|
|
2014-11-21 00:20:04 -06:00
|
|
|
let elems: ::vec::Vec<Foo> = e1.iter().collect();
|
2014-04-05 00:45:42 -05:00
|
|
|
assert!(elems.is_empty())
|
2013-06-30 13:12:04 -05:00
|
|
|
|
2014-11-06 11:24:47 -06:00
|
|
|
e1.insert(A);
|
2014-11-21 00:20:04 -06:00
|
|
|
let elems: ::vec::Vec<_> = e1.iter().collect();
|
2014-04-05 00:45:42 -05:00
|
|
|
assert_eq!(vec![A], elems)
|
2013-06-30 13:12:04 -05:00
|
|
|
|
2014-11-06 11:24:47 -06:00
|
|
|
e1.insert(C);
|
2014-11-21 00:20:04 -06:00
|
|
|
let elems: ::vec::Vec<_> = e1.iter().collect();
|
2014-04-05 00:45:42 -05:00
|
|
|
assert_eq!(vec![A,C], elems)
|
2013-06-30 13:12:04 -05:00
|
|
|
|
2014-11-06 11:24:47 -06:00
|
|
|
e1.insert(C);
|
2014-11-21 00:20:04 -06:00
|
|
|
let elems: ::vec::Vec<_> = e1.iter().collect();
|
2014-04-05 00:45:42 -05:00
|
|
|
assert_eq!(vec![A,C], elems)
|
2013-06-30 13:12:04 -05:00
|
|
|
|
2014-11-06 11:24:47 -06:00
|
|
|
e1.insert(B);
|
2014-11-21 00:20:04 -06:00
|
|
|
let elems: ::vec::Vec<_> = e1.iter().collect();
|
2014-04-05 00:45:42 -05:00
|
|
|
assert_eq!(vec![A,B,C], elems)
|
2013-06-30 13:12:04 -05:00
|
|
|
}
|
|
|
|
|
2013-05-08 14:10:26 -05:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// operators
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_operators() {
|
2014-11-06 11:24:47 -06:00
|
|
|
let mut e1: EnumSet<Foo> = EnumSet::new();
|
|
|
|
e1.insert(A);
|
|
|
|
e1.insert(C);
|
2013-05-08 14:10:26 -05:00
|
|
|
|
2014-11-06 11:24:47 -06:00
|
|
|
let mut e2: EnumSet<Foo> = EnumSet::new();
|
|
|
|
e2.insert(B);
|
|
|
|
e2.insert(C);
|
2013-05-08 14:10:26 -05:00
|
|
|
|
|
|
|
let e_union = e1 | e2;
|
2014-11-21 00:20:04 -06:00
|
|
|
let elems: ::vec::Vec<_> = e_union.iter().collect();
|
2014-04-05 00:45:42 -05:00
|
|
|
assert_eq!(vec![A,B,C], elems)
|
2013-05-08 14:10:26 -05:00
|
|
|
|
|
|
|
let e_intersection = e1 & e2;
|
2014-11-21 00:20:04 -06:00
|
|
|
let elems: ::vec::Vec<_> = e_intersection.iter().collect();
|
2014-04-05 00:45:42 -05:00
|
|
|
assert_eq!(vec![C], elems)
|
2013-05-08 14:10:26 -05:00
|
|
|
|
2014-11-07 17:46:29 -06:00
|
|
|
// Another way to express intersection
|
|
|
|
let e_intersection = e1 - (e1 - e2);
|
2014-11-21 00:20:04 -06:00
|
|
|
let elems: ::vec::Vec<_> = e_intersection.iter().collect();
|
2014-11-07 17:46:29 -06:00
|
|
|
assert_eq!(vec![C], elems)
|
|
|
|
|
2013-05-08 14:10:26 -05:00
|
|
|
let e_subtract = e1 - e2;
|
2014-11-21 00:20:04 -06:00
|
|
|
let elems: ::vec::Vec<_> = e_subtract.iter().collect();
|
2014-04-05 00:45:42 -05:00
|
|
|
assert_eq!(vec![A], elems)
|
2014-11-07 17:46:29 -06:00
|
|
|
|
|
|
|
// Bitwise XOR of two sets, aka symmetric difference
|
|
|
|
let e_symmetric_diff = e1 ^ e2;
|
2014-11-21 00:20:04 -06:00
|
|
|
let elems: ::vec::Vec<_> = e_symmetric_diff.iter().collect();
|
2014-11-07 17:46:29 -06:00
|
|
|
assert_eq!(vec![A,B], elems)
|
|
|
|
|
|
|
|
// Another way to express symmetric difference
|
|
|
|
let e_symmetric_diff = (e1 - e2) | (e2 - e1);
|
2014-11-21 00:20:04 -06:00
|
|
|
let elems: ::vec::Vec<_> = e_symmetric_diff.iter().collect();
|
2014-11-07 17:46:29 -06:00
|
|
|
assert_eq!(vec![A,B], elems)
|
|
|
|
|
|
|
|
// Yet another way to express symmetric difference
|
|
|
|
let e_symmetric_diff = (e1 | e2) - (e1 & e2);
|
2014-11-21 00:20:04 -06:00
|
|
|
let elems: ::vec::Vec<_> = e_symmetric_diff.iter().collect();
|
2014-11-07 17:46:29 -06:00
|
|
|
assert_eq!(vec![A,B], elems)
|
2013-05-08 14:10:26 -05:00
|
|
|
}
|
2014-11-06 17:10:24 -06:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_fail]
|
|
|
|
fn test_overflow() {
|
|
|
|
#[allow(dead_code)]
|
|
|
|
#[repr(uint)]
|
|
|
|
enum Bar {
|
|
|
|
V00, V01, V02, V03, V04, V05, V06, V07, V08, V09,
|
|
|
|
V10, V11, V12, V13, V14, V15, V16, V17, V18, V19,
|
|
|
|
V20, V21, V22, V23, V24, V25, V26, V27, V28, V29,
|
|
|
|
V30, V31, V32, V33, V34, V35, V36, V37, V38, V39,
|
|
|
|
V40, V41, V42, V43, V44, V45, V46, V47, V48, V49,
|
|
|
|
V50, V51, V52, V53, V54, V55, V56, V57, V58, V59,
|
|
|
|
V60, V61, V62, V63, V64, V65, V66, V67, V68, V69,
|
|
|
|
}
|
librustc: Make `Copy` opt-in.
This change makes the compiler no longer infer whether types (structures
and enumerations) implement the `Copy` trait (and thus are implicitly
copyable). Rather, you must implement `Copy` yourself via `impl Copy for
MyType {}`.
A new warning has been added, `missing_copy_implementations`, to warn
you if a non-generic public type has been added that could have
implemented `Copy` but didn't.
For convenience, you may *temporarily* opt out of this behavior by using
`#![feature(opt_out_copy)]`. Note though that this feature gate will never be
accepted and will be removed by the time that 1.0 is released, so you should
transition your code away from using it.
This breaks code like:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
Change this code to:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
impl Copy for Point2D {}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
This is the backwards-incompatible part of #13231.
Part of RFC #3.
[breaking-change]
2014-12-05 19:01:33 -06:00
|
|
|
|
|
|
|
impl Copy for Bar {}
|
|
|
|
|
2014-11-06 17:10:24 -06:00
|
|
|
impl CLike for Bar {
|
|
|
|
fn to_uint(&self) -> uint {
|
|
|
|
*self as uint
|
|
|
|
}
|
|
|
|
|
|
|
|
fn from_uint(v: uint) -> Bar {
|
|
|
|
unsafe { mem::transmute(v) }
|
|
|
|
}
|
|
|
|
}
|
2014-11-07 16:54:39 -06:00
|
|
|
let mut set = EnumSet::new();
|
2014-11-06 02:05:53 -06:00
|
|
|
set.insert(Bar::V64);
|
2014-11-06 17:10:24 -06:00
|
|
|
}
|
2013-05-08 14:10:26 -05:00
|
|
|
}
|