Skip to content

Commit 332db4d

Browse files
committed
Prepare hashbrown for inclusion in the standard library
1 parent edf79d0 commit 332db4d

File tree

8 files changed

+797
-174
lines changed

8 files changed

+797
-174
lines changed

Cargo.toml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ categories = ["data-structures", "no-std"]
1111
exclude = [".travis.yml", "bors.toml"]
1212

1313
[dependencies]
14-
byteorder = { version = "1.0", default-features = false }
15-
scopeguard = { version = "0.3", default-features = false }
16-
1714
# For external trait impls
1815
rayon = { version = "1.0", optional = true }
1916
serde = { version = "1.0.25", default-features = false, optional = true }
2017

18+
# When built as part of libstd
19+
core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" }
20+
compiler_builtins = { version = "0.1.2", optional = true }
21+
alloc = { version = "1.0.0", optional = true, package = "rustc-std-workspace-alloc" }
22+
2123
[dev-dependencies]
2224
lazy_static = "~1.2"
2325
rand = "0.5.1"
@@ -28,3 +30,4 @@ serde_test = "1.0"
2830
[features]
2931
default = []
3032
nightly = []
33+
rustc-dep-of-std = ["nightly", "core", "compiler_builtins", "alloc"]

src/fx.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ use core::hash::{BuildHasherDefault, Hasher};
55
use core::mem::size_of;
66
use core::ops::BitXor;
77

8-
use byteorder::{ByteOrder, NativeEndian};
9-
108
/// Type alias for a `HashBuilder` using the `fx` hash algorithm.
119
pub type FxHashBuilder = BuildHasherDefault<FxHasher>;
1210

@@ -47,25 +45,29 @@ impl FxHasher {
4745
impl Hasher for FxHasher {
4846
#[inline]
4947
fn write(&mut self, mut bytes: &[u8]) {
50-
#[cfg(target_pointer_width = "32")]
51-
#[allow(clippy::cast_possible_truncation)]
52-
let read_usize = |bytes| NativeEndian::read_u32(bytes) as usize;
53-
#[cfg(target_pointer_width = "64")]
54-
#[allow(clippy::cast_possible_truncation)]
55-
let read_usize = |bytes| NativeEndian::read_u64(bytes) as usize;
48+
macro_rules! read_bytes {
49+
($ty:ty, $src:expr) => {{
50+
assert!(size_of::<$ty>() <= $src.len());
51+
let mut data: $ty = 0;
52+
unsafe {
53+
$src.as_ptr().copy_to_nonoverlapping(&mut data as *mut $ty as *mut u8, size_of::<$ty>());
54+
}
55+
data
56+
}};
57+
}
5658

5759
let mut hash = Self { hash: self.hash };
5860
assert!(size_of::<usize>() <= 8);
5961
while bytes.len() >= size_of::<usize>() {
60-
hash.add_to_hash(read_usize(bytes));
62+
hash.add_to_hash(read_bytes!(usize, bytes) as usize);
6163
bytes = &bytes[size_of::<usize>()..];
6264
}
6365
if (size_of::<usize>() > 4) && (bytes.len() >= 4) {
64-
hash.add_to_hash(NativeEndian::read_u32(bytes) as usize);
66+
hash.add_to_hash(read_bytes!(u32, bytes) as usize);
6567
bytes = &bytes[4..];
6668
}
6769
if (size_of::<usize>() > 2) && bytes.len() >= 2 {
68-
hash.add_to_hash(NativeEndian::read_u16(bytes) as usize);
70+
hash.add_to_hash(read_bytes!(u16, bytes) as usize);
6971
bytes = &bytes[2..];
7072
}
7173
if (size_of::<usize>() > 1) && !bytes.is_empty() {

src/lib.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,16 @@
2626
#![allow(clippy::module_name_repetitions)]
2727

2828
#[cfg(test)]
29-
#[macro_use]
30-
#[allow(unused_imports)]
29+
#[cfg_attr(feature = "rayon", macro_use)]
3130
extern crate std;
3231
#[cfg(test)]
3332
extern crate rand;
3433

3534
#[cfg(feature = "nightly")]
3635
#[cfg_attr(test, macro_use)]
3736
extern crate alloc;
38-
extern crate byteorder;
3937
#[cfg(feature = "rayon")]
4038
extern crate rayon;
41-
extern crate scopeguard;
4239
#[cfg(feature = "serde")]
4340
extern crate serde;
4441
#[cfg(not(feature = "nightly"))]
@@ -53,11 +50,16 @@ mod fx;
5350
mod map;
5451
mod raw;
5552
mod set;
53+
#[cfg(feature = "rustc-dep-of-std")]
54+
mod rustc_entry;
5655

5756
pub mod hash_map {
5857
//! A hash map implemented with quadratic probing and SIMD lookup.
5958
pub use map::*;
6059

60+
#[cfg(feature = "rustc-dep-of-std")]
61+
pub use rustc_entry::*;
62+
6163
#[cfg(feature = "rayon")]
6264
/// [rayon]-based parallel iterator types for hash maps.
6365
/// You will rarely need to interact with it directly unless you have need

src/map.rs

Lines changed: 14 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ pub use fx::FxHashBuilder as DefaultHashBuilder;
150150
/// }
151151
///
152152
/// impl Viking {
153-
/// /// Create a new Viking.
153+
/// /// Creates a new Viking.
154154
/// fn new(name: &str, country: &str) -> Viking {
155155
/// Viking { name: name.to_string(), country: country.to_string() }
156156
/// }
@@ -186,12 +186,12 @@ pub use fx::FxHashBuilder as DefaultHashBuilder;
186186
187187
#[derive(Clone)]
188188
pub struct HashMap<K, V, S = DefaultHashBuilder> {
189-
hash_builder: S,
189+
pub(crate) hash_builder: S,
190190
pub(crate) table: RawTable<(K, V)>,
191191
}
192192

193193
#[inline]
194-
fn make_hash<K: Hash + ?Sized>(hash_builder: &impl BuildHasher, val: &K) -> u64 {
194+
pub(crate) fn make_hash<K: Hash + ?Sized>(hash_builder: &impl BuildHasher, val: &K) -> u64 {
195195
let mut state = hash_builder.build_hasher();
196196
val.hash(&mut state);
197197
state.finish()
@@ -232,8 +232,6 @@ impl<K, V> HashMap<K, V, DefaultHashBuilder> {
232232
}
233233

234234
impl<K, V, S> HashMap<K, V, S>
235-
where
236-
S: BuildHasher,
237235
{
238236
/// Creates an empty `HashMap` which will use the given hash builder to hash
239237
/// keys.
@@ -486,7 +484,7 @@ where
486484
self.table.len()
487485
}
488486

489-
/// Returns true if the map contains no elements.
487+
/// Returns `true` if the map contains no elements.
490488
///
491489
/// # Examples
492490
///
@@ -757,7 +755,7 @@ where
757755
})
758756
}
759757

760-
/// Returns true if the map contains a value for the specified key.
758+
/// Returns `true` if the map contains a value for the specified key.
761759
///
762760
/// The key may be any borrowed form of the map's key type, but
763761
/// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
@@ -1220,7 +1218,7 @@ impl<'a, K, V: Debug> fmt::Debug for Values<'a, K, V> {
12201218
/// [`drain`]: struct.HashMap.html#method.drain
12211219
/// [`HashMap`]: struct.HashMap.html
12221220
pub struct Drain<'a, K: 'a, V: 'a> {
1223-
pub(super) inner: RawDrain<'a, (K, V)>,
1221+
inner: RawDrain<'a, (K, V)>,
12241222
}
12251223

12261224
impl<'a, K, V> Drain<'a, K, V> {
@@ -1300,9 +1298,8 @@ pub struct RawEntryBuilder<'a, K: 'a, V: 'a, S: 'a> {
13001298
impl<'a, K, V, S> RawEntryBuilderMut<'a, K, V, S>
13011299
where
13021300
S: BuildHasher,
1303-
K: Eq + Hash,
13041301
{
1305-
/// Create a `RawEntryMut` from the given key.
1302+
/// Creates a `RawEntryMut` from the given key.
13061303
#[inline]
13071304
#[allow(clippy::wrong_self_convention)]
13081305
pub fn from_key<Q: ?Sized>(self, k: &Q) -> RawEntryMut<'a, K, V, S>
@@ -1315,7 +1312,7 @@ where
13151312
self.from_key_hashed_nocheck(hasher.finish(), k)
13161313
}
13171314

1318-
/// Create a `RawEntryMut` from the given key and its hash.
1315+
/// Creates a `RawEntryMut` from the given key and its hash.
13191316
#[inline]
13201317
#[allow(clippy::wrong_self_convention)]
13211318
pub fn from_key_hashed_nocheck<Q: ?Sized>(self, hash: u64, k: &Q) -> RawEntryMut<'a, K, V, S>
@@ -1331,7 +1328,7 @@ impl<'a, K, V, S> RawEntryBuilderMut<'a, K, V, S>
13311328
where
13321329
S: BuildHasher,
13331330
{
1334-
/// Create a `RawEntryMut` from the given hash.
1331+
/// Creates a `RawEntryMut` from the given hash.
13351332
#[inline]
13361333
#[allow(clippy::wrong_self_convention)]
13371334
pub fn from_hash<F>(self, hash: u64, is_match: F) -> RawEntryMut<'a, K, V, S>
@@ -1706,7 +1703,7 @@ pub enum Entry<'a, K: 'a, V: 'a, S: 'a> {
17061703
Vacant(VacantEntry<'a, K, V, S>),
17071704
}
17081705

1709-
impl<'a, K: 'a + Debug + Eq + Hash, V: 'a + Debug, S: 'a> Debug for Entry<'a, K, V, S> {
1706+
impl<'a, K: 'a + Debug, V: 'a + Debug, S: 'a> Debug for Entry<'a, K, V, S> {
17101707
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
17111708
match *self {
17121709
Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(),
@@ -1759,17 +1756,13 @@ pub struct VacantEntry<'a, K: 'a, V: 'a, S: 'a> {
17591756
table: &'a mut HashMap<K, V, S>,
17601757
}
17611758

1762-
impl<'a, K: 'a + Debug + Eq + Hash, V: 'a, S> Debug for VacantEntry<'a, K, V, S> {
1759+
impl<'a, K: 'a + Debug, V: 'a, S> Debug for VacantEntry<'a, K, V, S> {
17631760
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
17641761
f.debug_tuple("VacantEntry").field(self.key()).finish()
17651762
}
17661763
}
17671764

1768-
impl<'a, K, V, S> IntoIterator for &'a HashMap<K, V, S>
1769-
where
1770-
K: Eq + Hash,
1771-
S: BuildHasher,
1772-
{
1765+
impl<'a, K, V, S> IntoIterator for &'a HashMap<K, V, S> {
17731766
type Item = (&'a K, &'a V);
17741767
type IntoIter = Iter<'a, K, V>;
17751768

@@ -1779,11 +1772,7 @@ where
17791772
}
17801773
}
17811774

1782-
impl<'a, K, V, S> IntoIterator for &'a mut HashMap<K, V, S>
1783-
where
1784-
K: Eq + Hash,
1785-
S: BuildHasher,
1786-
{
1775+
impl<'a, K, V, S> IntoIterator for &'a mut HashMap<K, V, S> {
17871776
type Item = (&'a K, &'a mut V);
17881777
type IntoIter = IterMut<'a, K, V>;
17891778

@@ -1793,11 +1782,7 @@ where
17931782
}
17941783
}
17951784

1796-
impl<K, V, S> IntoIterator for HashMap<K, V, S>
1797-
where
1798-
K: Eq + Hash,
1799-
S: BuildHasher,
1800-
{
1785+
impl<K, V, S> IntoIterator for HashMap<K, V, S> {
18011786
type Item = (K, V);
18021787
type IntoIter = IntoIter<K, V>;
18031788

src/raw/mod.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use core::mem;
77
use core::mem::ManuallyDrop;
88
use core::ops::Range;
99
use core::ptr::NonNull;
10-
use scopeguard::guard;
1110
use CollectionAllocErr;
1211

1312
// Branch prediction hint. This is currently only available on nightly but it
@@ -60,6 +59,9 @@ cfg_if! {
6059

6160
mod bitmask;
6261

62+
mod scopeguard;
63+
64+
use self::scopeguard::guard;
6365
use self::bitmask::BitMask;
6466
use self::imp::Group;
6567

@@ -714,8 +716,10 @@ impl<T> RawTable<T> {
714716
// This may panic.
715717
let hash = hasher(item.as_ref());
716718

717-
// We can use a simpler version of insert() here since there are no
718-
// DELETED entries.
719+
// We can use a simpler version of insert() here since:
720+
// - there are no DELETED entries.
721+
// - we know there is enough space in the table.
722+
// - all elements are unique.
719723
let index = new_table.find_insert_slot(hash);
720724
new_table.set_ctrl(index, h2(hash));
721725
new_table.bucket(index).write(item.read());
@@ -737,7 +741,16 @@ impl<T> RawTable<T> {
737741
#[inline]
738742
pub fn insert(&mut self, hash: u64, value: T, hasher: impl Fn(&T) -> u64) -> Bucket<T> {
739743
self.reserve(1, hasher);
744+
self.insert_no_grow(hash, value)
745+
}
740746

747+
/// Inserts a new element into the table, without growing the table.
748+
///
749+
/// There must be enough space in the table to insert the new element.
750+
///
751+
/// This does not check if the given element already exists in the table.
752+
#[inline]
753+
pub fn insert_no_grow(&mut self, hash: u64, value: T) -> Bucket<T> {
741754
unsafe {
742755
let index = self.find_insert_slot(hash);
743756
let bucket = self.bucket(index);
@@ -941,7 +954,7 @@ impl<T> IntoIterator for RawTable<T> {
941954
}
942955
}
943956

944-
/// Iterator over a a sub-range of a table. Unlike `RawIter` this iterator does
957+
/// Iterator over a sub-range of a table. Unlike `RawIter` this iterator does
945958
/// not track an item count.
946959
pub struct RawIterRange<T> {
947960
// Using *const here for covariance

src/raw/scopeguard.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Extracted from the scopeguard crate
2+
use core::ops::{Deref, DerefMut};
3+
4+
pub struct ScopeGuard<T, F>
5+
where
6+
F: FnMut(&mut T),
7+
{
8+
dropfn: F,
9+
value: T,
10+
}
11+
12+
#[inline]
13+
pub fn guard<T, F>(value: T, dropfn: F) -> ScopeGuard<T, F>
14+
where
15+
F: FnMut(&mut T),
16+
{
17+
ScopeGuard { dropfn, value }
18+
}
19+
20+
impl<T, F> Deref for ScopeGuard<T, F>
21+
where
22+
F: FnMut(&mut T),
23+
{
24+
type Target = T;
25+
#[inline]
26+
fn deref(&self) -> &T {
27+
&self.value
28+
}
29+
}
30+
31+
impl<T, F> DerefMut for ScopeGuard<T, F>
32+
where
33+
F: FnMut(&mut T),
34+
{
35+
#[inline]
36+
fn deref_mut(&mut self) -> &mut T {
37+
&mut self.value
38+
}
39+
}
40+
41+
impl<T, F> Drop for ScopeGuard<T, F>
42+
where
43+
F: FnMut(&mut T),
44+
{
45+
#[inline]
46+
fn drop(&mut self) {
47+
(self.dropfn)(&mut self.value)
48+
}
49+
}

0 commit comments

Comments
 (0)