The two deletions are because the test cases are very old (still using `class` and modes!), and, as far as I can tell (since they are so old), the areas they test are well tested by other rpass tests.
LIBSYNTAX_CRATE := $(S)src/libsyntax/syntax.rs
LIBSYNTAX_INPUTS := $(wildcard $(addprefix $(S)src/libsyntax/, \
- *.rs */*.rs */*/*.rs))
+ *.rs */*.rs */*/*.rs */*/*/*.rs))
DRIVER_CRATE := $(S)src/driver/driver.rs
| $$(TLIB$(1)_T_$(2)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(STDLIB_GLOB_$(2)),$$(notdir $$@))
- $$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) -o $$@ $$< && touch $$@
+ $$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) --out-dir $$(@D) $$< && touch $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(STDLIB_GLOB_$(2)),$$(notdir $$@))
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2)): \
| $$(TLIB$(1)_T_$(2)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_GLOB_$(2)),$$(notdir $$@))
- $$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) -o $$@ $$< && touch $$@
+ $$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) --out-dir $$(@D) $$< && touch $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_GLOB_$(2)),$$(notdir $$@))
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(3)): \
| $$(TLIB$(1)_T_$(2)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBSYNTAX_GLOB_$(2)),$$(notdir $$@))
- $$(STAGE$(1)_T_$(2)_H_$(3)) $(BORROWCK) -o $$@ $$< && touch $$@
+ $$(STAGE$(1)_T_$(2)_H_$(3)) $(BORROWCK) --out-dir $$(@D) $$< && touch $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBSYNTAX_GLOB_$(2)),$$(notdir $$@))
# Only build the compiler for host triples
| $$(TLIB$(1)_T_$(2)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTC_GLOB_$(2)),$$(notdir $$@))
- $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< && touch $$@
+ $$(STAGE$(1)_T_$(2)_H_$(3)) --out-dir $$(@D) $$< && touch $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTC_GLOB_$(2)),$$(notdir $$@))
$$(TBIN$(1)_T_$(2)_H_$(3))/rustc$$(X_$(3)): \
| $$(TLIB$(1)_T_$(4)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTPKG_GLOB_$(4)),$$(notdir $$@))
- $$(STAGE$(1)_T_$(4)_H_$(3)) $$(WFLAGS_ST$(1)) -o $$@ $$< && touch $$@
+ $$(STAGE$(1)_T_$(4)_H_$(3)) $$(WFLAGS_ST$(1)) --out-dir $$(@D) $$< && touch $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTPKG_GLOB_$(4)),$$(notdir $$@))
$$(TBIN$(1)_T_$(4)_H_$(3))/rustpkg$$(X_$(4)): \
| $$(TLIB$(1)_T_$(4)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTDOC_GLOB_$(4)),$$(notdir $$@))
- $$(STAGE$(1)_T_$(4)_H_$(3)) -o $$@ $$< && touch $$@
+ $$(STAGE$(1)_T_$(4)_H_$(3)) --out-dir $$(@D) $$< && touch $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTDOC_GLOB_$(4)),$$(notdir $$@))
$$(TBIN$(1)_T_$(4)_H_$(3))/rustdoc$$(X_$(4)): \
| $$(TLIB$(1)_T_$(4)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTI_GLOB_$(4)),$$(notdir $$@))
- $$(STAGE$(1)_T_$(4)_H_$(3)) -o $$@ $$< && touch $$@
+ $$(STAGE$(1)_T_$(4)_H_$(3)) --out-dir $$(@D) $$< && touch $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTI_GLOB_$(4)),$$(notdir $$@))
$$(TBIN$(1)_T_$(4)_H_$(3))/rusti$$(X_$(4)): \
| $$(TLIB$(1)_T_$(4)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUST_GLOB_$(4)),$$(notdir $$@))
- $$(STAGE$(1)_T_$(4)_H_$(3)) -o $$@ $$< && touch $$@
+ $$(STAGE$(1)_T_$(4)_H_$(3)) --out-dir $$(@D) $$< && touch $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUST_GLOB_$(4)),$$(notdir $$@))
$$(TBIN$(1)_T_$(4)_H_$(3))/rust$$(X_$(4)): \
#[crate_type = "bin"];
#[allow(non_camel_case_types)];
-#[allow(unrecognized_lint)]; // NOTE: remove after snapshot
#[deny(warnings)];
extern mod extra;
// except according to those terms.
//! Base64 binary-to-text encoding
+use std::str;
/// Available encoding character sets
pub enum CharacterSet {
pub static MIME: Config =
Config {char_set: Standard, pad: true, line_length: Some(76)};
-static STANDARD_CHARS: [char, ..64] = [
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
- 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
- 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
-];
-
-static URLSAFE_CHARS: [char, ..64] = [
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
- 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
- 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
-];
+static STANDARD_CHARS: &'static[u8] = bytes!("ABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ "abcdefghijklmnopqrstuvwxyz",
+ "0123456789+/");
+
+static URLSAFE_CHARS: &'static[u8] = bytes!("ABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ "abcdefghijklmnopqrstuvwxyz",
+ "0123456789-_");
/// A trait for converting a value to base64 encoding.
pub trait ToBase64 {
* ~~~
*/
fn to_base64(&self, config: Config) -> ~str {
- let chars = match config.char_set {
+ let bytes = match config.char_set {
Standard => STANDARD_CHARS,
UrlSafe => URLSAFE_CHARS
};
- let mut s = ~"";
+ let mut v: ~[u8] = ~[];
let mut i = 0;
let mut cur_length = 0;
let len = self.len();
match config.line_length {
Some(line_length) =>
if cur_length >= line_length {
- s.push_str("\r\n");
+ v.push('\r' as u8);
+ v.push('\n' as u8);
cur_length = 0;
},
None => ()
(self[i + 2] as u32);
// This 24-bit number gets separated into four 6-bit numbers.
- s.push_char(chars[(n >> 18) & 63]);
- s.push_char(chars[(n >> 12) & 63]);
- s.push_char(chars[(n >> 6 ) & 63]);
- s.push_char(chars[n & 63]);
+ v.push(bytes[(n >> 18) & 63]);
+ v.push(bytes[(n >> 12) & 63]);
+ v.push(bytes[(n >> 6 ) & 63]);
+ v.push(bytes[n & 63]);
cur_length += 4;
i += 3;
match config.line_length {
Some(line_length) =>
if cur_length >= line_length {
- s.push_str("\r\n");
+ v.push('\r' as u8);
+ v.push('\n' as u8);
},
None => ()
}
0 => (),
1 => {
let n = (self[i] as u32) << 16;
- s.push_char(chars[(n >> 18) & 63]);
- s.push_char(chars[(n >> 12) & 63]);
+ v.push(bytes[(n >> 18) & 63]);
+ v.push(bytes[(n >> 12) & 63]);
if config.pad {
- s.push_str("==");
+ v.push('=' as u8);
+ v.push('=' as u8);
}
}
2 => {
let n = (self[i] as u32) << 16 |
(self[i + 1u] as u32) << 8;
- s.push_char(chars[(n >> 18) & 63]);
- s.push_char(chars[(n >> 12) & 63]);
- s.push_char(chars[(n >> 6 ) & 63]);
+ v.push(bytes[(n >> 18) & 63]);
+ v.push(bytes[(n >> 12) & 63]);
+ v.push(bytes[(n >> 6 ) & 63]);
if config.pad {
- s.push_char('=');
+ v.push('=' as u8);
}
}
_ => fail!("Algebra is broken, please alert the math police")
}
- s
- }
-}
-impl<'self> ToBase64 for &'self str {
- /**
- * Convert any string (literal, `@`, `&`, or `~`) to base64 encoding.
- *
- *
- * # Example
- *
- * ~~~ {.rust}
- * extern mod extra;
- * use extra::base64::{ToBase64, standard};
- *
- * fn main () {
- * let str = "Hello, World".to_base64(standard);
- * printfln!("%s", str);
- * }
- * ~~~
- *
- */
- fn to_base64(&self, config: Config) -> ~str {
- self.as_bytes().to_base64(config)
+ unsafe {
+ str::raw::from_bytes_owned(v)
+ }
}
}
fn from_base64(&self) -> Result<~[u8], ~str>;
}
-impl<'self> FromBase64 for &'self [u8] {
+impl<'self> FromBase64 for &'self str {
/**
- * Convert base64 `u8` vector into u8 byte values.
- * Every 4 encoded characters is converted into 3 octets, modulo padding.
+ * Convert any base64 encoded string (literal, `@`, `&`, or `~`)
+ * to the byte values it encodes.
+ *
+ * You can use the `from_bytes` function in `std::str`
+ * to turn a `[u8]` into a string with characters corresponding to those
+ * values.
*
* # Example
*
+ * This converts a string literal to base64 and back.
+ *
* ~~~ {.rust}
* extern mod extra;
* use extra::base64::{ToBase64, FromBase64, standard};
+ * use std::str;
*
* fn main () {
- * let str = [52,32].to_base64(standard);
- * printfln!("%s", str);
- * let bytes = str.from_base64();
+ * let hello_str = "Hello, World".to_base64(standard);
+ * printfln!("%s", hello_str);
+ * let bytes = hello_str.from_base64();
* printfln!("%?", bytes);
+ * let result_str = str::from_bytes(bytes);
+ * printfln!("%s", result_str);
* }
* ~~~
*/
let mut buf: u32 = 0;
let mut modulus = 0;
- let mut it = self.iter();
- for &byte in it {
- let ch = byte as char;
+ let mut it = self.byte_iter().enumerate();
+ for (idx, byte) in it {
let val = byte as u32;
- match ch {
+ match byte as char {
'A'..'Z' => buf |= val - 0x41,
'a'..'z' => buf |= val - 0x47,
'0'..'9' => buf |= val + 0x04,
'/'|'_' => buf |= 0x3F,
'\r'|'\n' => loop,
'=' => break,
- _ => return Err(~"Invalid Base64 character")
+ _ => return Err(fmt!("Invalid character '%c' at position %u",
+ self.char_at(idx), idx))
}
buf <<= 6;
}
}
- if !it.all(|&byte| {byte as char == '='}) {
- return Err(~"Invalid Base64 character");
+ for (idx, byte) in it {
+ if (byte as char) != '=' {
+ return Err(fmt!("Invalid character '%c' at position %u",
+ self.char_at(idx), idx));
+ }
}
match modulus {
}
}
-impl<'self> FromBase64 for &'self str {
- /**
- * Convert any base64 encoded string (literal, `@`, `&`, or `~`)
- * to the byte values it encodes.
- *
- * You can use the `from_bytes` function in `std::str`
- * to turn a `[u8]` into a string with characters corresponding to those
- * values.
- *
- * # Example
- *
- * This converts a string literal to base64 and back.
- *
- * ~~~ {.rust}
- * extern mod extra;
- * use extra::base64::{ToBase64, FromBase64, standard};
- * use std::str;
- *
- * fn main () {
- * let hello_str = "Hello, World".to_base64(standard);
- * printfln!("%s", hello_str);
- * let bytes = hello_str.from_base64();
- * printfln!("%?", bytes);
- * let result_str = str::from_bytes(bytes);
- * printfln!("%s", result_str);
- * }
- * ~~~
- */
- fn from_base64(&self) -> Result<~[u8], ~str> {
- self.as_bytes().from_base64()
- }
-}
-
#[cfg(test)]
mod test {
use test::BenchHarness;
#[test]
fn test_to_base64_basic() {
- assert_eq!("".to_base64(STANDARD), ~"");
- assert_eq!("f".to_base64(STANDARD), ~"Zg==");
- assert_eq!("fo".to_base64(STANDARD), ~"Zm8=");
- assert_eq!("foo".to_base64(STANDARD), ~"Zm9v");
- assert_eq!("foob".to_base64(STANDARD), ~"Zm9vYg==");
- assert_eq!("fooba".to_base64(STANDARD), ~"Zm9vYmE=");
- assert_eq!("foobar".to_base64(STANDARD), ~"Zm9vYmFy");
+ assert_eq!("".as_bytes().to_base64(STANDARD), ~"");
+ assert_eq!("f".as_bytes().to_base64(STANDARD), ~"Zg==");
+ assert_eq!("fo".as_bytes().to_base64(STANDARD), ~"Zm8=");
+ assert_eq!("foo".as_bytes().to_base64(STANDARD), ~"Zm9v");
+ assert_eq!("foob".as_bytes().to_base64(STANDARD), ~"Zm9vYg==");
+ assert_eq!("fooba".as_bytes().to_base64(STANDARD), ~"Zm9vYmE=");
+ assert_eq!("foobar".as_bytes().to_base64(STANDARD), ~"Zm9vYmFy");
}
#[test]
fn test_to_base64_line_break() {
assert!(![0u8, 1000].to_base64(Config {line_length: None, ..STANDARD})
.contains("\r\n"));
- assert_eq!("foobar".to_base64(Config {line_length: Some(4), ..STANDARD}),
+ assert_eq!("foobar".as_bytes().to_base64(Config {line_length: Some(4),
+ ..STANDARD}),
~"Zm9v\r\nYmFy");
}
#[test]
fn test_to_base64_padding() {
- assert_eq!("f".to_base64(Config {pad: false, ..STANDARD}), ~"Zg");
- assert_eq!("fo".to_base64(Config {pad: false, ..STANDARD}), ~"Zm8");
+ assert_eq!("f".as_bytes().to_base64(Config {pad: false, ..STANDARD}), ~"Zg");
+ assert_eq!("fo".as_bytes().to_base64(Config {pad: false, ..STANDARD}), ~"Zm8");
}
#[test]
#[test]
fn test_from_base64_invalid_char() {
assert!("Zm$=".from_base64().is_err())
- assert!("Zg==$".from_base64().is_err());
+ assert!("Zg==$".from_base64().is_err());
}
#[test]
}
#[bench]
- pub fn to_base64(bh: & mut BenchHarness) {
+ pub fn bench_to_base64(bh: & mut BenchHarness) {
let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
do bh.iter {
- s.to_base64(STANDARD);
+ s.as_bytes().to_base64(STANDARD);
}
bh.bytes = s.len() as u64;
}
#[bench]
- pub fn from_base64(bh: & mut BenchHarness) {
+ pub fn bench_from_base64(bh: & mut BenchHarness) {
let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
- let b = s.to_base64(STANDARD);
+ let b = s.as_bytes().to_base64(STANDARD);
do bh.iter {
b.from_base64();
}
--- /dev/null
+// 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)
+ }
+}
pub mod base64;
pub mod rl;
pub mod workcache;
+pub mod enum_set;
#[path="num/bigint.rs"]
pub mod bigint;
#[path="num/rational.rs"]
pub mod semver;
pub mod fileinput;
pub mod flate;
+pub mod hex;
#[cfg(unicode)]
mod unicode;
--- /dev/null
+// Copyright 2013 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.
+
+//! Hex binary-to-text encoding
+use std::str;
+use std::vec;
+
+/// A trait for converting a value to hexadecimal encoding
+pub trait ToHex {
+ /// Converts the value of `self` to a hex value, returning the owned
+ /// string.
+ fn to_hex(&self) -> ~str;
+}
+
+static CHARS: &'static[u8] = bytes!("0123456789abcdef");
+
+impl<'self> ToHex for &'self [u8] {
+ /**
+ * Turn a vector of `u8` bytes into a hexadecimal string.
+ *
+ * # Example
+ *
+ * ~~~ {.rust}
+ * extern mod extra;
+ * use extra::hex::ToHex;
+ *
+ * fn main () {
+ * let str = [52,32].to_hex();
+ * printfln!("%s", str);
+ * }
+ * ~~~
+ */
+ fn to_hex(&self) -> ~str {
+ let mut v = vec::with_capacity(self.len() * 2);
+ for &byte in self.iter() {
+ v.push(CHARS[byte >> 4]);
+ v.push(CHARS[byte & 0xf]);
+ }
+
+ unsafe {
+ str::raw::from_bytes_owned(v)
+ }
+ }
+}
+
+/// A trait for converting hexadecimal encoded values
+pub trait FromHex {
+ /// Converts the value of `self`, interpreted as hexadecimal encoded data,
+ /// into an owned vector of bytes, returning the vector.
+ fn from_hex(&self) -> Result<~[u8], ~str>;
+}
+
+impl<'self> FromHex for &'self str {
+ /**
+ * Convert any hexadecimal encoded string (literal, `@`, `&`, or `~`)
+ * to the byte values it encodes.
+ *
+ * You can use the `from_bytes` function in `std::str`
+ * to turn a `[u8]` into a string with characters corresponding to those
+ * values.
+ *
+ * # Example
+ *
+ * This converts a string literal to hexadecimal and back.
+ *
+ * ~~~ {.rust}
+ * extern mod extra;
+ * use extra::hex::{FromHex, ToHex};
+ * use std::str;
+ *
+ * fn main () {
+ * let hello_str = "Hello, World".to_hex();
+ * printfln!("%s", hello_str);
+ * let bytes = hello_str.from_hex().unwrap();
+ * printfln!("%?", bytes);
+ * let result_str = str::from_bytes(bytes);
+ * printfln!("%s", result_str);
+ * }
+ * ~~~
+ */
+ fn from_hex(&self) -> Result<~[u8], ~str> {
+ // This may be an overestimate if there is any whitespace
+ let mut b = vec::with_capacity(self.len() / 2);
+ let mut modulus = 0;
+ let mut buf = 0u8;
+
+ for (idx, byte) in self.byte_iter().enumerate() {
+ buf <<= 4;
+
+ match byte as char {
+ 'A'..'F' => buf |= byte - ('A' as u8) + 10,
+ 'a'..'f' => buf |= byte - ('a' as u8) + 10,
+ '0'..'9' => buf |= byte - ('0' as u8),
+ ' '|'\r'|'\n'|'\t' => {
+ buf >>= 4;
+ loop
+ }
+ _ => return Err(fmt!("Invalid character '%c' at position %u",
+ self.char_at(idx), idx))
+ }
+
+ modulus += 1;
+ if modulus == 2 {
+ modulus = 0;
+ b.push(buf);
+ }
+ }
+
+ match modulus {
+ 0 => Ok(b),
+ _ => Err(~"Invalid input length")
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use test::BenchHarness;
+ use hex::*;
+
+ #[test]
+ pub fn test_to_hex() {
+ assert_eq!("foobar".as_bytes().to_hex(), ~"666f6f626172");
+ }
+
+ #[test]
+ pub fn test_from_hex_okay() {
+ assert_eq!("666f6f626172".from_hex().unwrap(),
+ "foobar".as_bytes().to_owned());
+ assert_eq!("666F6F626172".from_hex().unwrap(),
+ "foobar".as_bytes().to_owned());
+ }
+
+ #[test]
+ pub fn test_from_hex_odd_len() {
+ assert!("666".from_hex().is_err());
+ assert!("66 6".from_hex().is_err());
+ }
+
+ #[test]
+ pub fn test_from_hex_invalid_char() {
+ assert!("66y6".from_hex().is_err());
+ }
+
+ #[test]
+ pub fn test_from_hex_ignores_whitespace() {
+ assert_eq!("666f 6f6\r\n26172 ".from_hex().unwrap(),
+ "foobar".as_bytes().to_owned());
+ }
+
+ #[test]
+ pub fn test_to_hex_all_bytes() {
+ for i in range(0, 256) {
+ assert_eq!([i as u8].to_hex(), fmt!("%02x", i as uint));
+ }
+ }
+
+ #[test]
+ pub fn test_from_hex_all_bytes() {
+ for i in range(0, 256) {
+ assert_eq!(fmt!("%02x", i as uint).from_hex().unwrap(), ~[i as u8]);
+ assert_eq!(fmt!("%02X", i as uint).from_hex().unwrap(), ~[i as u8]);
+ }
+ }
+
+ #[bench]
+ pub fn bench_to_hex(bh: & mut BenchHarness) {
+ let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
+ ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
+ do bh.iter {
+ s.as_bytes().to_hex();
+ }
+ bh.bytes = s.len() as u64;
+ }
+
+ #[bench]
+ pub fn bench_from_hex(bh: & mut BenchHarness) {
+ let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
+ ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
+ let b = s.as_bytes().to_hex();
+ do bh.iter {
+ b.from_hex();
+ }
+ bh.bytes = b.len() as u64;
+ }
+}
use serialize::Encodable;
use serialize;
-use sort::Sort;
use treemap::TreeMap;
/// Represents a json value
Object(ref d0) => {
match *other {
Number(_) | String(_) | Boolean(_) | List(_) => false,
- Object(ref d1) => {
- let mut d0_flat = ~[];
- let mut d1_flat = ~[];
-
- // FIXME #4430: this is horribly inefficient...
- for (k, v) in d0.iter() {
- d0_flat.push((@(*k).clone(), @(*v).clone()));
- }
- d0_flat.qsort();
-
- for (k, v) in d1.iter() {
- d1_flat.push((@(*k).clone(), @(*v).clone()));
- }
- d1_flat.qsort();
-
- d0_flat < d1_flat
- }
+ Object(ref d1) => d0 < d1,
Null => true
}
}
#[fixed_stack_segment]
pub fn compile_input(sess: Session, cfg: ast::CrateConfig, input: &input,
outdir: &Option<Path>, output: &Option<Path>) {
- let outputs = build_output_filenames(input, outdir, output, [], sess);
// We need nested scopes here, because the intermediate results can keep
// large chunks of memory alive and we want to free them as soon as
// possible to keep the peak memory usage low
- let trans = {
+ let (outputs, trans) = {
let expanded_crate = {
let crate = phase_1_parse_input(sess, cfg.clone(), input);
if stop_after_phase_1(sess) { return; }
};
let analysis = phase_3_run_analysis_passes(sess, expanded_crate);
if stop_after_phase_3(sess) { return; }
- phase_4_translate_to_llvm(sess, expanded_crate, &analysis, outputs)
+ let outputs = build_output_filenames(input, outdir, output, [], sess);
+ let trans = phase_4_translate_to_llvm(sess, expanded_crate,
+ &analysis, outputs);
+ (outputs, trans)
};
phase_5_run_llvm_passes(sess, &trans, outputs);
if stop_after_phase_5(sess) { return; }
};
if *sess.building_library {
- // FIXME (#2401): We might want to warn here; we're actually not
- // going to respect the user's choice of library name when it
- // comes time to link, we'll be linking to
- // lib<basename>-<hash>-<version>.so no matter what.
+ sess.warn("ignoring specified output filename for library.");
}
if *odir != None {
}
fn enc_bounds(w: @io::Writer, cx: @ctxt, bs: &ty::ParamBounds) {
- do bs.builtin_bounds.each |bound| {
+ for bound in bs.builtin_bounds.iter() {
match bound {
ty::BoundSend => w.write_char('S'),
ty::BoundFreeze => w.write_char('K'),
ty::BoundStatic => w.write_char('O'),
ty::BoundSized => w.write_char('Z'),
}
- true
- };
+ }
for &tp in bs.trait_bounds.iter() {
w.write_char('I');
// Note that `break` and `loop` statements
// may cause additional edges.
- // NOTE: Is the condition considered part of the loop?
+ // Is the condition considered part of the loop?
let loopback = self.add_dummy_node([pred]); // 1
let cond_exit = self.expr(cond, loopback); // 2
let expr_exit = self.add_node(expr.id, [cond_exit]); // 3
{
let kind = ty::type_contents(cx.tcx, ty);
let mut missing = ty::EmptyBuiltinBounds();
- do bounds.each |bound| {
+ for bound in bounds.iter() {
if !kind.meets_bound(cx.tcx, bound) {
missing.add(bound);
}
- true
- };
+ }
if !missing.is_empty() {
any_missing(missing);
}
use middle::trans::type_of;
use middle::ty;
use util::common::indenter;
+use util::ppaux::{Repr, vec_map_to_str};
use std::hashmap::HashMap;
use std::vec;
use syntax::ast_util::path_to_ident;
use syntax::ast_util;
use syntax::codemap::{span, dummy_sp};
-use syntax::print::pprust::pat_to_str;
// An option identifying a literal: either a unit-like struct or an
// expression.
data: ArmData<'self>
}
-pub fn match_to_str(bcx: @mut Block, m: &Match) -> ~str {
- if bcx.sess().verbose() {
- // for many programs, this just take too long to serialize
- fmt!("%?", m.pats.map(|p| pat_to_str(*p, bcx.sess().intr())))
- } else {
- fmt!("%u pats", m.pats.len())
+impl<'self> Repr for Match<'self> {
+ fn repr(&self, tcx: ty::ctxt) -> ~str {
+ if tcx.sess.verbose() {
+ // for many programs, this just take too long to serialize
+ self.pats.repr(tcx)
+ } else {
+ fmt!("%u pats", self.pats.len())
+ }
}
}
-pub fn matches_to_str(bcx: @mut Block, m: &[Match]) -> ~str {
- fmt!("%?", m.map(|n| match_to_str(bcx, n)))
-}
-
pub fn has_nested_bindings(m: &[Match], col: uint) -> bool {
for br in m.iter() {
match br.pats[col].node {
col: uint,
val: ValueRef)
-> ~[Match<'r>] {
- debug!("expand_nested_bindings(bcx=%s, m=%s, col=%u, val=%?)",
+ debug!("expand_nested_bindings(bcx=%s, m=%s, col=%u, val=%s)",
bcx.to_str(),
- matches_to_str(bcx, m),
+ m.repr(bcx.tcx()),
col,
bcx.val_to_str(val));
let _indenter = indenter();
bcx.sess().span_bug(
p.span,
fmt!("Expected an identifier pattern but found p: %s",
- pat_to_str(p, bcx.sess().intr())));
+ p.repr(bcx.tcx())));
}
}
val: ValueRef,
e: enter_pat)
-> ~[Match<'r>] {
- debug!("enter_match(bcx=%s, m=%s, col=%u, val=%?)",
+ debug!("enter_match(bcx=%s, m=%s, col=%u, val=%s)",
bcx.to_str(),
- matches_to_str(bcx, m),
+ m.repr(bcx.tcx()),
col,
bcx.val_to_str(val));
let _indenter = indenter();
}
}
- debug!("result=%s", matches_to_str(bcx, result));
+ debug!("result=%s", result.repr(bcx.tcx()));
return result;
}
col: uint,
val: ValueRef)
-> ~[Match<'r>] {
- debug!("enter_default(bcx=%s, m=%s, col=%u, val=%?)",
+ debug!("enter_default(bcx=%s, m=%s, col=%u, val=%s)",
bcx.to_str(),
- matches_to_str(bcx, m),
+ m.repr(bcx.tcx()),
col,
bcx.val_to_str(val));
let _indenter = indenter();
variant_size: uint,
val: ValueRef)
-> ~[Match<'r>] {
- debug!("enter_opt(bcx=%s, m=%s, col=%u, val=%?)",
+ debug!("enter_opt(bcx=%s, m=%s, col=%u, val=%s)",
bcx.to_str(),
- matches_to_str(bcx, m),
+ m.repr(bcx.tcx()),
col,
bcx.val_to_str(val));
let _indenter = indenter();
fields: &[ast::ident],
val: ValueRef)
-> ~[Match<'r>] {
- debug!("enter_rec_or_struct(bcx=%s, m=%s, col=%u, val=%?)",
+ debug!("enter_rec_or_struct(bcx=%s, m=%s, col=%u, val=%s)",
bcx.to_str(),
- matches_to_str(bcx, m),
+ m.repr(bcx.tcx()),
col,
bcx.val_to_str(val));
let _indenter = indenter();
val: ValueRef,
n_elts: uint)
-> ~[Match<'r>] {
- debug!("enter_tup(bcx=%s, m=%s, col=%u, val=%?)",
+ debug!("enter_tup(bcx=%s, m=%s, col=%u, val=%s)",
bcx.to_str(),
- matches_to_str(bcx, m),
+ m.repr(bcx.tcx()),
col,
bcx.val_to_str(val));
let _indenter = indenter();
val: ValueRef,
n_elts: uint)
-> ~[Match<'r>] {
- debug!("enter_tuple_struct(bcx=%s, m=%s, col=%u, val=%?)",
+ debug!("enter_tuple_struct(bcx=%s, m=%s, col=%u, val=%s)",
bcx.to_str(),
- matches_to_str(bcx, m),
+ m.repr(bcx.tcx()),
col,
bcx.val_to_str(val));
let _indenter = indenter();
col: uint,
val: ValueRef)
-> ~[Match<'r>] {
- debug!("enter_box(bcx=%s, m=%s, col=%u, val=%?)",
+ debug!("enter_box(bcx=%s, m=%s, col=%u, val=%s)",
bcx.to_str(),
- matches_to_str(bcx, m),
+ m.repr(bcx.tcx()),
col,
bcx.val_to_str(val));
let _indenter = indenter();
col: uint,
val: ValueRef)
-> ~[Match<'r>] {
- debug!("enter_uniq(bcx=%s, m=%s, col=%u, val=%?)",
+ debug!("enter_uniq(bcx=%s, m=%s, col=%u, val=%s)",
bcx.to_str(),
- matches_to_str(bcx, m),
+ m.repr(bcx.tcx()),
col,
bcx.val_to_str(val));
let _indenter = indenter();
col: uint,
val: ValueRef)
-> ~[Match<'r>] {
- debug!("enter_region(bcx=%s, m=%s, col=%u, val=%?)",
+ debug!("enter_region(bcx=%s, m=%s, col=%u, val=%s)",
bcx.to_str(),
- matches_to_str(bcx, m),
+ m.repr(bcx.tcx()),
col,
bcx.val_to_str(val));
let _indenter = indenter();
vals: &[ValueRef],
chk: Option<mk_fail>)
-> @mut Block {
- debug!("compile_guard(bcx=%s, guard_expr=%s, m=%s, vals=%?)",
+ debug!("compile_guard(bcx=%s, guard_expr=%s, m=%s, vals=%s)",
bcx.to_str(),
bcx.expr_to_str(guard_expr),
- matches_to_str(bcx, m),
- vals.map(|v| bcx.val_to_str(*v)));
+ m.repr(bcx.tcx()),
+ vec_map_to_str(vals, |v| bcx.val_to_str(*v)));
let _indenter = indenter();
let mut bcx = bcx;
m: &[Match],
vals: &[ValueRef],
chk: Option<mk_fail>) {
- debug!("compile_submatch(bcx=%s, m=%s, vals=%?)",
+ debug!("compile_submatch(bcx=%s, m=%s, vals=%s)",
bcx.to_str(),
- matches_to_str(bcx, m),
- vals.map(|v| bcx.val_to_str(*v)));
+ m.repr(bcx.tcx()),
+ vec_map_to_str(vals, |v| bcx.val_to_str(*v)));
let _indenter = indenter();
/*
// Decide what kind of branch we need
let opts = get_options(bcx, m, col);
+ debug!("options=%?", opts);
let mut kind = no_branch;
let mut test_val = val;
if opts.len() > 0u {
debug!("bind_irrefutable_pat(bcx=%s, pat=%s, binding_mode=%?)",
bcx.to_str(),
- pat_to_str(pat, bcx.sess().intr()),
+ pat.repr(bcx.tcx()),
binding_mode);
if bcx.sess().asm_comments() {
add_comment(bcx, fmt!("bind_irrefutable_pat(pat=%s)",
- pat_to_str(pat, bcx.sess().intr())));
+ pat.repr(bcx.tcx())));
}
let _indenter = indenter();
pub fn register_fn(ccx: @mut CrateContext,
sp: span,
sym: ~str,
- node_id: ast::NodeId)
- -> ValueRef {
- let t = ty::node_id_to_type(ccx.tcx, node_id);
- register_fn_full(ccx, sp, sym, node_id, t)
-}
-
-pub fn register_fn_full(ccx: @mut CrateContext,
- sp: span,
- sym: ~str,
- node_id: ast::NodeId,
- node_type: ty::t)
- -> ValueRef {
+ node_id: ast::NodeId,
+ node_type: ty::t)
+ -> ValueRef {
let llfty = type_of_fn_from_ty(ccx, node_type);
- register_fn_fuller(ccx, sp, sym, node_id, lib::llvm::CCallConv, llfty)
+ register_fn_llvmty(ccx, sp, sym, node_id, lib::llvm::CCallConv, llfty)
}
-pub fn register_fn_fuller(ccx: @mut CrateContext,
+pub fn register_fn_llvmty(ccx: @mut CrateContext,
sp: span,
sym: ~str,
node_id: ast::NodeId,
ast::item_fn(_, purity, _, _, _) => {
let llfn = if purity != ast::extern_fn {
- register_fn_full(ccx, i.span, sym, i.id, ty)
+ register_fn(ccx, i.span, sym, i.id, ty)
} else {
foreign::register_foreign_fn(ccx, i.span, sym, i.id)
};
let path = vec::append((*pth).clone(), [path_name(ni.ident)]);
let sym = exported_name(ccx, path, ty, ni.attrs);
- register_fn_full(ccx, ni.span, sym, ni.id, ty)
+ register_fn(ccx, ni.span, sym, ni.id, ty)
}
ast::foreign_item_static(*) => {
let ident = token::ident_to_str(&ni.ident);
llfn = match enm.node {
ast::item_enum(_, _) => {
- register_fn_full(ccx, (*v).span, sym, id, ty)
+ register_fn(ccx, (*v).span, sym, id, ty)
}
_ => fail!("node_variant, shouldn't happen")
};
let ty = ty::node_id_to_type(ccx.tcx, ctor_id);
let sym = exported_name(ccx, (*struct_path).clone(), ty,
struct_item.attrs);
- let llfn = register_fn_full(ccx, struct_item.span, sym, ctor_id, ty);
+ let llfn = register_fn(ccx, struct_item.span,
+ sym, ctor_id, ty);
set_inline_hint(llfn);
llfn
}
let sym = exported_name(ccx, path, mty, m.attrs);
- let llfn = register_fn_full(ccx, m.span, sym, id, mty);
+ let llfn = register_fn(ccx, m.span, sym, id, mty);
set_inline_hint_if_appr(m.attrs, llfn);
llfn
}
let tys = shim_types(ccx, node_id);
do tys.fn_ty.decl_fn |fnty| {
- register_fn_fuller(ccx, sp, sym.take(), node_id, lib::llvm::CCallConv, fnty)
+ register_fn_llvmty(ccx, sp, sym.take(), node_id, lib::llvm::CCallConv, fnty)
}
}
use util::ppaux::{trait_store_to_str, ty_to_str, vstore_to_str};
use util::ppaux::{Repr, UserString};
use util::common::{indenter};
-use util::enum_set::{EnumSet, CLike};
use std::cast;
use std::cmp;
use syntax::opt_vec;
use syntax::abi::AbiSet;
use syntax;
+use extra::enum_set::{EnumSet, CLike};
pub static INITIAL_DISCRIMINANT_VALUE: uint = 0;
// This is like with typarams below, but less "pessimistic" and also
// dependent on the trait store.
let mut bt = TC_NONE;
- do (AllBuiltinBounds() - bounds).each |bound| {
+ for bound in (AllBuiltinBounds() - bounds).iter() {
bt = bt + match bound {
BoundStatic if bounds.contains_elem(BoundSend)
=> TC_NONE, // Send bound implies static bound.
BoundFreeze => TC_MUTABLE,
BoundSized => TC_NONE, // don't care if interior is sized
};
- true
- };
+ }
st + mt + bt
}
let _i = indenter();
let mut tc = TC_ALL;
- do type_param_def.bounds.builtin_bounds.each |bound| {
+ for bound in type_param_def.bounds.builtin_bounds.iter() {
debug!("tc = %s, bound = %?", tc.to_str(), bound);
tc = tc - match bound {
BoundStatic => TypeContents::nonstatic(cx),
// The dynamic-size bit can be removed at pointer-level, etc.
BoundSized => TypeContents::dynamically_sized(cx),
};
- true
- };
+ }
debug!("result = %s", tc.to_str());
return tc;
pub mod util {
pub mod common;
pub mod ppaux;
- pub mod enum_set;
}
pub mod lib {
+++ /dev/null
-// 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)]
-pub struct EnumSet<E> {
- // We must maintain the invariant that no bits are set
- // for which no variant exists
- priv bits: uint
-}
-
-pub trait CLike {
- pub fn to_uint(&self) -> uint;
- pub fn from_uint(uint) -> Self;
-}
-
-fn bit<E:CLike>(e: E) -> uint {
- 1 << e.to_uint()
-}
-
-impl<E:CLike> EnumSet<E> {
- pub fn empty() -> EnumSet<E> {
- EnumSet {bits: 0}
- }
-
- pub fn is_empty(&self) -> bool {
- self.bits == 0
- }
-
- pub fn intersects(&self, e: EnumSet<E>) -> bool {
- (self.bits & e.bits) != 0
- }
-
- pub fn intersection(&self, e: EnumSet<E>) -> EnumSet<E> {
- EnumSet {bits: self.bits & e.bits}
- }
-
- pub fn contains(&self, e: EnumSet<E>) -> bool {
- (self.bits & e.bits) == e.bits
- }
-
- pub fn union(&self, e: EnumSet<E>) -> EnumSet<E> {
- EnumSet {bits: self.bits | e.bits}
- }
-
- pub fn add(&mut self, e: E) {
- self.bits |= bit(e);
- }
-
- pub fn contains_elem(&self, e: E) -> bool {
- (self.bits & bit(e)) != 0
- }
-
- pub fn each(&self, f: &fn(E) -> bool) -> bool {
- let mut bits = self.bits;
- let mut index = 0;
- while bits != 0 {
- if (bits & 1) != 0 {
- let e = CLike::from_uint(index);
- if !f(e) {
- return false;
- }
- }
- index += 1;
- bits >>= 1;
- }
- return true;
- }
-
- 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}
- }
-}
-
-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 util::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 / each
-
- #[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)
- }
-
- #[test]
- fn test_each() {
- let mut e1: EnumSet<Foo> = EnumSet::empty();
-
- assert_eq!(~[], collect(e1))
-
- e1.add(A);
- assert_eq!(~[A], collect(e1))
-
- e1.add(C);
- assert_eq!(~[A,C], collect(e1))
-
- e1.add(C);
- assert_eq!(~[A,C], collect(e1))
-
- e1.add(B);
- assert_eq!(~[A,B,C], collect(e1))
- }
-
- fn collect(e: EnumSet<Foo>) -> ~[Foo] {
- let mut elems = ~[];
- e.each(|elem| {
- elems.push(elem);
- true
- });
- 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)
- }
-}
}
}
+pub fn vec_map_to_str<T>(ts: &[T], f: &fn(t: &T) -> ~str) -> ~str {
+ let tstrs = ts.map(f);
+ fmt!("[%s]", tstrs.connect(", "))
+}
+
pub fn tys_to_str(cx: ctxt, ts: &[t]) -> ~str {
- let tstrs = ts.map(|t| ty_to_str(cx, *t));
- fmt!("(%s)", tstrs.connect(", "))
+ vec_map_to_str(ts, |t| ty_to_str(cx, *t))
}
pub fn fn_sig_to_str(cx: ctxt, typ: &ty::FnSig) -> ~str {
}
fn repr_vec<T:Repr>(tcx: ctxt, v: &[T]) -> ~str {
- fmt!("[%s]", v.map(|t| t.repr(tcx)).connect(","))
+ vec_map_to_str(v, |t| t.repr(tcx))
}
impl<'self, T:Repr> Repr for &'self [T] {
impl Repr for ty::ParamBounds {
fn repr(&self, tcx: ctxt) -> ~str {
let mut res = ~[];
- do self.builtin_bounds.each |b| {
+ for b in self.builtin_bounds.iter() {
res.push(match b {
ty::BoundStatic => ~"'static",
ty::BoundSend => ~"Send",
ty::BoundFreeze => ~"Freeze",
ty::BoundSized => ~"Sized",
});
- true
- };
+ }
for t in self.trait_bounds.iter() {
res.push(t.repr(tcx));
}
fn user_string(&self, tcx: ctxt) -> ~str {
if self.is_empty() { ~"<no-bounds>" } else {
let mut result = ~[];
- do self.each |bb| {
+ for bb in self.iter() {
result.push(bb.user_string(tcx));
- true
- };
+ }
result.connect("+")
}
}
}
}
- // FIXME: #7220 rusti on 32bit mac doesn't work.
- // FIXME: #7641 rusti on 32bit linux cross compile doesn't work
- // FIXME: #7115 re-enable once LLVM has been upgraded
- #[cfg(thiswillneverbeacfgflag)]
+ #[cfg(not(target_word_size = "32"))]
fn run_program(prog: &str) {
let mut r = repl();
for cmd in prog.split_iter('\n') {
"the command '%s' failed", cmd);
}
}
+ // FIXME: #7220 rusti on 32bit mac doesn't work
+ // FIXME: #7641 rusti on 32bit linux cross compile doesn't work
+ #[cfg(target_word_size = "32")]
fn run_program(_: &str) {}
#[test]
run_program("let a = 3;");
}
- #[test] #[ignore]
+ #[test]
fn new_tasks() {
- // XXX: can't spawn new tasks because the JIT code is cleaned up
- // after the main function is done.
run_program("
- spawn( || println(\"Please don't segfault\") );
- do spawn { println(\"Please?\"); }
+ use std::task::try;
+ try( || println(\"Please don't segfault\") );
+ do try { println(\"Please?\"); }
");
}
*(*self) > *(*other)
}
}
+
+#[cfg(not(test))]
+impl<'self, T: TotalOrd> TotalOrd for &'self T {
+ #[inline]
+ fn cmp(&self, other: & &'self T) -> Ordering { (**self).cmp(*other) }
+}
+
+#[cfg(not(test))]
+impl<'self, T: TotalEq> TotalEq for &'self T {
+ #[inline]
+ fn equals(&self, other: & &'self T) -> bool { (**self).equals(*other) }
+}
Return `o1` if it is not `Equal`, otherwise `o2`. Simulates the
lexical ordering on a type `(int, int)`.
*/
-// used in deriving code in libsyntax
#[inline]
pub fn lexical_ordering(o1: Ordering, o2: Ordering) -> Ordering {
match o1 {
*/
use cmp;
-use num::{Zero, One};
+use num::{Zero, One, Saturating};
use option::{Option, Some, None};
use ops::{Add, Mul};
use cmp::Ord;
let (a_lower, a_upper) = self.a.size_hint();
let (b_lower, b_upper) = self.b.size_hint();
- let lower = if uint::max_value - a_lower < b_lower {
- uint::max_value
- } else {
- a_lower + b_lower
- };
+ let lower = a_lower.saturating_add(b_lower);
let upper = match (a_upper, b_upper) {
- (Some(x), Some(y)) if uint::max_value - x < y => Some(uint::max_value),
- (Some(x), Some(y)) => Some(x + y),
+ (Some(x), Some(y)) => Some(x.saturating_add(y)),
_ => None
};
#[inline]
fn indexable(&self) -> uint {
let (a, b) = (self.a.indexable(), self.b.indexable());
- let total = a + b;
- if total < a || total < b {
- uint::max_value
- } else {
- total
- }
+ a.saturating_add(b)
}
#[inline]
fn size_hint(&self) -> (uint, Option<uint>) {
let (lower, upper) = self.iter.size_hint();
- let lower = if lower >= self.n { lower - self.n } else { 0 };
+ let lower = lower.saturating_sub(self.n);
let upper = match upper {
- Some(x) if x >= self.n => Some(x - self.n),
- Some(_) => Some(0),
+ Some(x) => Some(x.saturating_sub(self.n)),
None => None
};
impl<A, T: RandomAccessIterator<A>> RandomAccessIterator<A> for Skip<T> {
#[inline]
fn indexable(&self) -> uint {
- let N = self.iter.indexable();
- if N < self.n {
- 0
- } else {
- N - self.n
- }
+ self.iter.indexable().saturating_sub(self.n)
}
#[inline]
fn size_hint(&self) -> (uint, Option<uint>) {
let (flo, fhi) = self.frontiter.map_default((0, Some(0)), |it| it.size_hint());
let (blo, bhi) = self.backiter.map_default((0, Some(0)), |it| it.size_hint());
+ let lo = flo.saturating_add(blo);
match (self.iter.size_hint(), fhi, bhi) {
- ((0, Some(0)), Some(a), Some(b)) => (flo + blo, Some(a + b)),
- _ => (flo + blo, None)
+ ((0, Some(0)), Some(a), Some(b)) => (lo, Some(a.saturating_add(b))),
+ _ => (lo, None)
}
}
}
use ptr::to_unsafe_ptr;
-#[cfg(not(test))] use cmp::{Eq, Ord};
+#[cfg(not(test))] use cmp::*;
pub static RC_MANAGED_UNIQUE : uint = (-2) as uint;
pub static RC_IMMORTAL : uint = 0x77777777;
fn gt(&self, other: &@mut T) -> bool { *(*self) > *(*other) }
}
+#[cfg(not(test))]
+impl<T: TotalOrd> TotalOrd for @T {
+ #[inline]
+ fn cmp(&self, other: &@T) -> Ordering { (**self).cmp(*other) }
+}
+
+#[cfg(not(test))]
+impl<T: TotalOrd> TotalOrd for @mut T {
+ #[inline]
+ fn cmp(&self, other: &@mut T) -> Ordering { (**self).cmp(*other) }
+}
+
+#[cfg(not(test))]
+impl<T: TotalEq> TotalEq for @T {
+ #[inline]
+ fn equals(&self, other: &@T) -> bool { (**self).equals(*other) }
+}
+
+#[cfg(not(test))]
+impl<T: TotalEq> TotalEq for @mut T {
+ #[inline]
+ fn equals(&self, other: &@mut T) -> bool { (**self).equals(*other) }
+}
#[test]
fn test() {
let x = @3;
fn is_zero(&self) -> bool { (**self).is_zero() }
}
+/// Saturating math operations
+pub trait Saturating: Int {
+ /// Saturating addition operator.
+ /// Returns a+b, saturating at the numeric bounds instead of overflowing.
+ #[inline]
+ fn saturating_add(self, v: Self) -> Self {
+ let x = self + v;
+ if v >= Zero::zero() {
+ if x < self {
+ // overflow
+ Bounded::max_value::<Self>()
+ } else { x }
+ } else {
+ if x > self {
+ // underflow
+ Bounded::min_value::<Self>()
+ } else { x }
+ }
+ }
+
+ /// Saturating subtraction operator.
+ /// Returns a-b, saturating at the numeric bounds instead of overflowing.
+ #[inline]
+ fn saturating_sub(self, v: Self) -> Self {
+ let x = self - v;
+ if v >= Zero::zero() {
+ if x > self {
+ // underflow
+ Bounded::min_value::<Self>()
+ } else { x }
+ } else {
+ if x < self {
+ // overflow
+ Bounded::max_value::<Self>()
+ } else { x }
+ }
+ }
+}
+
+impl Saturating for int {}
+impl Saturating for i8 {}
+impl Saturating for i16 {}
+impl Saturating for i32 {}
+impl Saturating for i64 {}
+impl Saturating for uint {}
+impl Saturating for u8 {}
+impl Saturating for u16 {}
+impl Saturating for u32 {}
+impl Saturating for u64 {}
+
/// Helper function for testing numeric operations
#[cfg(test)]
pub fn test_num<T:Num + NumCast>(ten: T, two: T) {
assert_eq!(ten.rem(&two), ten % two);
}
-macro_rules! test_cast_20(
- ($_20:expr) => ({
- let _20 = $_20;
-
- assert_eq!(20u, _20.to_uint());
- assert_eq!(20u8, _20.to_u8());
- assert_eq!(20u16, _20.to_u16());
- assert_eq!(20u32, _20.to_u32());
- assert_eq!(20u64, _20.to_u64());
- assert_eq!(20i, _20.to_int());
- assert_eq!(20i8, _20.to_i8());
- assert_eq!(20i16, _20.to_i16());
- assert_eq!(20i32, _20.to_i32());
- assert_eq!(20i64, _20.to_i64());
- assert_eq!(20f, _20.to_float());
- assert_eq!(20f32, _20.to_f32());
- assert_eq!(20f64, _20.to_f64());
-
- assert_eq!(_20, NumCast::from(20u));
- assert_eq!(_20, NumCast::from(20u8));
- assert_eq!(_20, NumCast::from(20u16));
- assert_eq!(_20, NumCast::from(20u32));
- assert_eq!(_20, NumCast::from(20u64));
- assert_eq!(_20, NumCast::from(20i));
- assert_eq!(_20, NumCast::from(20i8));
- assert_eq!(_20, NumCast::from(20i16));
- assert_eq!(_20, NumCast::from(20i32));
- assert_eq!(_20, NumCast::from(20i64));
- assert_eq!(_20, NumCast::from(20f));
- assert_eq!(_20, NumCast::from(20f32));
- assert_eq!(_20, NumCast::from(20f64));
-
- assert_eq!(_20, cast(20u));
- assert_eq!(_20, cast(20u8));
- assert_eq!(_20, cast(20u16));
- assert_eq!(_20, cast(20u32));
- assert_eq!(_20, cast(20u64));
- assert_eq!(_20, cast(20i));
- assert_eq!(_20, cast(20i8));
- assert_eq!(_20, cast(20i16));
- assert_eq!(_20, cast(20i32));
- assert_eq!(_20, cast(20i64));
- assert_eq!(_20, cast(20f));
- assert_eq!(_20, cast(20f32));
- assert_eq!(_20, cast(20f64));
- })
-)
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ macro_rules! test_cast_20(
+ ($_20:expr) => ({
+ let _20 = $_20;
+
+ assert_eq!(20u, _20.to_uint());
+ assert_eq!(20u8, _20.to_u8());
+ assert_eq!(20u16, _20.to_u16());
+ assert_eq!(20u32, _20.to_u32());
+ assert_eq!(20u64, _20.to_u64());
+ assert_eq!(20i, _20.to_int());
+ assert_eq!(20i8, _20.to_i8());
+ assert_eq!(20i16, _20.to_i16());
+ assert_eq!(20i32, _20.to_i32());
+ assert_eq!(20i64, _20.to_i64());
+ assert_eq!(20f, _20.to_float());
+ assert_eq!(20f32, _20.to_f32());
+ assert_eq!(20f64, _20.to_f64());
+
+ assert_eq!(_20, NumCast::from(20u));
+ assert_eq!(_20, NumCast::from(20u8));
+ assert_eq!(_20, NumCast::from(20u16));
+ assert_eq!(_20, NumCast::from(20u32));
+ assert_eq!(_20, NumCast::from(20u64));
+ assert_eq!(_20, NumCast::from(20i));
+ assert_eq!(_20, NumCast::from(20i8));
+ assert_eq!(_20, NumCast::from(20i16));
+ assert_eq!(_20, NumCast::from(20i32));
+ assert_eq!(_20, NumCast::from(20i64));
+ assert_eq!(_20, NumCast::from(20f));
+ assert_eq!(_20, NumCast::from(20f32));
+ assert_eq!(_20, NumCast::from(20f64));
+
+ assert_eq!(_20, cast(20u));
+ assert_eq!(_20, cast(20u8));
+ assert_eq!(_20, cast(20u16));
+ assert_eq!(_20, cast(20u32));
+ assert_eq!(_20, cast(20u64));
+ assert_eq!(_20, cast(20i));
+ assert_eq!(_20, cast(20i8));
+ assert_eq!(_20, cast(20i16));
+ assert_eq!(_20, cast(20i32));
+ assert_eq!(_20, cast(20i64));
+ assert_eq!(_20, cast(20f));
+ assert_eq!(_20, cast(20f32));
+ assert_eq!(_20, cast(20f64));
+ })
+ )
+
+ #[test] fn test_u8_cast() { test_cast_20!(20u8) }
+ #[test] fn test_u16_cast() { test_cast_20!(20u16) }
+ #[test] fn test_u32_cast() { test_cast_20!(20u32) }
+ #[test] fn test_u64_cast() { test_cast_20!(20u64) }
+ #[test] fn test_uint_cast() { test_cast_20!(20u) }
+ #[test] fn test_i8_cast() { test_cast_20!(20i8) }
+ #[test] fn test_i16_cast() { test_cast_20!(20i16) }
+ #[test] fn test_i32_cast() { test_cast_20!(20i32) }
+ #[test] fn test_i64_cast() { test_cast_20!(20i64) }
+ #[test] fn test_int_cast() { test_cast_20!(20i) }
+ #[test] fn test_f32_cast() { test_cast_20!(20f32) }
+ #[test] fn test_f64_cast() { test_cast_20!(20f64) }
+ #[test] fn test_float_cast() { test_cast_20!(20f) }
+
+ #[test]
+ fn test_saturating_add_uint() {
+ use uint::max_value;
+ assert_eq!(3u.saturating_add(5u), 8u);
+ assert_eq!(3u.saturating_add(max_value-1), max_value);
+ assert_eq!(max_value.saturating_add(max_value), max_value);
+ assert_eq!((max_value-2).saturating_add(1), max_value-1);
+ }
+
+ #[test]
+ fn test_saturating_sub_uint() {
+ use uint::max_value;
+ assert_eq!(5u.saturating_sub(3u), 2u);
+ assert_eq!(3u.saturating_sub(5u), 0u);
+ assert_eq!(0u.saturating_sub(1u), 0u);
+ assert_eq!((max_value-1).saturating_sub(max_value), 0);
+ }
-#[test] fn test_u8_cast() { test_cast_20!(20u8) }
-#[test] fn test_u16_cast() { test_cast_20!(20u16) }
-#[test] fn test_u32_cast() { test_cast_20!(20u32) }
-#[test] fn test_u64_cast() { test_cast_20!(20u64) }
-#[test] fn test_uint_cast() { test_cast_20!(20u) }
-#[test] fn test_i8_cast() { test_cast_20!(20i8) }
-#[test] fn test_i16_cast() { test_cast_20!(20i16) }
-#[test] fn test_i32_cast() { test_cast_20!(20i32) }
-#[test] fn test_i64_cast() { test_cast_20!(20i64) }
-#[test] fn test_int_cast() { test_cast_20!(20i) }
-#[test] fn test_f32_cast() { test_cast_20!(20f32) }
-#[test] fn test_f64_cast() { test_cast_20!(20f64) }
-#[test] fn test_float_cast() { test_cast_20!(20f) }
+ #[test]
+ fn test_saturating_add_int() {
+ use int::{min_value,max_value};
+ assert_eq!(3i.saturating_add(5i), 8i);
+ assert_eq!(3i.saturating_add(max_value-1), max_value);
+ assert_eq!(max_value.saturating_add(max_value), max_value);
+ assert_eq!((max_value-2).saturating_add(1), max_value-1);
+ assert_eq!(3i.saturating_add(-5i), -2i);
+ assert_eq!(min_value.saturating_add(-1i), min_value);
+ assert_eq!((-2i).saturating_add(-max_value), min_value);
+ }
+
+ #[test]
+ fn test_saturating_sub_int() {
+ use int::{min_value,max_value};
+ assert_eq!(3i.saturating_sub(5i), -2i);
+ assert_eq!(min_value.saturating_sub(1i), min_value);
+ assert_eq!((-2i).saturating_sub(max_value), min_value);
+ assert_eq!(3i.saturating_sub(-5i), 8i);
+ assert_eq!(3i.saturating_sub(-(max_value-1)), max_value);
+ assert_eq!(max_value.saturating_sub(-max_value), max_value);
+ assert_eq!((max_value-2).saturating_sub(-1), max_value-1);
+ }
+}
//! Operations on unique pointer types
-#[cfg(not(test))] use cmp::{Eq, Ord};
+#[cfg(not(test))] use cmp::*;
#[cfg(not(test))]
impl<T:Eq> Eq for ~T {
#[inline]
fn gt(&self, other: &~T) -> bool { *(*self) > *(*other) }
}
+
+#[cfg(not(test))]
+impl<T: TotalOrd> TotalOrd for ~T {
+ #[inline]
+ fn cmp(&self, other: &~T) -> Ordering { (**self).cmp(*other) }
+}
+
+#[cfg(not(test))]
+impl<T: TotalEq> TotalEq for ~T {
+ #[inline]
+ fn equals(&self, other: &~T) -> bool { (**self).equals(*other) }
+}
//! Some various other I/O types
-// NOTE: These ultimately belong somewhere else
+// FIXME(#3660): should move to libextra
use prelude::*;
use super::*;
/// Create a blocked task, unless the task was already killed.
pub fn try_block(mut task: ~Task) -> Either<~Task, BlockedTask> {
+ // NB: As an optimization, we could give a free pass to being unkillable
+ // to tasks whose taskgroups haven't been initialized yet, but that
+ // introduces complications with select() and with the test cases below,
+ // and it's not clear the uncommon performance boost is worth it.
if task.death.unkillable > 0 {
Right(Unkillable(task))
} else {
let flag_arc = match task.death.spare_kill_flag.take() {
Some(spare_flag) => spare_flag,
None => {
- // FIXME(#7544): Uncomment this when terminate_current_task
- // stops being *terrible*. That's the only place that violates
- // the assumption of "becoming unkillable will fail if the
- // task was killed".
- // rtassert!(task.unwinder.unwinding);
+ // A task that kills us won't have a spare kill flag to
+ // give back to us, so we restore it ourselves here. This
+ // situation should only arise when we're already failing.
+ rtassert!(task.unwinder.unwinding);
(*task.death.kill_handle.get_ref().get()).killed.clone()
}
};
/// If begin is greater than end.
/// If end is greater than the length of the string.
#[inline]
- pub unsafe fn slice_bytes(s: &str, begin: uint, end: uint) -> &str {
+ pub unsafe fn slice_bytes<'a>(s: &'a str, begin: uint, end: uint) -> &'a str {
do s.as_imm_buf |sbuf, n| {
assert!((begin <= end));
assert!((end <= n));
use to_str::{ToStr,ToStrConsume};
use str;
use str::StrSlice;
+use str::OwnedStr;
+use container::Container;
use cast;
+use ptr;
use iterator::{Iterator, IteratorUtil};
use vec::{CopyableVector, ImmutableVector, OwnedVector};
use to_bytes::IterBytes;
/// Convert to lowercase.
#[inline]
pub fn to_lower(self) -> Ascii {
- if self.chr >= 65 && self.chr <= 90 {
- Ascii{chr: self.chr | 0x20 }
- } else {
- self
- }
+ Ascii{chr: ASCII_LOWER_MAP[self.chr]}
}
/// Convert to uppercase.
#[inline]
pub fn to_upper(self) -> Ascii {
- if self.chr >= 97 && self.chr <= 122 {
- Ascii{chr: self.chr & !0x20 }
- } else {
- self
- }
+ Ascii{chr: ASCII_UPPER_MAP[self.chr]}
}
/// Compares two ascii characters of equality, ignoring case.
#[inline]
pub fn eq_ignore_case(self, other: Ascii) -> bool {
- self.to_lower().chr == other.to_lower().chr
+ ASCII_LOWER_MAP[self.chr] == ASCII_LOWER_MAP[other.chr]
}
}
}
}
+
+/// Convert the string to ASCII upper case:
+/// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
+/// but non-ASCII letters are unchanged.
+#[inline]
+pub fn to_ascii_upper(string: &str) -> ~str {
+ map_bytes(string, ASCII_UPPER_MAP)
+}
+
+/// Convert the string to ASCII lower case:
+/// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
+/// but non-ASCII letters are unchanged.
+#[inline]
+pub fn to_ascii_lower(string: &str) -> ~str {
+ map_bytes(string, ASCII_LOWER_MAP)
+}
+
+#[inline]
+priv fn map_bytes(string: &str, map: &'static [u8]) -> ~str {
+ let len = string.len();
+ let mut result = str::with_capacity(len);
+ unsafe {
+ do result.as_mut_buf |mut buf, _| {
+ for c in string.as_bytes().iter() {
+ *buf = map[*c];
+ buf = ptr::mut_offset(buf, 1)
+ }
+ }
+ str::raw::set_len(&mut result, len);
+ }
+ result
+}
+
+/// Check that two strings are an ASCII case-insensitive match.
+/// Same as `to_ascii_lower(a) == to_ascii_lower(b)`,
+/// but without allocating and copying temporary strings.
+#[inline]
+pub fn eq_ignore_ascii_case(a: &str, b: &str) -> bool {
+ a.len() == b.len() && a.as_bytes().iter().zip(b.as_bytes().iter()).all(
+ |(byte_a, byte_b)| ASCII_LOWER_MAP[*byte_a] == ASCII_LOWER_MAP[*byte_b])
+}
+
+priv static ASCII_LOWER_MAP: &'static [u8] = &[
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+];
+
+priv static ASCII_UPPER_MAP: &'static [u8] = &[
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+];
+
+
#[cfg(test)]
mod tests {
use super::*;
use to_bytes::ToBytes;
+ use str::from_char;
macro_rules! v2ascii (
( [$($e:expr),*]) => ( [$(Ascii{chr:$e}),*]);
#[test] #[should_fail]
fn test_ascii_fail_char_slice() { 'λ'.to_ascii(); }
+
+ #[test]
+ fn test_to_ascii_upper() {
+ assert_eq!(to_ascii_upper("url()URL()uRl()ürl"), ~"URL()URL()URL()üRL");
+ assert_eq!(to_ascii_upper("hıKß"), ~"HıKß");
+
+ let mut i = 0;
+ while i <= 500 {
+ let c = i as char;
+ let upper = if 'a' <= c && c <= 'z' { c + 'A' - 'a' } else { c };
+ assert_eq!(to_ascii_upper(from_char(i as char)), from_char(upper))
+ i += 1;
+ }
+ }
+
+ #[test]
+ fn test_to_ascii_lower() {
+ assert_eq!(to_ascii_lower("url()URL()uRl()Ürl"), ~"url()url()url()Ürl");
+ // Dotted capital I, Kelvin sign, Sharp S.
+ assert_eq!(to_ascii_lower("HİKß"), ~"hİKß");
+
+ let mut i = 0;
+ while i <= 500 {
+ let c = i as char;
+ let lower = if 'A' <= c && c <= 'Z' { c + 'a' - 'A' } else { c };
+ assert_eq!(to_ascii_lower(from_char(i as char)), from_char(lower))
+ i += 1;
+ }
+ }
+
+
+ #[test]
+ fn test_eq_ignore_ascii_case() {
+ assert!(eq_ignore_ascii_case("url()URL()uRl()Ürl", "url()url()url()Ürl"));
+ assert!(!eq_ignore_ascii_case("Ürl", "ürl"));
+ // Dotted capital I, Kelvin sign, Sharp S.
+ assert!(eq_ignore_ascii_case("HİKß", "hİKß"));
+ assert!(!eq_ignore_ascii_case("İ", "i"));
+ assert!(!eq_ignore_ascii_case("K", "k"));
+ assert!(!eq_ignore_ascii_case("ß", "s"));
+
+ let mut i = 0;
+ while i <= 500 {
+ let c = i as char;
+ let lower = if 'A' <= c && c <= 'Z' { c + 'a' - 'A' } else { c };
+ assert!(eq_ignore_ascii_case(from_char(i as char), from_char(lower)));
+ i += 1;
+ }
+ }
}
let me = Local::unsafe_borrow::<Task>();
blk(match (*me).taskgroup {
None => {
- // Main task, doing first spawn ever. Lazily initialize.
+ // First task in its (unlinked/unsupervised) taskgroup.
+ // Lazily initialize.
let mut members = TaskSet::new();
let my_handle = (*me).death.kill_handle.get_ref().clone();
members.insert(NewTask(my_handle));
}
}
+// Returns 'None' in the case where the child's TG should be lazily initialized.
fn gen_child_taskgroup(linked: bool, supervised: bool)
- -> (TaskGroupArc, AncestorList, bool) {
- do RuntimeGlue::with_my_taskgroup |spawner_group| {
- let ancestors = AncestorList(spawner_group.ancestors.map(|x| x.clone()));
- if linked {
- // Child is in the same group as spawner.
- // Child's ancestors are spawner's ancestors.
- // Propagate main-ness.
- (spawner_group.tasks.clone(), ancestors, spawner_group.is_main)
- } else {
- // Child is in a separate group from spawner.
- let g = Exclusive::new(Some(TaskGroupData {
- members: TaskSet::new(),
- descendants: TaskSet::new(),
- }));
- let a = if supervised {
- let new_generation = incr_generation(&ancestors);
- assert!(new_generation < uint::max_value);
- // Child's ancestors start with the spawner.
- // Build a new node in the ancestor list.
- AncestorList(Some(Exclusive::new(AncestorNode {
- generation: new_generation,
- parent_group: spawner_group.tasks.clone(),
- ancestors: ancestors,
- })))
+ -> Option<(TaskGroupArc, AncestorList, bool)> {
+ // FIXME(#7544): Not safe to lazily initialize in the old runtime. Remove
+ // this context check once 'spawn_raw_oldsched' is gone.
+ if context() == OldTaskContext || linked || supervised {
+ // with_my_taskgroup will lazily initialize the parent's taskgroup if
+ // it doesn't yet exist. We don't want to call it in the unlinked case.
+ do RuntimeGlue::with_my_taskgroup |spawner_group| {
+ let ancestors = AncestorList(spawner_group.ancestors.map(|x| x.clone()));
+ if linked {
+ // Child is in the same group as spawner.
+ // Child's ancestors are spawner's ancestors.
+ // Propagate main-ness.
+ Some((spawner_group.tasks.clone(), ancestors, spawner_group.is_main))
} else {
- // Child has no ancestors.
- AncestorList(None)
- };
- (g, a, false)
+ // Child is in a separate group from spawner.
+ let g = Exclusive::new(Some(TaskGroupData {
+ members: TaskSet::new(),
+ descendants: TaskSet::new(),
+ }));
+ let a = if supervised {
+ let new_generation = incr_generation(&ancestors);
+ assert!(new_generation < uint::max_value);
+ // Child's ancestors start with the spawner.
+ // Build a new node in the ancestor list.
+ AncestorList(Some(Exclusive::new(AncestorNode {
+ generation: new_generation,
+ parent_group: spawner_group.tasks.clone(),
+ ancestors: ancestors,
+ })))
+ } else {
+ // Child has no ancestors.
+ AncestorList(None)
+ };
+ Some((g, a, false))
+ }
}
+ } else {
+ None
}
}
let child_wrapper: ~fn() = || {
// Child task runs this code.
- let child_data = Cell::new(child_data.take()); // :(
- let enlist_success = do Local::borrow::<Task, bool> |me| {
- let (child_tg, ancestors, is_main) = child_data.take();
- let mut ancestors = ancestors;
- // FIXME(#7544): Optimize out the xadd in this clone, somehow.
- let handle = me.death.kill_handle.get_ref().clone();
- // Atomically try to get into all of our taskgroups.
- if enlist_many(NewTask(handle), &child_tg, &mut ancestors) {
- // Got in. We can run the provided child body, and can also run
- // the taskgroup's exit-time-destructor afterward.
- me.taskgroup = Some(Taskgroup(child_tg, ancestors, is_main, None));
- true
- } else {
- false
+
+ // If child data is 'None', the enlist is vacuously successful.
+ let enlist_success = do child_data.take().map_consume_default(true) |child_data| {
+ let child_data = Cell::new(child_data); // :(
+ do Local::borrow::<Task, bool> |me| {
+ let (child_tg, ancestors, is_main) = child_data.take();
+ let mut ancestors = ancestors;
+ // FIXME(#7544): Optimize out the xadd in this clone, somehow.
+ let handle = me.death.kill_handle.get_ref().clone();
+ // Atomically try to get into all of our taskgroups.
+ if enlist_many(NewTask(handle), &child_tg, &mut ancestors) {
+ // Got in. We can run the provided child body, and can also run
+ // the taskgroup's exit-time-destructor afterward.
+ me.taskgroup = Some(Taskgroup(child_tg, ancestors, is_main, None));
+ true
+ } else {
+ false
+ }
}
};
// Should be run after the local-borrowed task is returned.
let join_task = join_task_cell.take();
let bootstrap_task = ~do Task::new_root(&mut new_sched.stack_pool) || {
- rtdebug!("boostraping a 1:1 scheduler");
+ rtdebug!("bootstrapping a 1:1 scheduler");
};
new_sched.bootstrap(bootstrap_task);
fn spawn_raw_oldsched(mut opts: TaskOpts, f: ~fn()) {
let (child_tg, ancestors, is_main) =
- gen_child_taskgroup(opts.linked, opts.supervised);
+ gen_child_taskgroup(opts.linked, opts.supervised).expect("old runtime needs TG");
unsafe {
let child_data = Cell::new((child_tg, ancestors, f));
Some(&node_local(ident)) => {
fmt!("local (id=%?, name=%s)", id, itr.get(ident.name))
}
- Some(&node_block(_)) => {
- fmt!("block")
+ Some(&node_block(ref block)) => {
+ fmt!("block %s (id=%?)", pprust::block_to_str(block, itr), id)
}
- Some(&node_struct_ctor(*)) => {
- fmt!("struct_ctor")
+ Some(&node_struct_ctor(_, _, path)) => {
+ fmt!("struct_ctor %s (id=%?)", path_to_str(*path, itr), id)
}
}
}
impl Visitor<()> for IdVisitor {
fn visit_mod(@mut self,
module: &_mod,
- span: span,
+ _span: span,
node_id: NodeId,
env: ()) {
(self.visit_callback)(node_id);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use ast;
use ast::{MetaItem, item, expr};
use codemap::span;
use ext::base::ExtCtxt;
}
-pub fn ordering_const(cx: @ExtCtxt, span: span, cnst: Ordering) -> @expr {
+pub fn ordering_const(cx: @ExtCtxt, span: span, cnst: Ordering) -> ast::Path {
let cnst = match cnst {
Less => "Less",
Equal => "Equal",
Greater => "Greater"
};
- cx.expr_path(
- cx.path_global(span,
- ~[cx.ident_of("std"),
- cx.ident_of("cmp"),
- cx.ident_of(cnst)]))
+ cx.path_global(span,
+ ~[cx.ident_of("std"),
+ cx.ident_of("cmp"),
+ cx.ident_of(cnst)])
}
pub fn cs_cmp(cx: @ExtCtxt, span: span,
substr: &Substructure) -> @expr {
+ let test_id = cx.ident_of("__test");
+ let equals_path = ordering_const(cx, span, Equal);
+ /*
+ Builds:
+
+ let __test = self_field1.cmp(&other_field2);
+ if other == ::std::cmp::Equal {
+ let __test = self_field2.cmp(&other_field2);
+ if __test == ::std::cmp::Equal {
+ ...
+ } else {
+ __test
+ }
+ } else {
+ __test
+ }
+
+ FIXME #6449: These `if`s could/should be `match`es.
+ */
cs_same_method_fold(
- // foldr (possibly) nests the matches in lexical_ordering better
+ // foldr nests the if-elses correctly, leaving the first field
+ // as the outermost one, and the last as the innermost.
false,
|cx, span, old, new| {
- cx.expr_call_global(span,
- ~[cx.ident_of("std"),
- cx.ident_of("cmp"),
- cx.ident_of("lexical_ordering")],
- ~[old, new])
+ // let __test = new;
+ // if __test == ::std::cmp::Equal {
+ // old
+ // } else {
+ // __test
+ // }
+
+ let assign = cx.stmt_let(span, false, test_id, new);
+
+ let cond = cx.expr_binary(span, ast::eq,
+ cx.expr_ident(span, test_id),
+ cx.expr_path(equals_path.clone()));
+ let if_ = cx.expr_if(span,
+ cond,
+ old, Some(cx.expr_ident(span, test_id)));
+ cx.expr_block(cx.block(span, ~[assign], Some(if_)))
},
- ordering_const(cx, span, Equal),
+ cx.expr_path(equals_path.clone()),
|cx, span, list, _| {
match list {
// an earlier nonmatching variant is Less than a
- // later one
+ // later one.
[(self_var, _, _),
- (other_var, _, _)] => ordering_const(cx, span,
- self_var.cmp(&other_var)),
+ (other_var, _, _)] => cx.expr_path(ordering_const(cx, span,
+ self_var.cmp(&other_var))),
_ => cx.span_bug(span, "Not exactly 2 arguments in `deriving(TotalOrd)`")
}
},
--- /dev/null
+// Copyright 2013 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.
+
+// check that the derived impls for the comparison traits shortcircuit
+// where possible, by having a type that fails when compared as the
+// second element, so this passes iff the instances shortcircuit.
+
+pub struct FailCmp;
+impl Eq for FailCmp {
+ fn eq(&self, _: &FailCmp) -> bool { fail!("eq") }
+}
+
+impl Ord for FailCmp {
+ fn lt(&self, _: &FailCmp) -> bool { fail!("lt") }
+}
+
+impl TotalEq for FailCmp {
+ fn equals(&self, _: &FailCmp) -> bool { fail!("equals") }
+}
+
+impl TotalOrd for FailCmp {
+ fn cmp(&self, _: &FailCmp) -> Ordering { fail!("cmp") }
+}
+
+#[deriving(Eq,Ord,TotalEq,TotalOrd)]
+struct ShortCircuit {
+ x: int,
+ y: FailCmp
+}
+
+fn main() {
+ let a = ShortCircuit { x: 1, y: FailCmp };
+ let b = ShortCircuit { x: 2, y: FailCmp };
+
+ assert!(a != b);
+ assert!(a < b);
+ assert!(!a.equals(&b));
+ assert_eq!(a.cmp(&b), ::std::cmp::Less);
+}