about summary refs log tree commit diff
path: root/src/libcore
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-05-29 19:50:22 +0000
committerbors <bors@rust-lang.org>2020-05-29 19:50:22 +0000
commit4bd32c98047a809ba5fd1fac2aa044638e5f2105 (patch)
tree2ab4b52a13d0ec1df564fac39c011993112c9709 /src/libcore
parent96dd4690c3aa70ec312448c3f2d50e6dc6fb87df (diff)
parent180a92cad72fc6fa9fad5a0f97db24703fe280bf (diff)
downloadrust-4bd32c98047a809ba5fd1fac2aa044638e5f2105.tar.gz
rust-4bd32c98047a809ba5fd1fac2aa044638e5f2105.zip
Auto merge of #72747 - Dylan-DPC:rollup-vvydkgl, r=Dylan-DPC
Rollup of 9 pull requests

Successful merges:

 - #72310 (Add Peekable::next_if)
 - #72383 (Suggest using std::mem::drop function instead of explicit destructor call)
 - #72398 (SocketAddr and friends now correctly pad its content)
 - #72465 (Warn about unused captured variables)
 - #72568 (Implement total_cmp for f32, f64)
 - #72572 (Add some regression tests)
 - #72591 (librustc_middle: Rename upvar_list to closure_captures)
 - #72701 (Fix grammar in liballoc raw_vec)
 - #72731 (Add missing empty line in E0619 explanation)

Failed merges:

r? @ghost
Diffstat (limited to 'src/libcore')
-rw-r--r--src/libcore/iter/adapters/mod.rs63
-rw-r--r--src/libcore/num/f32.rs74
-rw-r--r--src/libcore/num/f64.rs74
-rw-r--r--src/libcore/tests/iter.rs24
-rw-r--r--src/libcore/tests/lib.rs1
5 files changed, 236 insertions, 0 deletions
diff --git a/src/libcore/iter/adapters/mod.rs b/src/libcore/iter/adapters/mod.rs
index 195847ee98d..00529f0e2d5 100644
--- a/src/libcore/iter/adapters/mod.rs
+++ b/src/libcore/iter/adapters/mod.rs
@@ -1619,6 +1619,69 @@ impl<I: Iterator> Peekable<I> {
         let iter = &mut self.iter;
         self.peeked.get_or_insert_with(|| iter.next()).as_ref()
     }
+
+    /// Consume the next value of this iterator if a condition is true.
+    ///
+    /// If `func` returns `true` for the next value of this iterator, consume and return it.
+    /// Otherwise, return `None`.
+    ///
+    /// # Examples
+    /// Consume a number if it's equal to 0.
+    /// ```
+    /// #![feature(peekable_next_if)]
+    /// let mut iter = (0..5).peekable();
+    /// // The first item of the iterator is 0; consume it.
+    /// assert_eq!(iter.next_if(|&x| x == 0), Some(0));
+    /// // The next item returned is now 1, so `consume` will return `false`.
+    /// assert_eq!(iter.next_if(|&x| x == 0), None);
+    /// // `next_if` saves the value of the next item if it was not equal to `expected`.
+    /// assert_eq!(iter.next(), Some(1));
+    /// ```
+    ///
+    /// Consume any number less than 10.
+    /// ```
+    /// #![feature(peekable_next_if)]
+    /// let mut iter = (1..20).peekable();
+    /// // Consume all numbers less than 10
+    /// while iter.next_if(|&x| x < 10).is_some() {}
+    /// // The next value returned will be 10
+    /// assert_eq!(iter.next(), Some(10));
+    /// ```
+    #[unstable(feature = "peekable_next_if", issue = "72480")]
+    pub fn next_if(&mut self, func: impl FnOnce(&I::Item) -> bool) -> Option<I::Item> {
+        match self.next() {
+            Some(matched) if func(&matched) => Some(matched),
+            other => {
+                // Since we called `self.next()`, we consumed `self.peeked`.
+                assert!(self.peeked.is_none());
+                self.peeked = Some(other);
+                None
+            }
+        }
+    }
+
+    /// Consume the next item if it is equal to `expected`.
+    ///
+    /// # Example
+    /// Consume a number if it's equal to 0.
+    /// ```
+    /// #![feature(peekable_next_if)]
+    /// let mut iter = (0..5).peekable();
+    /// // The first item of the iterator is 0; consume it.
+    /// assert_eq!(iter.next_if_eq(&0), Some(0));
+    /// // The next item returned is now 1, so `consume` will return `false`.
+    /// assert_eq!(iter.next_if_eq(&0), None);
+    /// // `next_if_eq` saves the value of the next item if it was not equal to `expected`.
+    /// assert_eq!(iter.next(), Some(1));
+    /// ```
+    #[unstable(feature = "peekable_next_if", issue = "72480")]
+    pub fn next_if_eq<R>(&mut self, expected: &R) -> Option<I::Item>
+    where
+        R: ?Sized,
+        I::Item: PartialEq<R>,
+    {
+        self.next_if(|next| next == expected)
+    }
 }
 
 /// An iterator that rejects elements while `predicate` returns `true`.
diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs
index 434569020d2..6313de31ce4 100644
--- a/src/libcore/num/f32.rs
+++ b/src/libcore/num/f32.rs
@@ -810,4 +810,78 @@ impl f32 {
     pub fn from_ne_bytes(bytes: [u8; 4]) -> Self {
         Self::from_bits(u32::from_ne_bytes(bytes))
     }
+
+    /// Returns an ordering between self and other values.
+    /// Unlike the standard partial comparison between floating point numbers,
+    /// this comparison always produces an ordering in accordance to
+    /// the totalOrder predicate as defined in IEEE 754 (2008 revision)
+    /// floating point standard. The values are ordered in following order:
+    /// - Negative quiet NaN
+    /// - Negative signaling NaN
+    /// - Negative infinity
+    /// - Negative numbers
+    /// - Negative subnormal numbers
+    /// - Negative zero
+    /// - Positive zero
+    /// - Positive subnormal numbers
+    /// - Positive numbers
+    /// - Positive infinity
+    /// - Positive signaling NaN
+    /// - Positive quiet NaN
+    ///
+    /// # Example
+    /// ```
+    /// #![feature(total_cmp)]
+    /// struct GoodBoy {
+    ///     name: String,
+    ///     weight: f32,
+    /// }
+    ///
+    /// let mut bois = vec![
+    ///     GoodBoy { name: "Pucci".to_owned(), weight: 0.1 },
+    ///     GoodBoy { name: "Woofer".to_owned(), weight: 99.0 },
+    ///     GoodBoy { name: "Yapper".to_owned(), weight: 10.0 },
+    ///     GoodBoy { name: "Chonk".to_owned(), weight: f32::INFINITY },
+    ///     GoodBoy { name: "Abs. Unit".to_owned(), weight: f32::NAN },
+    ///     GoodBoy { name: "Floaty".to_owned(), weight: -5.0 },
+    /// ];
+    ///
+    /// bois.sort_by(|a, b| a.weight.total_cmp(&b.weight));
+    /// # assert!(bois.into_iter().map(|b| b.weight)
+    /// #     .zip([-5.0, 0.1, 10.0, 99.0, f32::INFINITY, f32::NAN].iter())
+    /// #     .all(|(a, b)| a.to_bits() == b.to_bits()))
+    /// ```
+    #[unstable(feature = "total_cmp", issue = "72599")]
+    #[inline]
+    pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering {
+        let mut left = self.to_bits() as i32;
+        let mut right = other.to_bits() as i32;
+
+        // In case of negatives, flip all the bits except the sign
+        // to achieve a similar layout as two's complement integers
+        //
+        // Why does this work? IEEE 754 floats consist of three fields:
+        // Sign bit, exponent and mantissa. The set of exponent and mantissa
+        // fields as a whole have the property that their bitwise order is
+        // equal to the numeric magnitude where the magnitude is defined.
+        // The magnitude is not normally defined on NaN values, but
+        // IEEE 754 totalOrder defines the NaN values also to follow the
+        // bitwise order. This leads to order explained in the doc comment.
+        // However, the representation of magnitude is the same for negative
+        // and positive numbers – only the sign bit is different.
+        // To easily compare the floats as signed integers, we need to
+        // flip the exponent and mantissa bits in case of negative numbers.
+        // We effectively convert the numbers to "two's complement" form.
+        //
+        // To do the flipping, we construct a mask and XOR against it.
+        // We branchlessly calculate an "all-ones except for the sign bit"
+        // mask from negative-signed values: right shifting sign-extends
+        // the integer, so we "fill" the mask with sign bits, and then
+        // convert to unsigned to push one more zero bit.
+        // On positive values, the mask is all zeros, so it's a no-op.
+        left ^= (((left >> 31) as u32) >> 1) as i32;
+        right ^= (((right >> 31) as u32) >> 1) as i32;
+
+        left.cmp(&right)
+    }
 }
diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs
index 6476ddb4541..d42e5392c58 100644
--- a/src/libcore/num/f64.rs
+++ b/src/libcore/num/f64.rs
@@ -824,4 +824,78 @@ impl f64 {
     pub fn from_ne_bytes(bytes: [u8; 8]) -> Self {
         Self::from_bits(u64::from_ne_bytes(bytes))
     }
+
+    /// Returns an ordering between self and other values.
+    /// Unlike the standard partial comparison between floating point numbers,
+    /// this comparison always produces an ordering in accordance to
+    /// the totalOrder predicate as defined in IEEE 754 (2008 revision)
+    /// floating point standard. The values are ordered in following order:
+    /// - Negative quiet NaN
+    /// - Negative signaling NaN
+    /// - Negative infinity
+    /// - Negative numbers
+    /// - Negative subnormal numbers
+    /// - Negative zero
+    /// - Positive zero
+    /// - Positive subnormal numbers
+    /// - Positive numbers
+    /// - Positive infinity
+    /// - Positive signaling NaN
+    /// - Positive quiet NaN
+    ///
+    /// # Example
+    /// ```
+    /// #![feature(total_cmp)]
+    /// struct GoodBoy {
+    ///     name: String,
+    ///     weight: f64,
+    /// }
+    ///
+    /// let mut bois = vec![
+    ///     GoodBoy { name: "Pucci".to_owned(), weight: 0.1 },
+    ///     GoodBoy { name: "Woofer".to_owned(), weight: 99.0 },
+    ///     GoodBoy { name: "Yapper".to_owned(), weight: 10.0 },
+    ///     GoodBoy { name: "Chonk".to_owned(), weight: f64::INFINITY },
+    ///     GoodBoy { name: "Abs. Unit".to_owned(), weight: f64::NAN },
+    ///     GoodBoy { name: "Floaty".to_owned(), weight: -5.0 },
+    /// ];
+    ///
+    /// bois.sort_by(|a, b| a.weight.total_cmp(&b.weight));
+    /// # assert!(bois.into_iter().map(|b| b.weight)
+    /// #     .zip([-5.0, 0.1, 10.0, 99.0, f64::INFINITY, f64::NAN].iter())
+    /// #     .all(|(a, b)| a.to_bits() == b.to_bits()))
+    /// ```
+    #[unstable(feature = "total_cmp", issue = "72599")]
+    #[inline]
+    pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering {
+        let mut left = self.to_bits() as i64;
+        let mut right = other.to_bits() as i64;
+
+        // In case of negatives, flip all the bits except the sign
+        // to achieve a similar layout as two's complement integers
+        //
+        // Why does this work? IEEE 754 floats consist of three fields:
+        // Sign bit, exponent and mantissa. The set of exponent and mantissa
+        // fields as a whole have the property that their bitwise order is
+        // equal to the numeric magnitude where the magnitude is defined.
+        // The magnitude is not normally defined on NaN values, but
+        // IEEE 754 totalOrder defines the NaN values also to follow the
+        // bitwise order. This leads to order explained in the doc comment.
+        // However, the representation of magnitude is the same for negative
+        // and positive numbers – only the sign bit is different.
+        // To easily compare the floats as signed integers, we need to
+        // flip the exponent and mantissa bits in case of negative numbers.
+        // We effectively convert the numbers to "two's complement" form.
+        //
+        // To do the flipping, we construct a mask and XOR against it.
+        // We branchlessly calculate an "all-ones except for the sign bit"
+        // mask from negative-signed values: right shifting sign-extends
+        // the integer, so we "fill" the mask with sign bits, and then
+        // convert to unsigned to push one more zero bit.
+        // On positive values, the mask is all zeros, so it's a no-op.
+        left ^= (((left >> 63) as u64) >> 1) as i64;
+        right ^= (((right >> 63) as u64) >> 1) as i64;
+
+        left.cmp(&right)
+    }
 }
diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs
index 52cf068f0a5..0265235a65a 100644
--- a/src/libcore/tests/iter.rs
+++ b/src/libcore/tests/iter.rs
@@ -813,6 +813,30 @@ fn test_iterator_peekable_rfold() {
     assert_eq!(i, xs.len());
 }
 
+#[test]
+fn test_iterator_peekable_next_if_eq() {
+    // first, try on references
+    let xs = vec!["Heart", "of", "Gold"];
+    let mut it = xs.into_iter().peekable();
+    // try before `peek()`
+    assert_eq!(it.next_if_eq(&"trillian"), None);
+    assert_eq!(it.next_if_eq(&"Heart"), Some("Heart"));
+    // try after peek()
+    assert_eq!(it.peek(), Some(&"of"));
+    assert_eq!(it.next_if_eq(&"of"), Some("of"));
+    assert_eq!(it.next_if_eq(&"zaphod"), None);
+    // make sure `next()` still behaves
+    assert_eq!(it.next(), Some("Gold"));
+
+    // make sure comparison works for owned values
+    let xs = vec![String::from("Ludicrous"), "speed".into()];
+    let mut it = xs.into_iter().peekable();
+    // make sure basic functionality works
+    assert_eq!(it.next_if_eq("Ludicrous"), Some("Ludicrous".into()));
+    assert_eq!(it.next_if_eq("speed"), Some("speed".into()));
+    assert_eq!(it.next_if_eq(""), None);
+}
+
 /// This is an iterator that follows the Iterator contract,
 /// but it is not fused. After having returned None once, it will start
 /// producing elements if .next() is called again.
diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs
index 6a8e908b9c6..37ebf411280 100644
--- a/src/libcore/tests/lib.rs
+++ b/src/libcore/tests/lib.rs
@@ -43,6 +43,7 @@
 #![feature(leading_trailing_ones)]
 #![feature(const_forget)]
 #![feature(option_unwrap_none)]
+#![feature(peekable_next_if)]
 
 extern crate test;