diff --git a/Makefile.in b/Makefile.in index d78176e5699..a9a41a073d0 100644 --- a/Makefile.in +++ b/Makefile.in @@ -297,7 +297,7 @@ COMPILER_INPUTS := $(wildcard $(addprefix $(S)src/librustc/, \ 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 diff --git a/doc/tutorial-tasks.md b/doc/tutorial-tasks.md index b2ef624d1ac..b5677a261c4 100644 --- a/doc/tutorial-tasks.md +++ b/doc/tutorial-tasks.md @@ -544,7 +544,7 @@ an intermediate generation has already exited: ~~~ # use std::task; # fn sleep_forever() { loop { task::yield() } } -# fn wait_for_a_while() { do 1000.times { task::yield() } } +# fn wait_for_a_while() { for _ in range(0, 1000u) { task::yield() } } # do task::try:: { do task::spawn_supervised { do task::spawn_supervised { @@ -563,7 +563,7 @@ other at all, using `task::spawn_unlinked` for _isolated failure_. ~~~ # use std::task; # fn random() -> uint { 100 } -# fn sleep_for(i: uint) { do i.times { task::yield() } } +# fn sleep_for(i: uint) { for _ in range(0, i) { task::yield() } } # do task::try::<()> { let (time1, time2) = (random(), random()); do task::spawn_unlinked { diff --git a/doc/tutorial.md b/doc/tutorial.md index a5f2001eaf5..6e6b804aa9d 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -1894,7 +1894,7 @@ struct TimeBomb { impl Drop for TimeBomb { fn drop(&self) { - do self.explosivity.times { + for _ in range(0, self.explosivity) { println("blam!"); } } diff --git a/src/libextra/base64.rs b/src/libextra/base64.rs index 550b891a4db..b4431004bd7 100644 --- a/src/libextra/base64.rs +++ b/src/libextra/base64.rs @@ -9,6 +9,7 @@ // except according to those terms. //! Base64 binary-to-text encoding +use std::str; /// Available encoding character sets pub enum CharacterSet { @@ -40,21 +41,13 @@ pub static URL_SAFE: Config = 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 STANDARD_CHARS: &'static[u8] = bytes!("ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "abcdefghijklmnopqrstuvwxyz", + "0123456789+/"); -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 URLSAFE_CHARS: &'static[u8] = bytes!("ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "abcdefghijklmnopqrstuvwxyz", + "0123456789-_"); /// A trait for converting a value to base64 encoding. pub trait ToBase64 { @@ -80,12 +73,12 @@ impl<'self> ToBase64 for &'self [u8] { * ~~~ */ 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(); @@ -93,7 +86,8 @@ impl<'self> ToBase64 for &'self [u8] { 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 => () @@ -104,10 +98,10 @@ impl<'self> ToBase64 for &'self [u8] { (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; @@ -117,7 +111,8 @@ impl<'self> ToBase64 for &'self [u8] { 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 => () } @@ -129,48 +124,29 @@ impl<'self> ToBase64 for &'self [u8] { 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) + } } } @@ -181,76 +157,6 @@ pub trait FromBase64 { fn from_base64(&self) -> Result<~[u8], ~str>; } -impl<'self> FromBase64 for &'self [u8] { - /** - * Convert base64 `u8` vector into u8 byte values. - * Every 4 encoded characters is converted into 3 octets, modulo padding. - * - * # Example - * - * ~~~ {.rust} - * extern mod extra; - * use extra::base64::{ToBase64, FromBase64, standard}; - * - * fn main () { - * let str = [52,32].to_base64(standard); - * printfln!("%s", str); - * let bytes = str.from_base64(); - * printfln!("%?", bytes); - * } - * ~~~ - */ - fn from_base64(&self) -> Result<~[u8], ~str> { - let mut r = ~[]; - let mut buf: u32 = 0; - let mut modulus = 0; - - let mut it = self.iter(); - for &byte in it { - let ch = byte as char; - let val = byte as u32; - - match ch { - 'A'..'Z' => buf |= val - 0x41, - 'a'..'z' => buf |= val - 0x47, - '0'..'9' => buf |= val + 0x04, - '+'|'-' => buf |= 0x3E, - '/'|'_' => buf |= 0x3F, - '\r'|'\n' => loop, - '=' => break, - _ => return Err(~"Invalid Base64 character") - } - - buf <<= 6; - modulus += 1; - if modulus == 4 { - modulus = 0; - r.push((buf >> 22) as u8); - r.push((buf >> 14) as u8); - r.push((buf >> 6 ) as u8); - } - } - - if !it.all(|&byte| {byte as char == '='}) { - return Err(~"Invalid Base64 character"); - } - - match modulus { - 2 => { - r.push((buf >> 10) as u8); - } - 3 => { - r.push((buf >> 16) as u8); - r.push((buf >> 8 ) as u8); - } - 0 => (), - _ => return Err(~"Invalid Base64 length") - } - - Ok(r) - } -} - impl<'self> FromBase64 for &'self str { /** * Convert any base64 encoded string (literal, `@`, `&`, or `~`) @@ -280,7 +186,56 @@ impl<'self> FromBase64 for &'self str { * ~~~ */ fn from_base64(&self) -> Result<~[u8], ~str> { - self.as_bytes().from_base64() + let mut r = ~[]; + let mut buf: u32 = 0; + let mut modulus = 0; + + let mut it = self.byte_iter().enumerate(); + for (idx, byte) in it { + let val = byte as u32; + + match byte as char { + 'A'..'Z' => buf |= val - 0x41, + 'a'..'z' => buf |= val - 0x47, + '0'..'9' => buf |= val + 0x04, + '+'|'-' => buf |= 0x3E, + '/'|'_' => buf |= 0x3F, + '\r'|'\n' => loop, + '=' => break, + _ => return Err(fmt!("Invalid character '%c' at position %u", + self.char_at(idx), idx)) + } + + buf <<= 6; + modulus += 1; + if modulus == 4 { + modulus = 0; + r.push((buf >> 22) as u8); + r.push((buf >> 14) as u8); + r.push((buf >> 6 ) as u8); + } + } + + 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 { + 2 => { + r.push((buf >> 10) as u8); + } + 3 => { + r.push((buf >> 16) as u8); + r.push((buf >> 8 ) as u8); + } + 0 => (), + _ => return Err(~"Invalid Base64 length") + } + + Ok(r) } } @@ -291,27 +246,28 @@ mod test { #[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] @@ -345,7 +301,7 @@ mod 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] @@ -369,20 +325,20 @@ mod 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(); } diff --git a/src/libextra/extra.rs b/src/libextra/extra.rs index 58929778a59..44781a1fd19 100644 --- a/src/libextra/extra.rs +++ b/src/libextra/extra.rs @@ -102,6 +102,7 @@ pub mod stats; pub mod semver; pub mod fileinput; pub mod flate; +pub mod hex; #[cfg(unicode)] mod unicode; diff --git a/src/libextra/hex.rs b/src/libextra/hex.rs new file mode 100644 index 00000000000..d5345cb956b --- /dev/null +++ b/src/libextra/hex.rs @@ -0,0 +1,193 @@ +// 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 or the MIT license +// , 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; + } +} diff --git a/src/libextra/iter.rs b/src/libextra/iter.rs deleted file mode 100644 index 7fd47fdbd39..00000000000 --- a/src/libextra/iter.rs +++ /dev/null @@ -1,331 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! Composable internal iterators - -Internal iterators are functions implementing the protocol used by the `for` loop. - -An internal iterator takes `fn(...) -> bool` as a parameter, with returning `false` used to signal -breaking out of iteration. The adaptors in the module work with any such iterator, not just ones -tied to specific traits. For example: - -~~~ {.rust} -println(iter::to_vec(|f| uint::range(0, 20, f)).to_str()); -~~~ - -An external iterator object implementing the interface in the `iterator` module can be used as an -internal iterator by calling the `advance` method. For example: - -~~~ {.rust} -let xs = [0u, 1, 2, 3, 4, 5]; -let ys = [30, 40, 50, 60]; -let mut it = xs.iter().chain(ys.iter()); -for &x: &uint in it { - println(x.to_str()); -} -~~~ - -Internal iterators provide a subset of the functionality of an external iterator. It's not possible -to interleave them to implement algorithms like `zip`, `union` and `merge`. However, they're often -much easier to implement. - -*/ - -use std::vec; -use std::cmp::Ord; -use std::option::{Option, Some, None}; -use std::num::{One, Zero}; -use std::ops::{Add, Mul}; - -#[allow(missing_doc)] -pub trait FromIter { - /// Build a container with elements from an internal iterator. - /// - /// # Example: - /// - /// ~~~ {.rust} - /// let xs = ~[1, 2, 3]; - /// let ys: ~[int] = do FromIter::from_iter |f| { xs.iter().advance(|x| f(*x)) }; - /// assert_eq!(xs, ys); - /// ~~~ - pub fn from_iter(iter: &fn(f: &fn(T) -> bool) -> bool) -> Self; -} - -/** - * Return true if `predicate` is true for any values yielded by an internal iterator. - * - * Example: - * - * ~~~ {.rust} - * let xs = ~[1u, 2, 3, 4, 5]; - * assert!(any(|&x: &uint| x > 2, |f| xs.iter().advance(f))); - * assert!(!any(|&x: &uint| x > 5, |f| xs.iter().advance(f))); - * ~~~ - */ -#[inline] -pub fn any(predicate: &fn(T) -> bool, - iter: &fn(f: &fn(T) -> bool) -> bool) -> bool { - do iter |x| { - predicate(x) - } -} - -/** - * Return true if `predicate` is true for all values yielded by an internal iterator. - * - * # Example: - * - * ~~~ {.rust} - * assert!(all(|&x: &uint| x < 6, |f| uint::range(1, 6, f))); - * assert!(!all(|&x: &uint| x < 5, |f| uint::range(1, 6, f))); - * ~~~ - */ -#[inline] -pub fn all(predicate: &fn(T) -> bool, - iter: &fn(f: &fn(T) -> bool) -> bool) -> bool { - // If we ever break, iter will return false, so this will only return true - // if predicate returns true for everything. - iter(|x| predicate(x)) -} - -/** - * Return the first element where `predicate` returns `true`. Return `None` if no element is found. - * - * # Example: - * - * ~~~ {.rust} - * let xs = ~[1u, 2, 3, 4, 5, 6]; - * assert_eq!(*find(|& &x: & &uint| x > 3, |f| xs.iter().advance(f)).unwrap(), 4); - * ~~~ - */ -#[inline] -pub fn find(predicate: &fn(&T) -> bool, - iter: &fn(f: &fn(T) -> bool) -> bool) -> Option { - let mut ret = None; - do iter |x| { - if predicate(&x) { - ret = Some(x); - false - } else { true } - }; - ret -} - -/** - * Return the largest item yielded by an iterator. Return `None` if the iterator is empty. - * - * # Example: - * - * ~~~ {.rust} - * let xs = ~[8, 2, 3, 1, -5, 9, 11, 15]; - * assert_eq!(max(|f| xs.iter().advance(f)).unwrap(), &15); - * ~~~ - */ -#[inline] -pub fn max(iter: &fn(f: &fn(T) -> bool) -> bool) -> Option { - let mut result = None; - do iter |x| { - match result { - Some(ref mut y) => { - if x > *y { - *y = x; - } - } - None => result = Some(x) - } - true - }; - result -} - -/** - * Return the smallest item yielded by an iterator. Return `None` if the iterator is empty. - * - * # Example: - * - * ~~~ {.rust} - * let xs = ~[8, 2, 3, 1, -5, 9, 11, 15]; - * assert_eq!(max(|f| xs.iter().advance(f)).unwrap(), &-5); - * ~~~ - */ -#[inline] -pub fn min(iter: &fn(f: &fn(T) -> bool) -> bool) -> Option { - let mut result = None; - do iter |x| { - match result { - Some(ref mut y) => { - if x < *y { - *y = x; - } - } - None => result = Some(x) - } - true - }; - result -} - -/** - * Reduce an iterator to an accumulated value. - * - * # Example: - * - * ~~~ {.rust} - * assert_eq!(fold(0i, |f| int::range(1, 5, f), |a, x| *a += x), 10); - * ~~~ - */ -#[inline] -pub fn fold(start: T, iter: &fn(f: &fn(U) -> bool) -> bool, f: &fn(&mut T, U)) -> T { - let mut result = start; - do iter |x| { - f(&mut result, x); - true - }; - result -} - -/** - * Reduce an iterator to an accumulated value. - * - * `fold_ref` is usable in some generic functions where `fold` is too lenient to type-check, but it - * forces the iterator to yield borrowed pointers. - * - * # Example: - * - * ~~~ {.rust} - * fn product>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T { - * fold_ref(One::one::(), iter, |a, x| *a = a.mul(x)) - * } - * ~~~ - */ -#[inline] -pub fn fold_ref(start: T, iter: &fn(f: &fn(&U) -> bool) -> bool, f: &fn(&mut T, &U)) -> T { - let mut result = start; - do iter |x| { - f(&mut result, x); - true - }; - result -} - -/** - * Return the sum of the items yielding by an iterator. - * - * # Example: - * - * ~~~ {.rust} - * let xs: ~[int] = ~[1, 2, 3, 4]; - * assert_eq!(do sum |f| { xs.iter().advance(f) }, 10); - * ~~~ - */ -#[inline] -pub fn sum>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T { - fold_ref(Zero::zero::(), iter, |a, x| *a = a.add(x)) -} - -/** - * Return the product of the items yielded by an iterator. - * - * # Example: - * - * ~~~ {.rust} - * let xs: ~[int] = ~[1, 2, 3, 4]; - * assert_eq!(do product |f| { xs.iter().advance(f) }, 24); - * ~~~ - */ -#[inline] -pub fn product>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T { - fold_ref(One::one::(), iter, |a, x| *a = a.mul(x)) -} - -impl FromIter for ~[T]{ - #[inline] - pub fn from_iter(iter: &fn(f: &fn(T) -> bool) -> bool) -> ~[T] { - let mut v = ~[]; - do iter |x| { v.push(x); true }; - v - } -} - -#[cfg(test)] -mod tests { - use super::*; - use prelude::*; - - use int; - use uint; - - #[test] - fn test_from_iter() { - let xs = ~[1, 2, 3]; - let ys: ~[int] = do FromIter::from_iter |f| { xs.iter().advance(|x| f(*x)) }; - assert_eq!(xs, ys); - } - - #[test] - fn test_any() { - let xs = ~[1u, 2, 3, 4, 5]; - assert!(any(|&x: &uint| x > 2, |f| xs.iter().advance(f))); - assert!(!any(|&x: &uint| x > 5, |f| xs.iter().advance(f))); - } - - #[test] - fn test_all() { - assert!(all(|x: uint| x < 6, |f| uint::range(1, 6, f))); - assert!(!all(|x: uint| x < 5, |f| uint::range(1, 6, f))); - } - - #[test] - fn test_find() { - let xs = ~[1u, 2, 3, 4, 5, 6]; - assert_eq!(*find(|& &x: & &uint| x > 3, |f| xs.iter().advance(f)).unwrap(), 4); - } - - #[test] - fn test_max() { - let xs = ~[8, 2, 3, 1, -5, 9, 11, 15]; - assert_eq!(max(|f| xs.iter().advance(f)).unwrap(), &15); - } - - #[test] - fn test_min() { - let xs = ~[8, 2, 3, 1, -5, 9, 11, 15]; - assert_eq!(min(|f| xs.iter().advance(f)).unwrap(), &-5); - } - - #[test] - fn test_fold() { - assert_eq!(fold(0i, |f| int::range(1, 5, f), |a, x| *a += x), 10); - } - - #[test] - fn test_sum() { - let xs: ~[int] = ~[1, 2, 3, 4]; - assert_eq!(do sum |f| { xs.iter().advance(f) }, 10); - } - - #[test] - fn test_empty_sum() { - let xs: ~[int] = ~[]; - assert_eq!(do sum |f| { xs.iter().advance(f) }, 0); - } - - #[test] - fn test_product() { - let xs: ~[int] = ~[1, 2, 3, 4]; - assert_eq!(do product |f| { xs.iter().advance(f) }, 24); - } - - #[test] - fn test_empty_product() { - let xs: ~[int] = ~[]; - assert_eq!(do product |f| { xs.iter().advance(f) }, 1); - } -} diff --git a/src/libextra/ringbuf.rs b/src/libextra/ringbuf.rs index 9833bd5d1cb..da8089250b3 100644 --- a/src/libextra/ringbuf.rs +++ b/src/libextra/ringbuf.rs @@ -696,7 +696,7 @@ mod tests { let u: ~[int] = deq.iter().transform(|&x| x).collect(); assert_eq!(u, v); - let mut seq = iterator::Counter::new(0u, 2).take_(256); + let mut seq = iterator::count(0u, 2).take_(256); let deq: RingBuf = seq.collect(); for (i, &x) in deq.iter().enumerate() { assert_eq!(2*i, x); diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 5153296337d..b1e600b9d73 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -888,6 +888,11 @@ pub fn trans_intrinsic(ccx: @mut CrateContext, let offset = get_param(decl, first_real_arg + 1); Ret(bcx, GEP(bcx, ptr, [offset])); } + "offset_inbounds" => { + let ptr = get_param(decl, first_real_arg); + let offset = get_param(decl, first_real_arg + 1); + Ret(bcx, InBoundsGEP(bcx, ptr, [offset])); + } "memcpy32" => memcpy_intrinsic(bcx, "llvm.memcpy.p0i8.p0i8.i32", substs.tys[0], 32), "memcpy64" => memcpy_intrinsic(bcx, "llvm.memcpy.p0i8.p0i8.i64", substs.tys[0], 64), "memmove32" => memcpy_intrinsic(bcx, "llvm.memmove.p0i8.p0i8.i32", substs.tys[0], 32), diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs index 42d5527ee43..ad83286c8c1 100644 --- a/src/librustc/middle/trans/type_use.rs +++ b/src/librustc/middle/trans/type_use.rs @@ -148,7 +148,8 @@ pub fn type_uses_for(ccx: @mut CrateContext, fn_id: def_id, n_tps: uint) "visit_tydesc" | "forget" | "frame_address" | "morestack_addr" => 0, - "offset" | "memcpy32" | "memcpy64" | "memmove32" | "memmove64" | + "offset" | "offset_inbounds" | + "memcpy32" | "memcpy64" | "memmove32" | "memmove64" | "memset32" | "memset64" => use_repr, "sqrtf32" | "sqrtf64" | "powif32" | "powif64" | diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index ea8a11fc7b3..8623ee546d6 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -3481,6 +3481,20 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { mutbl: ast::m_imm })) } + "offset_inbounds" => { + (1, + ~[ + ty::mk_ptr(tcx, ty::mt { + ty: param(ccx, 0), + mutbl: ast::m_imm + }), + ty::mk_int() + ], + ty::mk_ptr(tcx, ty::mt { + ty: param(ccx, 0), + mutbl: ast::m_imm + })) + } "memcpy32" => { (1, ~[ diff --git a/src/librustdoc/markdown_pass.rs b/src/librustdoc/markdown_pass.rs index 85c360a9e0d..f05c59083f4 100644 --- a/src/librustdoc/markdown_pass.rs +++ b/src/librustdoc/markdown_pass.rs @@ -637,7 +637,7 @@ mod test { let doc = (page_pass::mk_pass(config::DocPerMod).f)(srv, doc); write_markdown(doc, writer_factory); // We expect two pages to have been written - do 2.times { + for _ in range(0, 2u) { po.recv(); } } @@ -649,7 +649,7 @@ mod test { ~"#[link(name = \"core\")]; mod a { }"); let doc = (page_pass::mk_pass(config::DocPerMod).f)(srv, doc); write_markdown(doc, writer_factory); - do 2.times { + for _ in range(0, 2u) { let (page, markdown) = po.recv(); match page { doc::CratePage(_) => { diff --git a/src/librusti/rusti.rs b/src/librusti/rusti.rs index 86290ea65b5..5d5518997f6 100644 --- a/src/librusti/rusti.rs +++ b/src/librusti/rusti.rs @@ -565,7 +565,10 @@ mod tests { } } - #[cfg(not(target_word_size = "32"))] + // 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)] fn run_program(prog: &str) { let mut r = repl(); for cmd in prog.split_iter('\n') { @@ -574,9 +577,6 @@ mod tests { "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] @@ -594,12 +594,13 @@ mod tests { run_program("let a = 3;"); } - #[test] + #[test] #[ignore] fn new_tasks() { + // XXX: can't spawn new tasks because the JIT code is cleaned up + // after the main function is done. run_program(" - use std::task::try; - try( || println(\"Please don't segfault\") ); - do try { println(\"Please?\"); } + spawn( || println(\"Please don't segfault\") ); + do spawn { println(\"Please?\"); } "); } diff --git a/src/libstd/borrow.rs b/src/libstd/borrow.rs index 9e3a3a28fe8..6c3d4c5f1fb 100644 --- a/src/libstd/borrow.rs +++ b/src/libstd/borrow.rs @@ -58,3 +58,15 @@ impl<'self, T: Ord> Ord for &'self T { *(*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) } +} diff --git a/src/libstd/cmp.rs b/src/libstd/cmp.rs index 43a632562b2..b66f89e8341 100644 --- a/src/libstd/cmp.rs +++ b/src/libstd/cmp.rs @@ -153,7 +153,6 @@ pub fn cmp2( 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 { diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index 56a0dca5667..1be398966bb 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -18,7 +18,7 @@ implementing the `Iterator` trait. */ use cmp; -use num::{Zero, One}; +use num::{Zero, One, Saturating}; use option::{Option, Some, None}; use ops::{Add, Mul}; use cmp::Ord; @@ -313,7 +313,7 @@ pub trait IteratorUtil { /// ~~~ {.rust} /// let xs = [2u, 3]; /// let ys = [0u, 1, 0, 1, 2]; - /// let mut it = xs.iter().flat_map_(|&x| Counter::new(0u, 1).take_(x)); + /// let mut it = xs.iter().flat_map_(|&x| count(0u, 1).take_(x)); /// // Check that `it` has the same elements as `ys` /// let mut i = 0; /// for x: uint in it { @@ -351,7 +351,7 @@ pub trait IteratorUtil { /// ~~~ {.rust} /// use std::iterator::Counter; /// - /// for i in Counter::new(0, 10) { + /// for i in count(0, 10) { /// printfln!("%d", i); /// } /// ~~~ @@ -723,7 +723,7 @@ pub trait MultiplicativeIterator { /// use std::iterator::Counter; /// /// fn factorial(n: uint) -> uint { - /// Counter::new(1u, 1).take_while(|&i| i <= n).product() + /// count(1u, 1).take_while(|&i| i <= n).product() /// } /// assert!(factorial(0) == 1); /// assert!(factorial(1) == 1); @@ -790,7 +790,7 @@ pub trait ClonableIterator { /// # Example /// /// ~~~ {.rust} - /// let a = Counter::new(1,1).take_(1); + /// let a = count(1,1).take_(1); /// let mut cy = a.cycle(); /// assert_eq!(cy.next(), Some(1)); /// assert_eq!(cy.next(), Some(1)); @@ -884,15 +884,10 @@ impl, U: Iterator> Iterator for Chain { 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 }; @@ -916,12 +911,7 @@ for Chain { #[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] @@ -1273,11 +1263,10 @@ impl> Iterator for Skip { fn size_hint(&self) -> (uint, Option) { 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 }; @@ -1288,12 +1277,7 @@ impl> Iterator for Skip { impl> RandomAccessIterator for Skip { #[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] @@ -1316,10 +1300,9 @@ pub struct Take { impl> Iterator for Take { #[inline] fn next(&mut self) -> Option { - let next = self.iter.next(); if self.n != 0 { self.n -= 1; - next + self.iter.next() } else { None } @@ -1410,9 +1393,10 @@ impl<'self, A, T: Iterator, B, U: Iterator> Iterator for fn size_hint(&self) -> (uint, Option) { 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) } } } @@ -1527,12 +1511,10 @@ pub struct Counter { step: A } -impl Counter { - /// Creates a new counter with the specified start/step - #[inline] - pub fn new(start: A, step: A) -> Counter { - Counter{state: start, step: step} - } +/// Creates a new counter with the specified start/step +#[inline] +pub fn count(start: A, step: A) -> Counter { + Counter{state: start, step: step} } /// A range of numbers from [0, N) @@ -1619,7 +1601,7 @@ mod tests { #[test] fn test_counter_from_iter() { - let mut it = Counter::new(0, 5).take_(10); + let mut it = count(0, 5).take_(10); let xs: ~[int] = FromIterator::from_iterator(&mut it); assert_eq!(xs, ~[0, 5, 10, 15, 20, 25, 30, 35, 40, 45]); } @@ -1637,7 +1619,7 @@ mod tests { } assert_eq!(i, expected.len()); - let ys = Counter::new(30u, 10).take_(4); + let ys = count(30u, 10).take_(4); let mut it = xs.iter().transform(|&x| x).chain_(ys); let mut i = 0; for x in it { @@ -1649,7 +1631,7 @@ mod tests { #[test] fn test_filter_map() { - let mut it = Counter::new(0u, 1u).take_(10) + let mut it = count(0u, 1u).take_(10) .filter_map(|x| if x.is_even() { Some(x*x) } else { None }); assert_eq!(it.collect::<~[uint]>(), ~[0*0, 2*2, 4*4, 6*6, 8*8]); } @@ -1738,7 +1720,7 @@ mod tests { fn test_iterator_flat_map() { let xs = [0u, 3, 6]; let ys = [0u, 1, 2, 3, 4, 5, 6, 7, 8]; - let mut it = xs.iter().flat_map_(|&x| Counter::new(x, 1).take_(3)); + let mut it = xs.iter().flat_map_(|&x| count(x, 1).take_(3)); let mut i = 0; for x in it { assert_eq!(x, ys[i]); @@ -1785,13 +1767,13 @@ mod tests { #[test] fn test_cycle() { let cycle_len = 3; - let it = Counter::new(0u, 1).take_(cycle_len).cycle(); + let it = count(0u, 1).take_(cycle_len).cycle(); assert_eq!(it.size_hint(), (uint::max_value, None)); for (i, x) in it.take_(100).enumerate() { assert_eq!(i % cycle_len, x); } - let mut it = Counter::new(0u, 1).take_(0).cycle(); + let mut it = count(0u, 1).take_(0).cycle(); assert_eq!(it.size_hint(), (0, Some(0))); assert_eq!(it.next(), None); } @@ -1853,7 +1835,7 @@ mod tests { #[test] fn test_iterator_size_hint() { - let c = Counter::new(0, 1); + let c = count(0, 1); let v = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; let v2 = &[10, 11, 12]; let vi = v.iter(); diff --git a/src/libstd/managed.rs b/src/libstd/managed.rs index bd4dc69537c..57230b2fd24 100644 --- a/src/libstd/managed.rs +++ b/src/libstd/managed.rs @@ -12,7 +12,7 @@ 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; @@ -71,6 +71,29 @@ impl Ord for @mut T { fn gt(&self, other: &@mut T) -> bool { *(*self) > *(*other) } } +#[cfg(not(test))] +impl TotalOrd for @T { + #[inline] + fn cmp(&self, other: &@T) -> Ordering { (**self).cmp(*other) } +} + +#[cfg(not(test))] +impl TotalOrd for @mut T { + #[inline] + fn cmp(&self, other: &@mut T) -> Ordering { (**self).cmp(*other) } +} + +#[cfg(not(test))] +impl TotalEq for @T { + #[inline] + fn equals(&self, other: &@T) -> bool { (**self).equals(*other) } +} + +#[cfg(not(test))] +impl TotalEq for @mut T { + #[inline] + fn equals(&self, other: &@mut T) -> bool { (**self).equals(*other) } +} #[test] fn test() { let x = @3; diff --git a/src/libstd/num/num.rs b/src/libstd/num/num.rs index 8b61a8a8734..bbadf1caca2 100644 --- a/src/libstd/num/num.rs +++ b/src/libstd/num/num.rs @@ -466,6 +466,56 @@ impl Zero for ~T { 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::() + } else { x } + } else { + if x > self { + // underflow + Bounded::min_value::() + } 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::() + } else { x } + } else { + if x < self { + // overflow + Bounded::max_value::() + } 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(ten: T, two: T) { @@ -482,64 +532,111 @@ pub fn test_num(ten: T, two: T) { assert_eq!(ten.rem(&two), ten % two); } -macro_rules! test_cast_20( - ($_20:expr) => ({ - let _20 = $_20; +#[cfg(test)] +mod tests { + use super::*; - 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()); + macro_rules! test_cast_20( + ($_20:expr) => ({ + let _20 = $_20; - 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!(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, 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)); - }) -) + 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)); -#[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) } + 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_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); + } +} diff --git a/src/libstd/owned.rs b/src/libstd/owned.rs index e7a6e38fdb0..424c4fd6b2f 100644 --- a/src/libstd/owned.rs +++ b/src/libstd/owned.rs @@ -10,7 +10,7 @@ //! Operations on unique pointer types -#[cfg(not(test))] use cmp::{Eq, Ord}; +#[cfg(not(test))] use cmp::*; #[cfg(not(test))] impl Eq for ~T { @@ -31,3 +31,15 @@ impl Ord for ~T { #[inline] fn gt(&self, other: &~T) -> bool { *(*self) > *(*other) } } + +#[cfg(not(test))] +impl TotalOrd for ~T { + #[inline] + fn cmp(&self, other: &~T) -> Ordering { (**self).cmp(*other) } +} + +#[cfg(not(test))] +impl TotalEq for ~T { + #[inline] + fn equals(&self, other: &~T) -> bool { (**self).equals(*other) } +} diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index 5b8833f3f36..f035e61fa1e 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -50,6 +50,7 @@ pub use char::Char; pub use container::{Container, Mutable, Map, MutableMap, Set, MutableSet}; pub use hash::Hash; pub use iter::Times; +pub use iterator::Extendable; pub use iterator::{Iterator, IteratorUtil, DoubleEndedIterator, DoubleEndedIteratorUtil}; pub use iterator::{ClonableIterator, OrdIterator}; pub use num::{Num, NumCast}; @@ -65,7 +66,7 @@ pub use path::WindowsPath; pub use ptr::RawPtr; pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr, ToBytesConsume}; pub use str::{Str, StrVector, StrSlice, OwnedStr}; -pub use from_str::{FromStr}; +pub use from_str::FromStr; pub use to_bytes::IterBytes; pub use to_str::{ToStr, ToStrConsume}; pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps}; diff --git a/src/libstd/ptr.rs b/src/libstd/ptr.rs index a9e2e4c81a9..26653a51d66 100644 --- a/src/libstd/ptr.rs +++ b/src/libstd/ptr.rs @@ -272,6 +272,7 @@ pub trait RawPtr { fn is_not_null(&self) -> bool; unsafe fn to_option(&self) -> Option<&T>; fn offset(&self, count: int) -> Self; + unsafe fn offset_inbounds(self, count: int) -> Self; } /// Extension methods for immutable pointers @@ -304,6 +305,22 @@ impl RawPtr for *T { /// Calculates the offset from a pointer. #[inline] fn offset(&self, count: int) -> *T { offset(*self, count) } + + /// Calculates the offset from a pointer. The offset *must* be in-bounds of + /// the object, or one-byte-past-the-end. + #[inline] + #[cfg(stage0)] + unsafe fn offset_inbounds(self, count: int) -> *T { + intrinsics::offset(self, count) + } + + /// Calculates the offset from a pointer. The offset *must* be in-bounds of + /// the object, or one-byte-past-the-end. + #[inline] + #[cfg(not(stage0))] + unsafe fn offset_inbounds(self, count: int) -> *T { + intrinsics::offset_inbounds(self, count) + } } /// Extension methods for mutable pointers @@ -336,6 +353,30 @@ impl RawPtr for *mut T { /// Calculates the offset from a mutable pointer. #[inline] fn offset(&self, count: int) -> *mut T { mut_offset(*self, count) } + + /// Calculates the offset from a pointer. The offset *must* be in-bounds of + /// the object, or one-byte-past-the-end. An arithmetic overflow is also + /// undefined behaviour. + /// + /// This method should be preferred over `offset` when the guarantee can be + /// satisfied, to enable better optimization. + #[inline] + #[cfg(stage0)] + unsafe fn offset_inbounds(self, count: int) -> *mut T { + intrinsics::offset(self as *T, count) as *mut T + } + + /// Calculates the offset from a pointer. The offset *must* be in-bounds of + /// the object, or one-byte-past-the-end. An arithmetic overflow is also + /// undefined behaviour. + /// + /// This method should be preferred over `offset` when the guarantee can be + /// satisfied, to enable better optimization. + #[inline] + #[cfg(not(stage0))] + unsafe fn offset_inbounds(self, count: int) -> *mut T { + intrinsics::offset_inbounds(self as *T, count) as *mut T + } } // Equality for pointers diff --git a/src/libstd/str.rs b/src/libstd/str.rs index 7c3a3ca8619..d08879c68cc 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -3483,19 +3483,22 @@ mod tests { fn test_add() { #[allow(unnecessary_allocation)]; macro_rules! t ( - ($s1:expr, $s2:expr, $e:expr) => { - assert_eq!($s1 + $s2, $e); - assert_eq!($s1.to_owned() + $s2, $e); - assert_eq!($s1.to_managed() + $s2, $e); - } + ($s1:expr, $s2:expr, $e:expr) => { { + let s1 = $s1; + let s2 = $s2; + let e = $e; + assert_eq!(s1 + s2, e.to_owned()); + assert_eq!(s1.to_owned() + s2, e.to_owned()); + assert_eq!(s1.to_managed() + s2, e.to_owned()); + } } ); - t!("foo", "bar", ~"foobar"); - t!("foo", @"bar", ~"foobar"); - t!("foo", ~"bar", ~"foobar"); - t!("ศไทย中", "华Việt Nam", ~"ศไทย中华Việt Nam"); - t!("ศไทย中", @"华Việt Nam", ~"ศไทย中华Việt Nam"); - t!("ศไทย中", ~"华Việt Nam", ~"ศไทย中华Việt Nam"); + t!("foo", "bar", "foobar"); + t!("foo", @"bar", "foobar"); + t!("foo", ~"bar", "foobar"); + t!("ศไทย中", "华Việt Nam", "ศไทย中华Việt Nam"); + t!("ศไทย中", @"华Việt Nam", "ศไทย中华Việt Nam"); + t!("ศไทย中", ~"华Việt Nam", "ศไทย中华Việt Nam"); } #[test] diff --git a/src/libstd/str/ascii.rs b/src/libstd/str/ascii.rs index 5ffb7efab31..b4d3e4b0ad1 100644 --- a/src/libstd/str/ascii.rs +++ b/src/libstd/str/ascii.rs @@ -13,7 +13,10 @@ 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}; #[cfg(stage0)] @@ -41,27 +44,19 @@ impl Ascii { /// 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] } } @@ -292,10 +287,124 @@ impl ToBytesConsume for ~[Ascii] { } } + +/// 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}),*]); @@ -378,4 +487,53 @@ mod tests { #[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; + } + } } diff --git a/src/libstd/unstable/intrinsics.rs b/src/libstd/unstable/intrinsics.rs index 1270a80c354..c60edad3dbd 100644 --- a/src/libstd/unstable/intrinsics.rs +++ b/src/libstd/unstable/intrinsics.rs @@ -317,12 +317,21 @@ extern "rust-intrinsic" { /// Get the address of the `__morestack` stack growth function. pub fn morestack_addr() -> *(); - /// Adjust a pointer by an offset. + /// Calculates the offset from a pointer. /// /// This is implemented as an intrinsic to avoid converting to and from an /// integer, since the conversion would throw away aliasing information. pub fn offset(dst: *T, offset: int) -> *T; + /// Calculates the offset from a pointer. The offset *must* be in-bounds of + /// the object, or one-byte-past-the-end. An arithmetic overflow is also + /// undefined behaviour. + /// + /// This intrinsic should be preferred over `offset` when the guarantee can + /// be satisfied, to enable better optimization. + #[cfg(not(stage0))] + pub fn offset_inbounds(dst: *T, offset: int) -> *T; + /// Equivalent to the `llvm.memcpy.p0i8.0i8.i32` intrinsic, with a size of /// `count` * `size_of::()` and an alignment of `min_align_of::()` pub fn memcpy32(dst: *mut T, src: *T, count: u32); diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 0259b547ab3..36201dc5e82 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -849,10 +849,15 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] { fn iter(self) -> VecIterator<'self, T> { unsafe { let p = vec::raw::to_ptr(self); - VecIterator{ptr: p, - end: (p as uint + self.len() * - sys::nonzero_size_of::()) as *T, - lifetime: cast::transmute(p)} + if sys::size_of::() == 0 { + VecIterator{ptr: p, + end: (p as uint + self.len()) as *T, + lifetime: cast::transmute(p)} + } else { + VecIterator{ptr: p, + end: p.offset_inbounds(self.len() as int), + lifetime: cast::transmute(p)} + } } } @@ -1826,10 +1831,15 @@ impl<'self,T> MutableVector<'self, T> for &'self mut [T] { fn mut_iter(self) -> VecMutIterator<'self, T> { unsafe { let p = vec::raw::to_mut_ptr(self); - VecMutIterator{ptr: p, - end: (p as uint + self.len() * - sys::nonzero_size_of::()) as *mut T, - lifetime: cast::transmute(p)} + if sys::size_of::() == 0 { + VecMutIterator{ptr: p, + end: (p as uint + self.len()) as *mut T, + lifetime: cast::transmute(p)} + } else { + VecMutIterator{ptr: p, + end: p.offset_inbounds(self.len() as int), + lifetime: cast::transmute(p)} + } } } @@ -2183,7 +2193,7 @@ macro_rules! iterator { // same pointer. cast::transmute(self.ptr as uint + 1) } else { - self.ptr.offset(1) + self.ptr.offset_inbounds(1) }; Some(cast::transmute(old)) @@ -2215,7 +2225,7 @@ macro_rules! double_ended_iterator { // See above for why 'ptr.offset' isn't used cast::transmute(self.end as uint - 1) } else { - self.end.offset(-1) + self.end.offset_inbounds(-1) }; Some(cast::transmute(self.end)) } diff --git a/src/libsyntax/ext/deriving/cmp/totalord.rs b/src/libsyntax/ext/deriving/cmp/totalord.rs index 01dacdfe453..001e9235528 100644 --- a/src/libsyntax/ext/deriving/cmp/totalord.rs +++ b/src/libsyntax/ext/deriving/cmp/totalord.rs @@ -8,6 +8,7 @@ // 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; @@ -40,40 +41,70 @@ pub fn expand_deriving_totalord(cx: @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)`") } }, diff --git a/src/test/bench/core-set.rs b/src/test/bench/core-set.rs index 4fbe00622aa..70fe6f706f7 100644 --- a/src/test/bench/core-set.rs +++ b/src/test/bench/core-set.rs @@ -59,7 +59,7 @@ impl Results { { let mut set = f(); do timed(&mut self.random_ints) { - do num_keys.times { + for _ in range(0, num_keys) { set.insert((rng.next() as uint) % rand_cap); } } @@ -103,7 +103,7 @@ impl Results { { let mut set = f(); do timed(&mut self.random_strings) { - do num_keys.times { + for _ in range(0, num_keys) { let s = uint::to_str(rng.next() as uint); set.insert(s); } diff --git a/src/test/bench/noise.rs b/src/test/bench/noise.rs index 19380feea6d..8503b188b2f 100644 --- a/src/test/bench/noise.rs +++ b/src/test/bench/noise.rs @@ -105,7 +105,7 @@ fn main() { let symbols = [" ", "░", "▒", "▓", "█", "█"]; let mut pixels = [0f32, ..256*256]; let n2d = ~Noise2DContext::new(); - do 100.times { + for _ in range(0, 100u) { for y in range(0, 256) { for x in range(0, 256) { let v = n2d.get( diff --git a/src/test/bench/shootout-chameneos-redux.rs b/src/test/bench/shootout-chameneos-redux.rs index 190ad62d6e1..2b177ccb98f 100644 --- a/src/test/bench/shootout-chameneos-redux.rs +++ b/src/test/bench/shootout-chameneos-redux.rs @@ -169,7 +169,7 @@ fn rendezvous(nn: uint, set: ~[color]) { let mut creatures_met = 0; // set up meetings... - do nn.times { + for _ in range(0, nn) { let fst_creature: CreatureInfo = from_creatures.recv(); let snd_creature: CreatureInfo = from_creatures.recv(); diff --git a/src/test/bench/shootout-fasta-redux.rs b/src/test/bench/shootout-fasta-redux.rs index 579b88a7e0e..44b1a28c12b 100644 --- a/src/test/bench/shootout-fasta-redux.rs +++ b/src/test/bench/shootout-fasta-redux.rs @@ -164,7 +164,7 @@ impl RandomFasta { let chars_left = n % LINE_LEN; let mut buf = [0, ..LINE_LEN + 1]; - do lines.times { + for _ in range(0, lines) { for i in range(0u, LINE_LEN) { buf[i] = self.nextc(); } diff --git a/src/test/bench/shootout-k-nucleotide.rs b/src/test/bench/shootout-k-nucleotide.rs index 96fd4d7e604..2b5b4ded947 100644 --- a/src/test/bench/shootout-k-nucleotide.rs +++ b/src/test/bench/shootout-k-nucleotide.rs @@ -54,7 +54,7 @@ impl Code { fn unpack(&self, frame: i32) -> ~str { let mut key = **self; let mut result = ~[]; - do (frame as uint).times { + for _ in range(0, frame) { result.push(unpack_symbol((key as u8) & 3)); key >>= 2; } @@ -251,7 +251,7 @@ fn generate_frequencies(frequencies: &mut Table, let mut code = Code(0); // Pull first frame. - do (frame as uint).times { + for _ in range(0, frame) { code = code.push_char(input[0]); input = next_char(input); } diff --git a/src/test/bench/shootout-nbody.rs b/src/test/bench/shootout-nbody.rs index 115607d0a99..6a9c5ea89e4 100644 --- a/src/test/bench/shootout-nbody.rs +++ b/src/test/bench/shootout-nbody.rs @@ -79,7 +79,7 @@ struct Planet { fn advance(bodies: &mut [Planet, ..N_BODIES], dt: f64, steps: i32) { let mut d = [ 0.0, ..3 ]; - do (steps as uint).times { + for _ in range(0, steps) { for i in range(0u, N_BODIES) { for j in range(i + 1, N_BODIES) { d[0] = bodies[i].x[0] - bodies[j].x[0]; diff --git a/src/test/bench/shootout-spectralnorm.rs b/src/test/bench/shootout-spectralnorm.rs index aef22bc2b84..ecf54bf1647 100644 --- a/src/test/bench/shootout-spectralnorm.rs +++ b/src/test/bench/shootout-spectralnorm.rs @@ -56,7 +56,7 @@ fn main() { let mut u = vec::from_elem(n, 1f64); let mut v = u.clone(); let mut tmp = u.clone(); - do 8.times { + for _ in range(0, 8u) { mult_AtAv(u, v, tmp); mult_AtAv(v, u, tmp); } diff --git a/src/test/bench/task-perf-alloc-unwind.rs b/src/test/bench/task-perf-alloc-unwind.rs index ca539d712fd..114c7e997a2 100644 --- a/src/test/bench/task-perf-alloc-unwind.rs +++ b/src/test/bench/task-perf-alloc-unwind.rs @@ -32,7 +32,7 @@ fn main() { } fn run(repeat: int, depth: int) { - do (repeat as uint).times { + for _ in range(0, repeat) { info!("starting %.4f", precise_time_s()); do task::try { recurse_or_fail(depth, None) diff --git a/src/test/bench/task-perf-linked-failure.rs b/src/test/bench/task-perf-linked-failure.rs index 95dd803af81..15808427f4a 100644 --- a/src/test/bench/task-perf-linked-failure.rs +++ b/src/test/bench/task-perf-linked-failure.rs @@ -32,7 +32,7 @@ fn grandchild_group(num_tasks: uint) { let (po, ch) = stream(); let ch = SharedChan::new(ch); - do num_tasks.times { + for _ in range(0, num_tasks) { let ch = ch.clone(); do task::spawn { // linked ch.send(()); @@ -41,7 +41,7 @@ fn grandchild_group(num_tasks: uint) { } } error!("Grandchild group getting started"); - do num_tasks.times { + for _ in range(0, num_tasks) { // Make sure all above children are fully spawned; i.e., enlisted in // their ancestor groups. po.recv(); diff --git a/src/test/run-pass/class-impl-parameterized-trait.rs b/src/test/run-pass/class-impl-parameterized-trait.rs deleted file mode 100644 index 93e9eac1dd9..00000000000 --- a/src/test/run-pass/class-impl-parameterized-trait.rs +++ /dev/null @@ -1,83 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// xfail-test FIXME #7307 -// xfail-fast - -extern mod extra; -use extra::oldmap::*; - -class cat : map { - priv { - // Yes, you can have negative meows - let mut meows : int; - fn meow() { - self.meows += 1; - error!("Meow %d", self.meows); - if self.meows % 5 == 0 { - self.how_hungry += 1; - } - } - } - - let mut how_hungry : int; - let name : str; - - new(in_x : int, in_y : int, in_name: str) - { self.meows = in_x; self.how_hungry = in_y; self.name = in_name; } - - fn speak() { self.meow(); } - - fn eat() -> bool { - if self.how_hungry > 0 { - error!("OM NOM NOM"); - self.how_hungry -= 2; - return true; - } - else { - error!("Not hungry!"); - return false; - } - } - - fn size() -> uint { self.meows as uint } - fn insert(+k: int, +v: bool) -> bool { - if v { self.meows += k; } else { self.meows -= k; }; - true - } - fn contains_key(&&k: int) -> bool { k <= self.meows } - fn get(&&k:int) -> bool { k <= self.meows } - fn [](&&k:int) -> bool { k <= self.meows } - fn find(&&k:int) -> Option { Some(self.get(k)) } - fn remove(&&k:int) -> Option { self.meows -= k; Some(true) } - fn each(f: &fn(&&int, &&bool) -> bool) { - let mut n = num::abs(self.meows); - while n > 0 { - if !f(n, true) { break; } - n -= 1; - } - } - fn each_key(&&f: &fn(&&int) -> bool) { - for self.each |k, _v| { if !f(k) { break; } again;}; - } - fn each_value(&&f: &fn(&&bool) -> bool) { - for self.each |_k, v| { if !f(v) { break; } again;}; - } - fn clear() { } -} - -pub fn main() { - let nyan : cat = cat(0, 2, "nyan"); - for _ in range(1u, 5u) { nyan.speak(); } - // cat returns true if uint input is greater than - // the number of meows so far - assert!((nyan.get(1))); - assert!((!nyan.get(10))); -} diff --git a/src/test/run-pass/class-implements-multiple-traits.rs b/src/test/run-pass/class-implements-multiple-traits.rs deleted file mode 100644 index 4fccc45a753..00000000000 --- a/src/test/run-pass/class-implements-multiple-traits.rs +++ /dev/null @@ -1,129 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// xfail-test FIXME #7305 - -extern mod extra; -use extra::oldmap::*; -use vec::*; -use dvec::{dvec, extensions}; - -enum furniture { chair, couch, bed } -enum body_part { finger, toe, nose, ear } - -trait noisy { - fn speak() -> int; -} - -trait scratchy { - fn scratch() -> Option; -} - -trait bitey { - fn bite() -> body_part; -} - -fn vec_includes(xs: ~[T], x: T) -> bool { - for each(xs) |y| { if y == x { return true; }} - return false; -} - -// vtables other than the 1st one don't seem to work -class cat : noisy, scratchy, bitey { - priv { - let meows : @mut uint; - let scratched : dvec; - let bite_counts : hashmap; - - fn meow() -> uint { - info!("Meow: %u", *self.meows); - *self.meows += 1u; - if *self.meows % 5u == 0u { - *self.how_hungry += 1; - } - *self.meows - } - } - - let how_hungry : @mut int; - let name : str; - - new(in_x : uint, in_y : int, in_name: str) - { self.meows = @mut in_x; self.how_hungry = @mut in_y; - self.name = in_name; self.scratched = dvec(); - let hsher: hashfn = |p| int::hash(p as int); - let eqer : eqfn = |p, q| p == q; - let t : hashmap = - hashmap::(hsher, eqer); - self.bite_counts = t; - do iter(~[finger, toe, nose, ear]) |p| { - self.bite_counts.insert(p, 0u); - }; - } - - fn speak() -> int { self.meow() as int } - fn meow_count() -> uint { *self.meows } - fn scratch() -> Option { - let all = ~[chair, couch, bed]; - log(error, self.scratched); - let mut rslt = None; - for each(all) |thing| { if !self.scratched.contains(thing) { - self.scratched.push(thing); - return Some(thing); }} - rslt - } - fn bite() -> body_part { - error!("In bite()"); - let all = ~[toe, nose, ear]; - let mut min = finger; - do iter(all) |next| { - info!("min = %?", min); - if self.bite_counts.get(next) < self.bite_counts.get(min) { - min = next; - }}; - self.bite_counts.insert(min, self.bite_counts.get(min) + 1u); - info!("Bit %?", min); - min - } -} - -fn annoy_neighbors(critter: T) { - for i in range(0u, 10u) { - let what = critter.speak(); - info!("%u %d", i, what); - } -} - -fn bite_everything(critter: T) -> bool { - let mut left : ~[body_part] = ~[finger, toe, nose, ear]; - while left.len() > 0u { - let part = critter.bite(); - info!("%? %?", left, part); - if vec_includes(left, part) { - left = vec::filter(left, |p| p != part ); - } - else { - return false; - } - } - true -} - -fn scratched_something(critter: T) -> bool { - option::is_some(critter.scratch()) -} - -pub fn main() { - let nyan : cat = cat(0u, 2, "nyan"); - annoy_neighbors(nyan as noisy); - assert_eq!(nyan.meow_count(), 10u); - assert!((bite_everything(nyan as bitey))); - assert!((scratched_something(nyan as scratchy))); -} diff --git a/src/test/run-pass/coerce-reborrow-imm-vec-arg.rs b/src/test/run-pass/coerce-reborrow-imm-vec-arg.rs index 7fb01006844..b31f0eab2e2 100644 --- a/src/test/run-pass/coerce-reborrow-imm-vec-arg.rs +++ b/src/test/run-pass/coerce-reborrow-imm-vec-arg.rs @@ -12,10 +12,4 @@ fn sum_imm(y: &[int]) -> int { sum(y) } -/* FIXME #7304 -fn sum_const(y: &const [int]) -> int { - sum(y) -} -*/ - pub fn main() {} diff --git a/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs b/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs index 590cd825020..8a271a4d65f 100644 --- a/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs +++ b/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs @@ -1,9 +1,3 @@ -/* FIXME #7302 -fn foo(v: &const [uint]) -> ~[uint] { - v.to_owned() -} -*/ - fn bar(v: &mut [uint]) -> ~[uint] { v.to_owned() } @@ -14,7 +8,6 @@ fn bip(v: &[uint]) -> ~[uint] { pub fn main() { let mut the_vec = ~[1u, 2, 3, 100]; -// assert_eq!(the_vec.clone(), foo(the_vec)); assert_eq!(the_vec.clone(), bar(the_vec)); assert_eq!(the_vec.clone(), bip(the_vec)); } diff --git a/src/test/run-pass/deriving-cmp-shortcircuit.rs b/src/test/run-pass/deriving-cmp-shortcircuit.rs new file mode 100644 index 00000000000..7f5c78cf602 --- /dev/null +++ b/src/test/run-pass/deriving-cmp-shortcircuit.rs @@ -0,0 +1,46 @@ +// 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 or the MIT license +// , 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); +} diff --git a/src/test/run-pass/rcvr-borrowed-to-region.rs b/src/test/run-pass/rcvr-borrowed-to-region.rs index 28396119596..46819027dad 100644 --- a/src/test/run-pass/rcvr-borrowed-to-region.rs +++ b/src/test/run-pass/rcvr-borrowed-to-region.rs @@ -12,7 +12,9 @@ trait get { fn get(self) -> int; } -// FIXME #7302: Note: impl on a slice +// Note: impl on a slice; we're checking that the pointers below +// correctly get borrowed to `&`. (similar to impling for `int`, with +// `&self` instead of `self`.) impl<'self> get for &'self int { fn get(self) -> int { return *self; @@ -34,11 +36,6 @@ pub fn main() { info!("y=%d", y); assert_eq!(y, 6); - let x = ~6; - let y = x.get(); - info!("y=%d", y); - assert_eq!(y, 6); - let x = &6; let y = x.get(); info!("y=%d", y);