From b3a317c368d424929cdd2e6c3be661d7d8553cc0 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Mon, 5 Aug 2013 19:23:29 -0400 Subject: [PATCH 1/7] iterator: simplify the `take` implementation --- src/libstd/iterator.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index 56a0dca56679..4803e2e004e7 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -1316,10 +1316,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 } From c13f4f398a0c27af573fac8d426a6cda68a168fe Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Mon, 5 Aug 2013 19:58:56 -0400 Subject: [PATCH 2/7] add Extendable to the prelude --- src/libstd/prelude.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index 517bc4a441a6..65db55297b3b 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -49,6 +49,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}; @@ -64,7 +65,7 @@ pub use path::WindowsPath; pub use ptr::RawPtr; pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr, ToBytesConsume}; pub use str::{Str, StrVector, StrSlice, OwnedStr, NullTerminatedStr}; -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}; From 40d11a546178ca32523e7424a0bf61fe25f7e3d1 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Mon, 5 Aug 2013 20:02:26 -0400 Subject: [PATCH 3/7] iterator: rename `Counter::new` to `count` to match the convention used by `range`, since `iterator::count` is already namespaced enough and won't be ambiguous --- src/libextra/ringbuf.rs | 2 +- src/libstd/iterator.rs | 32 +++++++++++++++----------------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/libextra/ringbuf.rs b/src/libextra/ringbuf.rs index 9833bd5d1cbf..da8089250b34 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/libstd/iterator.rs b/src/libstd/iterator.rs index 4803e2e004e7..65cb7e7a8a9e 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -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)); @@ -1526,12 +1526,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) @@ -1618,7 +1616,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]); } @@ -1636,7 +1634,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 { @@ -1648,7 +1646,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]); } @@ -1737,7 +1735,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]); @@ -1784,13 +1782,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); } @@ -1852,7 +1850,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(); From 8f9bbc476d9e4403bc5cd1edfe4a651bd341e811 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Mon, 5 Aug 2013 23:43:06 -0400 Subject: [PATCH 4/7] remove `extra::iter` This module provided adaptors for the old internal iterator protocol, but they proved to be quite unreadable and are not generic enough to handle borrowed pointers well. Since Rust no longer defines an internal iteration protocol, I don't think there's going to be any reuse via these adaptors. --- doc/tutorial-tasks.md | 4 +- doc/tutorial.md | 2 +- src/libextra/iter.rs | 331 --------------------- src/librustdoc/markdown_pass.rs | 4 +- src/test/bench/core-set.rs | 4 +- src/test/bench/noise.rs | 2 +- src/test/bench/shootout-chameneos-redux.rs | 2 +- src/test/bench/shootout-fasta-redux.rs | 2 +- src/test/bench/shootout-k-nucleotide.rs | 4 +- src/test/bench/shootout-nbody.rs | 2 +- src/test/bench/shootout-spectralnorm.rs | 2 +- src/test/bench/task-perf-alloc-unwind.rs | 2 +- src/test/bench/task-perf-linked-failure.rs | 4 +- 13 files changed, 17 insertions(+), 348 deletions(-) delete mode 100644 src/libextra/iter.rs diff --git a/doc/tutorial-tasks.md b/doc/tutorial-tasks.md index b2ef624d1ac3..b5677a261c45 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 a5f2001eaf51..6e6b804aa9d3 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/iter.rs b/src/libextra/iter.rs deleted file mode 100644 index 7fd47fdbd399..000000000000 --- 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/librustdoc/markdown_pass.rs b/src/librustdoc/markdown_pass.rs index 85c360a9e0df..f05c59083f40 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/test/bench/core-set.rs b/src/test/bench/core-set.rs index 4fbe00622aa2..70fe6f706f79 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 19380feea6df..8503b188b2f2 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 190ad62d6e17..2b177ccb98fc 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 579b88a7e0e7..44b1a28c12b3 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 96fd4d7e604e..2b5b4ded9477 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 115607d0a992..6a9c5ea89e4f 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 aef22bc2b842..ecf54bf16473 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 ca539d712fde..114c7e997a24 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 95dd803af818..15808427f4a8 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(); From f23fb19ee508515912e136c948a0242cc88a2d4e Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 6 Aug 2013 17:15:43 -0400 Subject: [PATCH 5/7] vec: avoid `ptrtoint`/`inttoptr` in the iterators This results in throwing away alias analysis information, because LLVM does *not* implement reasoning about these conversions yet. We specialize zero-size types since a `getelementptr` offset will return us the same pointer, making it broken as a simple counter. --- src/libstd/vec.rs | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 0259b547ab3f..8dbfb3ec543e 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(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(self.len() as int), + lifetime: cast::transmute(p)} + } } } From 7d115c94205dd4b937d29c77d1704aa3f801869e Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 6 Aug 2013 17:44:40 -0400 Subject: [PATCH 6/7] add an intrinsic for inbounds GEP --- src/librustc/middle/trans/foreign.rs | 5 +++++ src/librustc/middle/trans/type_use.rs | 3 ++- src/librustc/middle/typeck/check/mod.rs | 14 ++++++++++++++ src/libstd/ptr.rs | 22 ++++++++++++++++++++++ src/libstd/unstable/intrinsics.rs | 11 ++++++++++- 5 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 5153296337da..b1e600b9d737 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 42d5527ee43b..ad83286c8c1d 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 ea8a11fc7b38..8623ee546d66 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/libstd/ptr.rs b/src/libstd/ptr.rs index dfd11f9227d4..98fb132672c6 100644 --- a/src/libstd/ptr.rs +++ b/src/libstd/ptr.rs @@ -272,6 +272,8 @@ pub trait RawPtr { fn is_not_null(&self) -> bool; unsafe fn to_option(&self) -> Option<&T>; fn offset(&self, count: int) -> Self; + #[cfg(not(stage0))] + unsafe fn offset_inbounds(self, count: int) -> Self; } /// Extension methods for immutable pointers @@ -304,6 +306,14 @@ 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(not(stage0))] + unsafe fn offset_inbounds(self, count: int) -> *T { + intrinsics::offset_inbounds(self, count) + } } /// Extension methods for mutable pointers @@ -336,6 +346,18 @@ 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(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/unstable/intrinsics.rs b/src/libstd/unstable/intrinsics.rs index 1270a80c3549..c60edad3dbd5 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); From 55f3d04101c214a13f7d47fbdb140c5c1126c41b Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 6 Aug 2013 18:05:43 -0400 Subject: [PATCH 7/7] vec: use `offset_inbounds` for iterators This allows LLVM to optimize vector iterators to an `getelementptr` and `icmp` pair, instead of `getelementptr` and *two* comparisons. Code snippet: ~~~ fn foo(xs: &mut [f64]) { for x in xs.mut_iter() { *x += 10.0; } } ~~~ LLVM IR at stage0: ~~~ ; Function Attrs: noinline uwtable define void @"_ZN3foo17_68e1b25bca131dba7_0$x2e0E"({ i64, %tydesc*, i8*, i8*, i8 }* nocapture, { double*, i64 }* nocapture) #1 { "function top level": %2 = getelementptr inbounds { double*, i64 }* %1, i64 0, i32 0 %3 = load double** %2, align 8 %4 = getelementptr inbounds { double*, i64 }* %1, i64 0, i32 1 %5 = load i64* %4, align 8 %6 = ptrtoint double* %3 to i64 %7 = and i64 %5, -8 %8 = add i64 %7, %6 %9 = inttoptr i64 %8 to double* %10 = icmp eq double* %3, %9 %11 = icmp eq double* %3, null %or.cond6 = or i1 %10, %11 br i1 %or.cond6, label %match_case, label %match_else match_else: ; preds = %"function top level", %match_else %12 = phi double* [ %13, %match_else ], [ %3, %"function top level" ] %13 = getelementptr double* %12, i64 1 %14 = load double* %12, align 8 %15 = fadd double %14, 1.000000e+01 store double %15, double* %12, align 8 %16 = icmp eq double* %13, %9 %17 = icmp eq double* %13, null %or.cond = or i1 %16, %17 br i1 %or.cond, label %match_case, label %match_else match_case: ; preds = %match_else, %"function top level" ret void } ~~~ Optimized LLVM IR at stage1/stage2: ~~~ ; Function Attrs: noinline uwtable define void @"_ZN3foo17_68e1b25bca131dba7_0$x2e0E"({ i64, %tydesc*, i8*, i8*, i8 }* nocapture, { double*, i64 }* nocapture) #1 { "function top level": %2 = getelementptr inbounds { double*, i64 }* %1, i64 0, i32 0 %3 = load double** %2, align 8 %4 = getelementptr inbounds { double*, i64 }* %1, i64 0, i32 1 %5 = load i64* %4, align 8 %6 = lshr i64 %5, 3 %7 = getelementptr inbounds double* %3, i64 %6 %8 = icmp eq i64 %6, 0 %9 = icmp eq double* %3, null %or.cond6 = or i1 %8, %9 br i1 %or.cond6, label %match_case, label %match_else match_else: ; preds = %"function top level", %match_else %.sroa.0.0.in7 = phi double* [ %10, %match_else ], [ %3, %"function top level" ] %10 = getelementptr inbounds double* %.sroa.0.0.in7, i64 1 %11 = load double* %.sroa.0.0.in7, align 8 %12 = fadd double %11, 1.000000e+01 store double %12, double* %.sroa.0.0.in7, align 8 %13 = icmp eq double* %10, %7 br i1 %13, label %match_case, label %match_else match_case: ; preds = %match_else, %"function top level" ret void } ~~~ --- src/libstd/ptr.rs | 21 ++++++++++++++++++++- src/libstd/vec.rs | 8 ++++---- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/libstd/ptr.rs b/src/libstd/ptr.rs index 98fb132672c6..5a2bd0c4de9c 100644 --- a/src/libstd/ptr.rs +++ b/src/libstd/ptr.rs @@ -272,7 +272,6 @@ pub trait RawPtr { fn is_not_null(&self) -> bool; unsafe fn to_option(&self) -> Option<&T>; fn offset(&self, count: int) -> Self; - #[cfg(not(stage0))] unsafe fn offset_inbounds(self, count: int) -> Self; } @@ -307,6 +306,14 @@ impl RawPtr for *T { #[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] @@ -347,6 +354,18 @@ impl RawPtr for *mut T { #[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. diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 8dbfb3ec543e..36201dc5e826 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -855,7 +855,7 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] { lifetime: cast::transmute(p)} } else { VecIterator{ptr: p, - end: p.offset(self.len() as int), + end: p.offset_inbounds(self.len() as int), lifetime: cast::transmute(p)} } } @@ -1837,7 +1837,7 @@ impl<'self,T> MutableVector<'self, T> for &'self mut [T] { lifetime: cast::transmute(p)} } else { VecMutIterator{ptr: p, - end: p.offset(self.len() as int), + end: p.offset_inbounds(self.len() as int), lifetime: cast::transmute(p)} } } @@ -2193,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)) @@ -2225,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)) }