about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-08-15 00:02:25 +0200
committerGitHub <noreply@github.com>2024-08-15 00:02:25 +0200
commitcd1b42c3e9a2f60c3fae428ef839514b7e97eb0e (patch)
treed28ec5fa9601e0e3b9ab046377f790297bda521c
parent9938349c7167fb5abd6381b4441e735504d522b6 (diff)
parentfce1decc3c6508aa72f590d024e583dd5c0cf04d (diff)
downloadrust-cd1b42c3e9a2f60c3fae428ef839514b7e97eb0e.tar.gz
rust-cd1b42c3e9a2f60c3fae428ef839514b7e97eb0e.zip
Rollup merge of #128946 - orlp:faster-ip-hash, r=joboet
Hash Ipv*Addr as an integer

The `Ipv4Addr` and `Ipv6Addr` structs always have a fixed size, but directly derive `Hash`. This causes them to call the bytestring hasher implementation, which adds extra work for most hashers. This PR converts the internal representation to a fixed-width integer before passing to the hasher to prevent this.
-rw-r--r--library/core/src/net/ip_addr.rs25
1 files changed, 23 insertions, 2 deletions
diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs
index 3e036b88128..919f681f911 100644
--- a/library/core/src/net/ip_addr.rs
+++ b/library/core/src/net/ip_addr.rs
@@ -1,6 +1,7 @@
 use super::display_buffer::DisplayBuffer;
 use crate::cmp::Ordering;
 use crate::fmt::{self, Write};
+use crate::hash::{Hash, Hasher};
 use crate::iter;
 use crate::mem::transmute;
 use crate::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not};
@@ -67,12 +68,22 @@ pub enum IpAddr {
 /// assert!("0000000.0.0.0".parse::<Ipv4Addr>().is_err()); // first octet is a zero in octal
 /// assert!("0xcb.0x0.0x71.0x00".parse::<Ipv4Addr>().is_err()); // all octets are in hex
 /// ```
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Ipv4Addr {
     octets: [u8; 4],
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Hash for Ipv4Addr {
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        // Hashers are often more efficient at hashing a fixed-width integer
+        // than a bytestring, so convert before hashing. We don't use to_bits()
+        // here as that may involve a byteswap which is unnecessary.
+        u32::from_ne_bytes(self.octets).hash(state);
+    }
+}
+
 /// An IPv6 address.
 ///
 /// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291].
@@ -149,12 +160,22 @@ pub struct Ipv4Addr {
 /// assert_eq!("::1".parse(), Ok(localhost));
 /// assert_eq!(localhost.is_loopback(), true);
 /// ```
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Ipv6Addr {
     octets: [u8; 16],
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Hash for Ipv6Addr {
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        // Hashers are often more efficient at hashing a fixed-width integer
+        // than a bytestring, so convert before hashing. We don't use to_bits()
+        // here as that may involve unnecessary byteswaps.
+        u128::from_ne_bytes(self.octets).hash(state);
+    }
+}
+
 /// Scope of an [IPv6 multicast address] as defined in [IETF RFC 7346 section 2].
 ///
 /// # Stability Guarantees