From 2a916a617f6c6c62536a3b164f4b15ea58eaa148 Mon Sep 17 00:00:00 2001 From: Jo Liss Date: Tue, 27 Jun 2017 17:23:31 +0000 Subject: [PATCH 1/3] Short-circuit Rc/Arc equality checking on equal pointers where T: Eq Closes #42655 --- src/liballoc/rc.rs | 25 +++++++++++++++++++++++-- src/liballoc/sync.rs | 26 +++++++++++++++++++++++--- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 52ad30c411a10..85bde5f63ce8e 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(specialization)] #![allow(deprecated)] //! Single-threaded reference-counting pointers. 'Rc' stands for 'Reference @@ -906,6 +907,9 @@ impl PartialEq for Rc { /// /// Two `Rc`s are equal if their inner values are equal. /// + /// If `T` also implements `Eq`, two `Rc`s that point to the same value are + /// always equal. + /// /// # Examples /// /// ``` @@ -916,7 +920,7 @@ impl PartialEq for Rc { /// assert!(five == Rc::new(5)); /// ``` #[inline(always)] - fn eq(&self, other: &Rc) -> bool { + default fn eq(&self, other: &Rc) -> bool { **self == **other } @@ -924,6 +928,9 @@ impl PartialEq for Rc { /// /// Two `Rc`s are unequal if their inner values are unequal. /// + /// If `T` also implements `Eq`, two `Rc`s that point to the same value are + /// never unequal. + /// /// # Examples /// /// ``` @@ -934,11 +941,25 @@ impl PartialEq for Rc { /// assert!(five != Rc::new(6)); /// ``` #[inline(always)] - fn ne(&self, other: &Rc) -> bool { + default fn ne(&self, other: &Rc) -> bool { **self != **other } } +#[doc(hidden)] +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for Rc { + #[inline(always)] + fn eq(&self, other: &Rc) -> bool { + Rc::ptr_eq(self, other) || **self == **other + } + + #[inline(always)] + fn ne(&self, other: &Rc) -> bool { + !Rc::ptr_eq(self, other) && **self != **other + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Eq for Rc {} diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index 111459d12a4df..d6863238cd4b6 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(specialization)] #![stable(feature = "rust1", since = "1.0.0")] //! Thread-safe reference-counting pointers. @@ -1293,6 +1294,9 @@ impl PartialEq for Arc { /// /// Two `Arc`s are equal if their inner values are equal. /// + /// If `T` also implements `Eq`, two `Arc`s that point to the same value are + /// always equal. + /// /// # Examples /// /// ``` @@ -1302,14 +1306,17 @@ impl PartialEq for Arc { /// /// assert!(five == Arc::new(5)); /// ``` - fn eq(&self, other: &Arc) -> bool { - *(*self) == *(*other) + default fn eq(&self, other: &Arc) -> bool { + **self == **other } /// Inequality for two `Arc`s. /// /// Two `Arc`s are unequal if their inner values are unequal. /// + /// If `T` also implements `Eq`, two `Arc`s that point to the same value are + /// never unequal. + /// /// # Examples /// /// ``` @@ -1319,8 +1326,21 @@ impl PartialEq for Arc { /// /// assert!(five != Arc::new(6)); /// ``` + default fn ne(&self, other: &Arc) -> bool { + **self != **other + } +} +#[doc(hidden)] +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for Arc { + #[inline(always)] + fn eq(&self, other: &Arc) -> bool { + Arc::ptr_eq(self, other) || **self == **other + } + + #[inline(always)] fn ne(&self, other: &Arc) -> bool { - *(*self) != *(*other) + !Arc::ptr_eq(self, other) && **self != **other } } #[stable(feature = "rust1", since = "1.0.0")] From 40d60a4608c76e8a74ab643f4629dbaf129e07a4 Mon Sep 17 00:00:00 2001 From: Thomas Heck Date: Wed, 5 Dec 2018 21:43:44 +0100 Subject: [PATCH 2/3] Use private trait for Rc/Arc Eq specialization --- src/liballoc/rc.rs | 57 ++++++++++++++++++++++++++++---------------- src/liballoc/sync.rs | 54 ++++++++++++++++++++++++++++------------- 2 files changed, 74 insertions(+), 37 deletions(-) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 85bde5f63ce8e..6769a70ddbe0a 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(specialization)] #![allow(deprecated)] //! Single-threaded reference-counting pointers. 'Rc' stands for 'Reference @@ -901,6 +900,38 @@ impl Default for Rc { } } +#[stable(feature = "rust1", since = "1.0.0")] +trait RcEqIdent { + fn eq(&self, other: &Rc) -> bool; + fn ne(&self, other: &Rc) -> bool; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl RcEqIdent for Rc { + #[inline] + default fn eq(&self, other: &Rc) -> bool { + **self == **other + } + + #[inline] + default fn ne(&self, other: &Rc) -> bool { + **self != **other + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl RcEqIdent for Rc { + #[inline] + fn eq(&self, other: &Rc) -> bool { + Rc::ptr_eq(self, other) || **self == **other + } + + #[inline] + fn ne(&self, other: &Rc) -> bool { + !Rc::ptr_eq(self, other) && **self != **other + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for Rc { /// Equality for two `Rc`s. @@ -919,9 +950,9 @@ impl PartialEq for Rc { /// /// assert!(five == Rc::new(5)); /// ``` - #[inline(always)] - default fn eq(&self, other: &Rc) -> bool { - **self == **other + #[inline] + fn eq(&self, other: &Rc) -> bool { + RcEqIdent::eq(self, other) } /// Inequality for two `Rc`s. @@ -940,23 +971,9 @@ impl PartialEq for Rc { /// /// assert!(five != Rc::new(6)); /// ``` - #[inline(always)] - default fn ne(&self, other: &Rc) -> bool { - **self != **other - } -} - -#[doc(hidden)] -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for Rc { - #[inline(always)] - fn eq(&self, other: &Rc) -> bool { - Rc::ptr_eq(self, other) || **self == **other - } - - #[inline(always)] + #[inline] fn ne(&self, other: &Rc) -> bool { - !Rc::ptr_eq(self, other) && **self != **other + RcEqIdent::ne(self, other) } } diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index d6863238cd4b6..e596694fb9d4b 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(specialization)] #![stable(feature = "rust1", since = "1.0.0")] //! Thread-safe reference-counting pointers. @@ -1288,6 +1287,37 @@ impl Drop for Weak { } } +#[stable(feature = "rust1", since = "1.0.0")] +trait ArcEqIdent { + fn eq(&self, other: &Arc) -> bool; + fn ne(&self, other: &Arc) -> bool; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ArcEqIdent for Arc { + #[inline] + default fn eq(&self, other: &Arc) -> bool { + **self == **other + } + #[inline] + default fn ne(&self, other: &Arc) -> bool { + **self != **other + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ArcEqIdent for Arc { + #[inline] + fn eq(&self, other: &Arc) -> bool { + Arc::ptr_eq(self, other) || **self == **other + } + + #[inline] + fn ne(&self, other: &Arc) -> bool { + !Arc::ptr_eq(self, other) && **self != **other + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for Arc { /// Equality for two `Arc`s. @@ -1306,8 +1336,9 @@ impl PartialEq for Arc { /// /// assert!(five == Arc::new(5)); /// ``` - default fn eq(&self, other: &Arc) -> bool { - **self == **other + #[inline] + fn eq(&self, other: &Arc) -> bool { + ArcEqIdent::eq(self, other) } /// Inequality for two `Arc`s. @@ -1326,23 +1357,12 @@ impl PartialEq for Arc { /// /// assert!(five != Arc::new(6)); /// ``` - default fn ne(&self, other: &Arc) -> bool { - **self != **other - } -} -#[doc(hidden)] -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for Arc { - #[inline(always)] - fn eq(&self, other: &Arc) -> bool { - Arc::ptr_eq(self, other) || **self == **other - } - - #[inline(always)] + #[inline] fn ne(&self, other: &Arc) -> bool { - !Arc::ptr_eq(self, other) && **self != **other + ArcEqIdent::ne(self, other) } } + #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for Arc { /// Partial comparison for two `Arc`s. From d828c22bd6ff6059c75dfa63e024997619eb6e7c Mon Sep 17 00:00:00 2001 From: Thomas Heck Date: Sat, 8 Dec 2018 09:35:23 +0100 Subject: [PATCH 3/3] Add Arc/Rc Eq tests --- src/liballoc/tests/arc.rs | 42 +++++++++++++++++++++++++++++++++++++++ src/liballoc/tests/rc.rs | 42 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/src/liballoc/tests/arc.rs b/src/liballoc/tests/arc.rs index d90c22a3b1892..ec589710216c3 100644 --- a/src/liballoc/tests/arc.rs +++ b/src/liballoc/tests/arc.rs @@ -10,6 +10,8 @@ use std::any::Any; use std::sync::{Arc, Weak}; +use std::cell::RefCell; +use std::cmp::PartialEq; #[test] fn uninhabited() { @@ -53,3 +55,43 @@ fn trait_object() { b = b.clone(); assert!(b.upgrade().is_none()); } + +#[test] +fn float_nan_ne() { + let x = Arc::new(std::f32::NAN); + assert!(x != x); + assert!(!(x == x)); +} + +#[test] +fn partial_eq() { + struct TestPEq (RefCell); + impl PartialEq for TestPEq { + fn eq(&self, other: &TestPEq) -> bool { + *self.0.borrow_mut() += 1; + *other.0.borrow_mut() += 1; + true + } + } + let x = Arc::new(TestPEq(RefCell::new(0))); + assert!(x == x); + assert!(!(x != x)); + assert_eq!(*x.0.borrow(), 4); +} + +#[test] +fn eq() { + #[derive(Eq)] + struct TestEq (RefCell); + impl PartialEq for TestEq { + fn eq(&self, other: &TestEq) -> bool { + *self.0.borrow_mut() += 1; + *other.0.borrow_mut() += 1; + true + } + } + let x = Arc::new(TestEq(RefCell::new(0))); + assert!(x == x); + assert!(!(x != x)); + assert_eq!(*x.0.borrow(), 0); +} diff --git a/src/liballoc/tests/rc.rs b/src/liballoc/tests/rc.rs index 9ec7c831444d1..02e1dfe13bb36 100644 --- a/src/liballoc/tests/rc.rs +++ b/src/liballoc/tests/rc.rs @@ -10,6 +10,8 @@ use std::any::Any; use std::rc::{Rc, Weak}; +use std::cell::RefCell; +use std::cmp::PartialEq; #[test] fn uninhabited() { @@ -53,3 +55,43 @@ fn trait_object() { b = b.clone(); assert!(b.upgrade().is_none()); } + +#[test] +fn float_nan_ne() { + let x = Rc::new(std::f32::NAN); + assert!(x != x); + assert!(!(x == x)); +} + +#[test] +fn partial_eq() { + struct TestPEq (RefCell); + impl PartialEq for TestPEq { + fn eq(&self, other: &TestPEq) -> bool { + *self.0.borrow_mut() += 1; + *other.0.borrow_mut() += 1; + true + } + } + let x = Rc::new(TestPEq(RefCell::new(0))); + assert!(x == x); + assert!(!(x != x)); + assert_eq!(*x.0.borrow(), 4); +} + +#[test] +fn eq() { + #[derive(Eq)] + struct TestEq (RefCell); + impl PartialEq for TestEq { + fn eq(&self, other: &TestEq) -> bool { + *self.0.borrow_mut() += 1; + *other.0.borrow_mut() += 1; + true + } + } + let x = Rc::new(TestEq(RefCell::new(0))); + assert!(x == x); + assert!(!(x != x)); + assert_eq!(*x.0.borrow(), 0); +}