Skip to content

Commit 16dd426

Browse files
authored
Rollup merge of rust-lang#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.
2 parents 383c4db + ec7a585 commit 16dd426

File tree

1 file changed

+23
-2
lines changed

1 file changed

+23
-2
lines changed

core/src/net/ip_addr.rs

+23-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use super::display_buffer::DisplayBuffer;
22
use crate::cmp::Ordering;
33
use crate::fmt::{self, Write};
4+
use crate::hash::{Hash, Hasher};
45
use crate::iter;
56
use crate::mem::transmute;
67
use crate::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not};
@@ -67,12 +68,22 @@ pub enum IpAddr {
6768
/// assert!("0000000.0.0.0".parse::<Ipv4Addr>().is_err()); // first octet is a zero in octal
6869
/// assert!("0xcb.0x0.0x71.0x00".parse::<Ipv4Addr>().is_err()); // all octets are in hex
6970
/// ```
70-
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
71+
#[derive(Copy, Clone, PartialEq, Eq)]
7172
#[stable(feature = "rust1", since = "1.0.0")]
7273
pub struct Ipv4Addr {
7374
octets: [u8; 4],
7475
}
7576

77+
#[stable(feature = "rust1", since = "1.0.0")]
78+
impl Hash for Ipv4Addr {
79+
fn hash<H: Hasher>(&self, state: &mut H) {
80+
// Hashers are often more efficient at hashing a fixed-width integer
81+
// than a bytestring, so convert before hashing. We don't use to_bits()
82+
// here as that may involve a byteswap which is unnecessary.
83+
u32::from_ne_bytes(self.octets).hash(state);
84+
}
85+
}
86+
7687
/// An IPv6 address.
7788
///
7889
/// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291].
@@ -149,12 +160,22 @@ pub struct Ipv4Addr {
149160
/// assert_eq!("::1".parse(), Ok(localhost));
150161
/// assert_eq!(localhost.is_loopback(), true);
151162
/// ```
152-
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
163+
#[derive(Copy, Clone, PartialEq, Eq)]
153164
#[stable(feature = "rust1", since = "1.0.0")]
154165
pub struct Ipv6Addr {
155166
octets: [u8; 16],
156167
}
157168

169+
#[stable(feature = "rust1", since = "1.0.0")]
170+
impl Hash for Ipv6Addr {
171+
fn hash<H: Hasher>(&self, state: &mut H) {
172+
// Hashers are often more efficient at hashing a fixed-width integer
173+
// than a bytestring, so convert before hashing. We don't use to_bits()
174+
// here as that may involve unnecessary byteswaps.
175+
u128::from_ne_bytes(self.octets).hash(state);
176+
}
177+
}
178+
158179
/// Scope of an [IPv6 multicast address] as defined in [IETF RFC 7346 section 2].
159180
///
160181
/// # Stability Guarantees

0 commit comments

Comments
 (0)