diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2024-08-15 00:02:25 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-08-15 00:02:25 +0200 |
| commit | cd1b42c3e9a2f60c3fae428ef839514b7e97eb0e (patch) | |
| tree | d28ec5fa9601e0e3b9ab046377f790297bda521c | |
| parent | 9938349c7167fb5abd6381b4441e735504d522b6 (diff) | |
| parent | fce1decc3c6508aa72f590d024e583dd5c0cf04d (diff) | |
| download | rust-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.rs | 25 |
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 |
