Skip to content

Commit aa1411b

Browse files
committed
Auto merge of #546 - Amanieu:remove-raw, r=Amanieu
Remove the `raw` feature and make `RawTable` private This will give more freedom for the internal implementation details of hashbrown to evolve without the need for regular releases with breaking changes. All existing users of `RawTable` should migrate to the `HashTable` API which is entirely safe while providing the same flexibility as `RawTable`. This also removes the following features which were only exposed under `RawTable`: - `RawTable::iter_hash` - `RawIter::reflect_insert` and `RawIter::reflect_remove` - `RawTable::clone_from_with_hasher` - `RawTable::insert_no_grow` and `RawTable::try_insert_no_grow` - `RawTable::allocation_info` - `RawTable::try_with_capacity(_in)` - `HashMap::raw_table(_mut)` and `HashSet::raw_table(_mut)` If anyone was previously relying on this functionaly, please raise a comment. It may be possible to re-introduce it as a safe API in `HashTable` and/or `HashMap`.
2 parents f1ba3b4 + 26ef4a1 commit aa1411b

File tree

10 files changed

+4
-807
lines changed

10 files changed

+4
-807
lines changed

Diff for: Cargo.toml

+1-4
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,6 @@ rustc-dep-of-std = [
6767
"raw-entry",
6868
]
6969

70-
# Enables the experimental and unsafe RawTable API.
71-
raw = []
72-
7370
# Enables the deprecated RawEntry API.
7471
raw-entry = []
7572

@@ -84,5 +81,5 @@ default-hasher = ["dep:ahash"]
8481
inline-more = []
8582

8683
[package.metadata.docs.rs]
87-
features = ["nightly", "rayon", "serde", "raw"]
84+
features = ["nightly", "rayon", "serde", "raw-entry"]
8885
rustdoc-args = ["--generate-link-to-definition"]

Diff for: README.md

-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,6 @@ This crate has the following Cargo features:
105105
- `rkyv`: Enables rkyv serialization support.
106106
- `rayon`: Enables rayon parallel iterator support.
107107
- `equivalent`: Allows comparisons to be customized with the `Equivalent` trait.
108-
- `raw`: Enables access to the experimental and unsafe `RawTable` API.
109108
- `raw-entry`: Enables access to the deprecated `RawEntry` API.
110109
- `inline-more`: Adds inline hints to most functions, improving run-time performance at the cost
111110
of compilation time. (enabled by default)

Diff for: ci/run.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ if [ "${NO_STD}" = "1" ]; then
3333
FEATURES="rustc-internal-api"
3434
OP="build"
3535
else
36-
FEATURES="rustc-internal-api,serde,rayon,raw"
36+
FEATURES="rustc-internal-api,serde,rayon"
3737
OP="test"
3838
fi
3939

Diff for: ci/tools.sh

-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ fi
3131

3232
if retry rustup component add clippy ; then
3333
cargo clippy --all --tests --features serde,rayon -- -D clippy::all
34-
cargo clippy --all --tests --features raw -- -D clippy::all
3534
fi
3635

3736
if command -v shellcheck ; then

Diff for: src/lib.rs

-21
Original file line numberDiff line numberDiff line change
@@ -61,27 +61,6 @@ doc_comment::doctest!("../README.md");
6161
#[macro_use]
6262
mod macros;
6363

64-
#[cfg(feature = "raw")]
65-
/// Experimental and unsafe `RawTable` API. This module is only available if the
66-
/// `raw` feature is enabled.
67-
pub mod raw {
68-
// The RawTable API is still experimental and is not properly documented yet.
69-
#[allow(missing_docs)]
70-
#[path = "mod.rs"]
71-
mod inner;
72-
pub use inner::*;
73-
74-
#[cfg(feature = "rayon")]
75-
/// [rayon]-based parallel iterator types for hash maps.
76-
/// You will rarely need to interact with it directly unless you have need
77-
/// to name one of the iterator types.
78-
///
79-
/// [rayon]: https://docs.rs/rayon/1.0/rayon
80-
pub mod rayon {
81-
pub use crate::external_trait_impls::rayon::raw::*;
82-
}
83-
}
84-
#[cfg(not(feature = "raw"))]
8564
mod raw;
8665

8766
mod external_trait_impls;

Diff for: src/map.rs

-143
Original file line numberDiff line numberDiff line change
@@ -1931,81 +1931,6 @@ where
19311931
}
19321932
}
19331933

1934-
impl<K, V, S, A: Allocator> HashMap<K, V, S, A> {
1935-
/// Returns a reference to the [`RawTable`] used underneath [`HashMap`].
1936-
/// This function is only available if the `raw` feature of the crate is enabled.
1937-
///
1938-
/// See [`raw_table_mut`] for more.
1939-
///
1940-
/// [`raw_table_mut`]: Self::raw_table_mut
1941-
#[cfg(feature = "raw")]
1942-
#[cfg_attr(feature = "inline-more", inline)]
1943-
pub fn raw_table(&self) -> &RawTable<(K, V), A> {
1944-
&self.table
1945-
}
1946-
1947-
/// Returns a mutable reference to the [`RawTable`] used underneath [`HashMap`].
1948-
/// This function is only available if the `raw` feature of the crate is enabled.
1949-
///
1950-
/// # Note
1951-
///
1952-
/// Calling this function is safe, but using the raw hash table API may require
1953-
/// unsafe functions or blocks.
1954-
///
1955-
/// `RawTable` API gives the lowest level of control under the map that can be useful
1956-
/// for extending the HashMap's API, but may lead to *[undefined behavior]*.
1957-
///
1958-
/// [`HashMap`]: struct.HashMap.html
1959-
/// [`RawTable`]: crate::raw::RawTable
1960-
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
1961-
///
1962-
/// # Examples
1963-
///
1964-
/// ```
1965-
/// use core::hash::{BuildHasher, Hash};
1966-
/// use hashbrown::HashMap;
1967-
///
1968-
/// let mut map = HashMap::new();
1969-
/// map.extend([("a", 10), ("b", 20), ("c", 30)]);
1970-
/// assert_eq!(map.len(), 3);
1971-
///
1972-
/// // Let's imagine that we have a value and a hash of the key, but not the key itself.
1973-
/// // However, if you want to remove the value from the map by hash and value, and you
1974-
/// // know exactly that the value is unique, then you can create a function like this:
1975-
/// fn remove_by_hash<K, V, S, F>(
1976-
/// map: &mut HashMap<K, V, S>,
1977-
/// hash: u64,
1978-
/// is_match: F,
1979-
/// ) -> Option<(K, V)>
1980-
/// where
1981-
/// F: Fn(&(K, V)) -> bool,
1982-
/// {
1983-
/// let raw_table = map.raw_table_mut();
1984-
/// match raw_table.find(hash, is_match) {
1985-
/// Some(bucket) => Some(unsafe { raw_table.remove(bucket).0 }),
1986-
/// None => None,
1987-
/// }
1988-
/// }
1989-
///
1990-
/// fn compute_hash<K: Hash + ?Sized, S: BuildHasher>(hash_builder: &S, key: &K) -> u64 {
1991-
/// use core::hash::Hasher;
1992-
/// let mut state = hash_builder.build_hasher();
1993-
/// key.hash(&mut state);
1994-
/// state.finish()
1995-
/// }
1996-
///
1997-
/// let hash = compute_hash(map.hasher(), "a");
1998-
/// assert_eq!(remove_by_hash(&mut map, hash, |(_, v)| *v == 10), Some(("a", 10)));
1999-
/// assert_eq!(map.get(&"a"), None);
2000-
/// assert_eq!(map.len(), 2);
2001-
/// ```
2002-
#[cfg(feature = "raw")]
2003-
#[cfg_attr(feature = "inline-more", inline)]
2004-
pub fn raw_table_mut(&mut self) -> &mut RawTable<(K, V), A> {
2005-
&mut self.table
2006-
}
2007-
}
2008-
20091934
impl<K, V, S, A> PartialEq for HashMap<K, V, S, A>
20101935
where
20111936
K: Eq + Hash,
@@ -5958,74 +5883,6 @@ mod test_map {
59585883
}
59595884
}
59605885

5961-
#[test]
5962-
#[cfg(feature = "raw")]
5963-
fn test_into_iter_refresh() {
5964-
#[cfg(miri)]
5965-
const N: usize = 32;
5966-
#[cfg(not(miri))]
5967-
const N: usize = 128;
5968-
5969-
let mut rng = rand::thread_rng();
5970-
for n in 0..N {
5971-
let mut map = HashMap::new();
5972-
for i in 0..n {
5973-
assert!(map.insert(i, 2 * i).is_none());
5974-
}
5975-
let hash_builder = map.hasher().clone();
5976-
5977-
let mut it = unsafe { map.table.iter() };
5978-
assert_eq!(it.len(), n);
5979-
5980-
let mut i = 0;
5981-
let mut left = n;
5982-
let mut removed = Vec::new();
5983-
loop {
5984-
// occasionally remove some elements
5985-
if i < n && rng.gen_bool(0.1) {
5986-
let hash_value = super::make_hash(&hash_builder, &i);
5987-
5988-
unsafe {
5989-
let e = map.table.find(hash_value, |q| q.0.eq(&i));
5990-
if let Some(e) = e {
5991-
it.reflect_remove(&e);
5992-
let t = map.table.remove(e).0;
5993-
removed.push(t);
5994-
left -= 1;
5995-
} else {
5996-
assert!(removed.contains(&(i, 2 * i)), "{i} not in {removed:?}");
5997-
let e = map.table.insert(
5998-
hash_value,
5999-
(i, 2 * i),
6000-
super::make_hasher::<_, usize, _>(&hash_builder),
6001-
);
6002-
it.reflect_insert(&e);
6003-
if let Some(p) = removed.iter().position(|e| e == &(i, 2 * i)) {
6004-
removed.swap_remove(p);
6005-
}
6006-
left += 1;
6007-
}
6008-
}
6009-
}
6010-
6011-
let e = it.next();
6012-
if e.is_none() {
6013-
break;
6014-
}
6015-
assert!(i < n);
6016-
let t = unsafe { e.unwrap().as_ref() };
6017-
assert!(!removed.contains(t));
6018-
let (key, value) = t;
6019-
assert_eq!(*value, 2 * key);
6020-
i += 1;
6021-
}
6022-
assert!(i <= n);
6023-
6024-
// just for safety:
6025-
assert_eq!(map.table.len(), left);
6026-
}
6027-
}
6028-
60295886
#[test]
60305887
fn test_const_with_hasher() {
60315888
use core::hash::BuildHasher;

Diff for: src/raw/bitmask.rs

-16
Original file line numberDiff line numberDiff line change
@@ -105,22 +105,6 @@ impl IntoIterator for BitMask {
105105
#[derive(Copy, Clone)]
106106
pub(crate) struct BitMaskIter(pub(crate) BitMask);
107107

108-
impl BitMaskIter {
109-
/// Flip the bit in the mask for the entry at the given index.
110-
///
111-
/// Returns the bit's previous state.
112-
#[inline]
113-
#[allow(clippy::cast_ptr_alignment)]
114-
#[cfg(feature = "raw")]
115-
pub(crate) unsafe fn flip(&mut self, index: usize) -> bool {
116-
// NOTE: The + BITMASK_STRIDE - 1 is to set the high bit.
117-
let mask = 1 << (index * BITMASK_STRIDE + BITMASK_STRIDE - 1);
118-
self.0 .0 ^= mask;
119-
// The bit was set if the bit is now 0.
120-
self.0 .0 & mask == 0
121-
}
122-
}
123-
124108
impl Iterator for BitMaskIter {
125109
type Item = usize;
126110

0 commit comments

Comments
 (0)