Skip to content

Commit 1da2130

Browse files
committed
Release 0.6 with newer hashbrown and no mod raw
Fixes #21 so crate will work on Rust 1.82. We can't upgrade to `hashbrown 0.15` since it removes the `raw` table support. This is known upstream, and may just be something we have to live with: rust-lang/hashbrown#545 (comment) To align with `hashbrown`, and given this is a breaking change regardless, we remove the `raw` module just like `hashbrown` has. This should hopefully increase the chances that one day we can move to `hashbrown`'s new lower-level interface (`HashTable`) without a breaking change. This release also removes the `nightly` feature because it was mostly useless.
1 parent 80613a9 commit 1da2130

File tree

10 files changed

+77
-319
lines changed

10 files changed

+77
-319
lines changed

.github/workflows/check.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -104,15 +104,15 @@ jobs:
104104
# intentionally no target specifier; see https://github.com/jonhoo/rust-ci-conf/pull/4
105105
# --feature-powerset runs for every combination of features
106106
- name: cargo hack
107-
run: cargo hack --feature-powerset --exclude-features nightly check
107+
run: cargo hack --feature-powerset check
108108
msrv:
109109
# check that we can build using the minimal rust version that is specified by this crate
110110
runs-on: ubuntu-latest
111111
# we use a matrix here just because env can't be used in job names
112112
# https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability
113113
strategy:
114114
matrix:
115-
msrv: ["1.60.0"] # 2021 edition requires 1.56
115+
msrv: ["1.63.0"]
116116
name: ubuntu / ${{ matrix.msrv }}
117117
steps:
118118
- uses: actions/checkout@v4

.github/workflows/test.yml

+5-5
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,10 @@ jobs:
3939
run: cargo generate-lockfile
4040
# https://twitter.com/jonhoo/status/1571290371124260865
4141
- name: cargo test --locked
42-
run: cargo test --locked --features serde,rayon,raw --all-targets
42+
run: cargo test --locked --all-features --all-targets
4343
# https://github.com/rust-lang/cargo/issues/6669
4444
- name: cargo test --doc
45-
run: cargo test --locked --features serde,rayon,raw --doc
45+
run: cargo test --locked --all-features --doc
4646
minimal:
4747
# This action chooses the oldest version of the dependencies permitted by Cargo.toml to ensure
4848
# that this crate is compatible with the minimal version that this crate and its dependencies
@@ -81,7 +81,7 @@ jobs:
8181
- name: cargo update -Zminimal-versions
8282
run: cargo +nightly update -Zminimal-versions
8383
- name: cargo test
84-
run: cargo test --locked --features serde,rayon,raw --all-targets
84+
run: cargo test --locked --all-features --all-targets
8585
os-check:
8686
# run cargo test on mac and windows
8787
runs-on: ${{ matrix.os }}
@@ -106,7 +106,7 @@ jobs:
106106
if: hashFiles('Cargo.lock') == ''
107107
run: cargo generate-lockfile
108108
- name: cargo test
109-
run: cargo test --locked --features serde,rayon,raw --all-targets
109+
run: cargo test --locked --all-features --all-targets
110110
coverage:
111111
# use llvm-cov to build and collect coverage and outputs in a format that
112112
# is compatible with codecov.io
@@ -145,7 +145,7 @@ jobs:
145145
if: hashFiles('Cargo.lock') == ''
146146
run: cargo generate-lockfile
147147
- name: cargo llvm-cov
148-
run: cargo llvm-cov --locked --features serde,rayon,raw --lcov --output-path lcov.info
148+
run: cargo llvm-cov --locked --all-features --lcov --output-path lcov.info
149149
- name: Record Rust version
150150
run: echo "RUST=$(rustc --version)" >> "$GITHUB_ENV"
151151
- name: Upload to codecov.io

Cargo.toml

+5-8
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
[package]
22
name = "griddle"
3-
version = "0.5.2"
3+
version = "0.6.0"
44
authors = ["Jon Gjengset <[email protected]>"]
5-
edition = "2018"
5+
edition = "2021"
66
license = "MIT OR Apache-2.0"
77

88
readme = "README.md"
@@ -14,9 +14,9 @@ categories = ["data-structures", "no-std"]
1414

1515
[dependencies]
1616
# For the default hasher
17-
ahash_ = { version = "0.7.0", default-features = false, optional = true, package = "ahash" }
17+
ahash_ = { version = "0.8.0", default-features = false, optional = true, package = "ahash" }
1818

19-
hashbrown = { version = "0.11.2", default-features = false, features = ["raw"] }
19+
hashbrown = { version = "0.14.0", default-features = false, features = ["raw"] }
2020

2121
# For external trait impls
2222
rayon_ = { version = "1.3.0", optional = true, package = "rayon" }
@@ -37,17 +37,14 @@ ahash-compile-time-rng = ["ahash_/compile-time-rng"]
3737
ahash = [ "ahash_", "hashbrown/ahash" ]
3838
serde = [ "serde_", "hashbrown/serde" ]
3939
rayon = [ "rayon_", "hashbrown/rayon" ]
40-
raw = []
4140

4241
# Enables usage of `#[inline]` on far more functions than by default in this
4342
# crate. This may lead to a performance increase but often comes at a compile
4443
# time cost.
4544
inline-more = [ "hashbrown/inline-more" ]
4645

47-
nightly = []
48-
4946
[package.metadata.docs.rs]
50-
features = ["rayon", "serde", "raw"]
47+
features = ["rayon", "serde"]
5148

5249
[[bench]]
5350
name = "vroom"

README.md

+5-4
Original file line numberDiff line numberDiff line change
@@ -80,18 +80,19 @@ work required to find the buckets that hold elements that must be moved.
8080
## Implementation
8181

8282
Griddle uses the
83-
[`hashbrown::raw`](https://docs.rs/hashbrown/0.8/hashbrown/raw/index.html)
83+
[`hashbrown::raw`](https://docs.rs/hashbrown/0.14/hashbrown/raw/index.html)
8484
API, which allows it to take advantage of all the awesome work that has
8585
gone into making `hashbrown` as fast as it is. The key different parts
86-
of griddle live in `src/raw/mod.rs`.
86+
of griddle live in `src/raw/mod.rs`. The `raw` API was [removed in
87+
`hashbrown` 0.15](https://github.com/rust-lang/hashbrown/issues/545), so
88+
Griddle is stuck on 0.14 for now.
8789

8890
Griddle aims to stick as closely to `hashbrown` as it can, both in terms
8991
of code and API. `src/map.rs` and `src/set.rs` are virtually identical
9092
to the equivalent files in `hashbrown` (I encourage you to diff them!),
9193
without only some (currently;
9294
[#4](https://github.com/jonhoo/griddle/issues/4)) unsupported API
93-
removed. Like `hashbrown`, griddle exposes a `raw` module, which lets
94-
you build your own map implementation on top of griddle's table variant.
95+
removed.
9596

9697
## Why "griddle"?
9798

src/external_trait_impls/rayon/map.rs

-43
Original file line numberDiff line numberDiff line change
@@ -328,55 +328,12 @@ where
328328
#[cfg(test)]
329329
mod test_par_map {
330330
use alloc::vec::Vec;
331-
use core::hash::{Hash, Hasher};
332331
use core::sync::atomic::{AtomicUsize, Ordering};
333332

334333
use rayon_::prelude::*;
335334

336335
use crate::hash_map::HashMap;
337336

338-
struct Dropable<'a> {
339-
k: usize,
340-
counter: &'a AtomicUsize,
341-
}
342-
343-
impl Dropable<'_> {
344-
fn new(k: usize, counter: &AtomicUsize) -> Dropable<'_> {
345-
counter.fetch_add(1, Ordering::Relaxed);
346-
347-
Dropable { k, counter }
348-
}
349-
}
350-
351-
impl Drop for Dropable<'_> {
352-
fn drop(&mut self) {
353-
self.counter.fetch_sub(1, Ordering::Relaxed);
354-
}
355-
}
356-
357-
impl Clone for Dropable<'_> {
358-
fn clone(&self) -> Self {
359-
Dropable::new(self.k, self.counter)
360-
}
361-
}
362-
363-
impl Hash for Dropable<'_> {
364-
fn hash<H>(&self, state: &mut H)
365-
where
366-
H: Hasher,
367-
{
368-
self.k.hash(state)
369-
}
370-
}
371-
372-
impl PartialEq for Dropable<'_> {
373-
fn eq(&self, other: &Self) -> bool {
374-
self.k == other.k
375-
}
376-
}
377-
378-
impl Eq for Dropable<'_> {}
379-
380337
#[test]
381338
fn test_empty_iter() {
382339
let mut m: HashMap<isize, bool> = HashMap::new();

src/external_trait_impls/rayon/raw.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rayon_::iter::{
66
};
77

88
/// Parallel iterator which returns a raw pointer to every full bucket in the table.
9-
pub struct RawParIter<T> {
9+
pub(crate) struct RawParIter<T> {
1010
iter: hashbrown::raw::rayon::RawParIter<T>,
1111
leftovers: Option<hashbrown::raw::rayon::RawParIter<T>>,
1212
}
@@ -50,7 +50,7 @@ impl<T> ParallelIterator for RawParIter<T> {
5050
impl<T> RawTable<T> {
5151
/// Returns a parallel iterator over the elements in a `RawTable`.
5252
#[cfg_attr(feature = "inline-more", inline)]
53-
pub unsafe fn par_iter(&self) -> RawParIter<T> {
53+
pub(crate) unsafe fn par_iter(&self) -> RawParIter<T> {
5454
RawParIter {
5555
iter: self.main().par_iter(),
5656
leftovers: self.leftovers().map(|t| t.iter().into()),

src/lib.rs

-20
Original file line numberDiff line numberDiff line change
@@ -66,26 +66,6 @@ extern crate std;
6666
#[cfg_attr(test, macro_use)]
6767
extern crate alloc;
6868

69-
#[cfg(feature = "raw")]
70-
/// Experimental and unsafe `RawTable` API. This module is only available if the
71-
/// `raw` feature is enabled.
72-
pub mod raw {
73-
#[path = "mod.rs"]
74-
mod inner;
75-
pub use inner::*;
76-
77-
#[cfg(feature = "rayon")]
78-
/// [rayon]-based parallel iterator types for raw hash tables.
79-
/// You will rarely need to interact with it directly unless you have need
80-
/// to name one of the iterator types.
81-
///
82-
/// [rayon]: https://docs.rs/rayon/1.0/rayon
83-
pub mod rayon {
84-
pub use crate::external_trait_impls::rayon::raw::*;
85-
}
86-
}
87-
#[cfg(not(feature = "raw"))]
88-
#[allow(dead_code)]
8969
mod raw;
9070

9171
mod external_trait_impls;

src/map.rs

+4-101
Original file line numberDiff line numberDiff line change
@@ -3171,7 +3171,6 @@ mod test_map {
31713171
use super::DefaultHashBuilder;
31723172
use super::Entry::{Occupied, Vacant};
31733173
use super::{HashMap, RawEntryMut};
3174-
use crate::TryReserveError::*;
31753174
use rand::{rngs::SmallRng, Rng, SeedableRng};
31763175
use std::cell::RefCell;
31773176
use std::usize;
@@ -4327,11 +4326,11 @@ mod test_map {
43274326
let key = "hello there";
43284327
let value = "value goes here";
43294328
assert!(a.is_empty());
4330-
a.insert(key.clone(), value.clone());
4329+
a.insert(key, value);
43314330
assert_eq!(a.len(), 1);
43324331
assert_eq!(a[key], value);
43334332

4334-
match a.entry(key.clone()) {
4333+
match a.entry(key) {
43354334
Vacant(_) => panic!(),
43364335
Occupied(e) => assert_eq!(key, *e.key()),
43374336
}
@@ -4346,11 +4345,11 @@ mod test_map {
43464345
let value = "value goes here";
43474346

43484347
assert!(a.is_empty());
4349-
match a.entry(key.clone()) {
4348+
match a.entry(key) {
43504349
Occupied(_) => panic!(),
43514350
Vacant(e) => {
43524351
assert_eq!(key, *e.key());
4353-
e.insert(value.clone());
4352+
e.insert(value);
43544353
}
43554354
}
43564355
assert_eq!(a.len(), 1);
@@ -4446,102 +4445,6 @@ mod test_map {
44464445
}
44474446
}
44484447

4449-
#[test]
4450-
#[cfg_attr(miri, ignore)] // FIXME: no OOM signalling (https://github.com/rust-lang/miri/issues/613)
4451-
fn test_try_reserve() {
4452-
let mut empty_bytes: HashMap<u8, u8> = HashMap::new();
4453-
4454-
const MAX_USIZE: usize = usize::MAX;
4455-
4456-
if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) {
4457-
} else {
4458-
panic!("usize::MAX should trigger an overflow!");
4459-
}
4460-
4461-
if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE / 8) {
4462-
} else {
4463-
// This may succeed if there is enough free memory. Attempt to
4464-
// allocate a second hashmap to ensure the allocation will fail.
4465-
let mut empty_bytes2: HashMap<u8, u8> = HashMap::new();
4466-
if let Err(AllocError { .. }) = empty_bytes2.try_reserve(MAX_USIZE / 8) {
4467-
} else {
4468-
panic!("usize::MAX / 8 should trigger an OOM!");
4469-
}
4470-
}
4471-
}
4472-
4473-
#[test]
4474-
#[cfg(feature = "raw")]
4475-
fn test_into_iter_refresh() {
4476-
use core::hash::{BuildHasher, Hash, Hasher};
4477-
4478-
#[cfg(miri)]
4479-
const N: usize = 32;
4480-
#[cfg(not(miri))]
4481-
const N: usize = 128;
4482-
4483-
let mut rng = rand::thread_rng();
4484-
for n in 0..N {
4485-
let mut m = HashMap::new();
4486-
for i in 0..n {
4487-
assert!(m.insert(i, 2 * i).is_none());
4488-
}
4489-
let hasher = m.hasher().clone();
4490-
4491-
let mut it = unsafe { m.table.iter() };
4492-
assert_eq!(it.len(), n);
4493-
4494-
let mut i = 0;
4495-
let mut left = n;
4496-
let mut removed = Vec::new();
4497-
loop {
4498-
// occasionally remove some elements
4499-
if i < n && rng.gen_bool(0.1) {
4500-
let mut hsh = hasher.build_hasher();
4501-
i.hash(&mut hsh);
4502-
let hash = hsh.finish();
4503-
4504-
unsafe {
4505-
let e = m.table.find(hash, |q| q.0.eq(&i));
4506-
if let Some(e) = e {
4507-
it.reflect_remove(&e);
4508-
let t = m.table.remove(e);
4509-
removed.push(t);
4510-
left -= 1;
4511-
} else {
4512-
assert!(removed.contains(&(i, 2 * i)), "{} not in {:?}", i, removed);
4513-
let e = m.table.insert(
4514-
hash,
4515-
(i, 2 * i),
4516-
super::make_hasher::<usize, _, _, _>(&hasher),
4517-
);
4518-
it.reflect_insert(&e);
4519-
if let Some(p) = removed.iter().position(|e| e == &(i, 2 * i)) {
4520-
removed.swap_remove(p);
4521-
}
4522-
left += 1;
4523-
}
4524-
}
4525-
}
4526-
4527-
let e = it.next();
4528-
if e.is_none() {
4529-
break;
4530-
}
4531-
assert!(i < n);
4532-
let t = unsafe { e.unwrap().as_ref() };
4533-
assert!(!removed.contains(t));
4534-
let (k, v) = t;
4535-
assert_eq!(*v, 2 * k);
4536-
i += 1;
4537-
}
4538-
assert!(i <= n);
4539-
4540-
// just for safety:
4541-
assert_eq!(m.table.len(), left);
4542-
}
4543-
}
4544-
45454448
#[test]
45464449
fn test_raw_entry() {
45474450
use super::RawEntryMut::{Occupied, Vacant};

0 commit comments

Comments
 (0)