From 6093128ef3c5ae661ec66fbf3685833d6be217bb Mon Sep 17 00:00:00 2001 From: kennytm Date: Fri, 13 Jul 2018 13:08:28 +0800 Subject: [PATCH] Changed implementation of the third field to make LLVM optimize it better. --- src/libcore/iter/mod.rs | 8 ++++---- src/libcore/iter/range.rs | 42 +++++++++++++++++++-------------------- src/libcore/ops/range.rs | 20 +++++++++++++------ 3 files changed, 39 insertions(+), 31 deletions(-) diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 32134783516..35ae7741106 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -787,19 +787,19 @@ where #[inline] fn spec_next(&mut self) -> Option { self.first_take = false; - if self.iter.is_empty() { - self.iter.is_iterating = Some(false); + self.iter.compute_is_empty(); + if self.iter.is_empty.unwrap_or_default() { return None; } // add 1 to self.step to get original step size back // it was decremented for the general case on construction if let Some(n) = self.iter.start.add_usize(self.step+1) { - self.iter.is_iterating = Some(n <= self.iter.end); + self.iter.is_empty = Some(!(n <= self.iter.end)); let next = mem::replace(&mut self.iter.start, n); Some(next) } else { let last = self.iter.start.clone(); - self.iter.is_iterating = Some(false); + self.iter.is_empty = Some(true); Some(last) } } diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 16849e84f27..651c7a35d41 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -330,18 +330,18 @@ impl Iterator for ops::RangeInclusive { #[inline] fn next(&mut self) -> Option { - if self.is_empty() { - self.is_iterating = Some(false); + self.compute_is_empty(); + if self.is_empty.unwrap_or_default() { return None; } - if self.start < self.end { + let is_iterating = self.start < self.end; + self.is_empty = Some(!is_iterating); + Some(if is_iterating { let n = self.start.add_one(); - self.is_iterating = Some(true); - Some(mem::replace(&mut self.start, n)) + mem::replace(&mut self.start, n) } else { - self.is_iterating = Some(false); - Some(self.start.clone()) - } + self.start.clone() + }) } #[inline] @@ -358,8 +358,8 @@ impl Iterator for ops::RangeInclusive { #[inline] fn nth(&mut self, n: usize) -> Option { - if self.is_empty() { - self.is_iterating = Some(false); + self.compute_is_empty(); + if self.is_empty.unwrap_or_default() { return None; } @@ -368,19 +368,19 @@ impl Iterator for ops::RangeInclusive { match plus_n.partial_cmp(&self.end) { Some(Less) => { - self.is_iterating = Some(true); + self.is_empty = Some(false); self.start = plus_n.add_one(); return Some(plus_n) } Some(Equal) => { - self.is_iterating = Some(false); + self.is_empty = Some(true); return Some(plus_n) } _ => {} } } - self.is_iterating = Some(false); + self.is_empty = Some(true); None } @@ -404,18 +404,18 @@ impl Iterator for ops::RangeInclusive { impl DoubleEndedIterator for ops::RangeInclusive { #[inline] fn next_back(&mut self) -> Option { - if self.is_empty() { - self.is_iterating = Some(false); + self.compute_is_empty(); + if self.is_empty.unwrap_or_default() { return None; } - if self.start < self.end { + let is_iterating = self.start < self.end; + self.is_empty = Some(!is_iterating); + Some(if is_iterating { let n = self.end.sub_one(); - self.is_iterating = Some(true); - Some(mem::replace(&mut self.end, n)) + mem::replace(&mut self.end, n) } else { - self.is_iterating = Some(false); - Some(self.end.clone()) - } + self.end.clone() + }) } } diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 0f119789a75..9c635678d7a 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -332,11 +332,11 @@ impl> RangeTo { pub struct RangeInclusive { pub(crate) start: Idx, pub(crate) end: Idx, - pub(crate) is_iterating: Option, + pub(crate) is_empty: Option, // This field is: // - `None` when next() or next_back() was never called - // - `Some(true)` when `start <= end` assuming no overflow - // - `Some(false)` otherwise + // - `Some(false)` when `start <= end` assuming no overflow + // - `Some(true)` otherwise // The field cannot be a simple `bool` because the `..=` constructor can // accept non-PartialOrd types, also we want the constructor to be const. } @@ -347,7 +347,7 @@ trait RangeInclusiveEquality: Sized { impl RangeInclusiveEquality for T { #[inline] default fn canonicalized_is_empty(range: &RangeInclusive) -> bool { - !range.is_iterating.unwrap_or(false) + range.is_empty.unwrap_or_default() } } impl RangeInclusiveEquality for T { @@ -392,7 +392,7 @@ impl RangeInclusive { #[stable(feature = "inclusive_range_methods", since = "1.27.0")] #[inline] pub const fn new(start: Idx, end: Idx) -> Self { - Self { start, end, is_iterating: None } + Self { start, end, is_empty: None } } /// Returns the lower bound of the range (inclusive). @@ -536,7 +536,15 @@ impl> RangeInclusive { #[unstable(feature = "range_is_empty", reason = "recently added", issue = "48111")] #[inline] pub fn is_empty(&self) -> bool { - !self.is_iterating.unwrap_or_else(|| self.start <= self.end) + self.is_empty.unwrap_or_else(|| !(self.start <= self.end)) + } + + // If this range's `is_empty` is field is unknown (`None`), update it to be a concrete value. + #[inline] + pub(crate) fn compute_is_empty(&mut self) { + if self.is_empty.is_none() { + self.is_empty = Some(!(self.start <= self.end)); + } } }