diff --git a/Cargo.toml b/Cargo.toml index 1d8a68f83..db798f4d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,10 @@ test = false [dependencies] either = { version = "1.0", default-features = false } +hashbrown = { version = "0.15", optional = true, default-features = false, features = [ + "alloc", + "default-hasher", +] } [dev-dependencies] rand = "0.7" @@ -36,6 +40,7 @@ quickcheck = { version = "0.9", default-features = false } default = ["use_std"] use_std = ["use_alloc", "either/use_std"] use_alloc = [] +hashbrown = ["dep:hashbrown", "use_alloc"] [profile] bench = { debug = true } diff --git a/src/duplicates_impl.rs b/src/duplicates_impl.rs index a0db15432..6586e8300 100644 --- a/src/duplicates_impl.rs +++ b/src/duplicates_impl.rs @@ -1,6 +1,9 @@ use std::hash::Hash; mod private { + #[cfg(feature = "hashbrown")] + use hashbrown::HashMap; + #[cfg(not(feature = "hashbrown"))] use std::collections::HashMap; use std::fmt; use std::hash::Hash; diff --git a/src/group_map.rs b/src/group_map.rs index e60606bb3..fc289c834 100644 --- a/src/group_map.rs +++ b/src/group_map.rs @@ -1,5 +1,9 @@ -#![cfg(feature = "use_std")] +#![cfg(any(feature = "use_std", feature = "hashbrown"))] +use alloc::vec::Vec; +#[cfg(feature = "hashbrown")] +use hashbrown::HashMap; +#[cfg(not(feature = "hashbrown"))] use std::collections::HashMap; use std::hash::Hash; use std::iter::Iterator; diff --git a/src/grouping_map.rs b/src/grouping_map.rs index 725e2592a..cc8430832 100644 --- a/src/grouping_map.rs +++ b/src/grouping_map.rs @@ -2,7 +2,10 @@ use crate::{ adaptors::map::{MapSpecialCase, MapSpecialCaseFn}, MinMaxResult, }; +#[cfg(feature = "hashbrown")] +use hashbrown::HashMap; use std::cmp::Ordering; +#[cfg(not(feature = "hashbrown"))] use std::collections::HashMap; use std::hash::Hash; use std::iter::Iterator; diff --git a/src/lib.rs b/src/lib.rs index 745e82048..263a06ccd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,6 +47,13 @@ //! - Enabled by default. //! - Enables any item that depend on allocations (like `chunk_by`, //! `kmerge`, `join` and many more). +//! - `hashbrown` +//! - Disabled by default. +//! - Enables `use_alloc` and uses `hashbrown::HashMap` instead of +//! `std::collections::HashMap` to enable some items that depend on hash maps +//! without `use_std`. It is also possible to use this feature together with +//! `use_std` if you prefer `hashbrown::HashMap` (for example, because of the +//! different default hasher). //! //! ## Rust Version //! @@ -64,15 +71,15 @@ use alloc::{collections::VecDeque, string::String, vec::Vec}; pub use either::Either; use core::borrow::Borrow; +#[cfg(feature = "hashbrown")] +use hashbrown::{HashMap, HashSet}; use std::cmp::Ordering; -#[cfg(feature = "use_std")] -use std::collections::HashMap; -#[cfg(feature = "use_std")] -use std::collections::HashSet; +#[cfg(all(feature = "use_std", not(feature = "hashbrown")))] +use std::collections::{HashMap, HashSet}; use std::fmt; #[cfg(feature = "use_alloc")] use std::fmt::Write; -#[cfg(feature = "use_std")] +#[cfg(any(feature = "use_std", feature = "hashbrown"))] use std::hash::Hash; use std::iter::{once, IntoIterator}; #[cfg(feature = "use_alloc")] @@ -102,7 +109,7 @@ pub mod structs { #[cfg(feature = "use_alloc")] pub use crate::combinations_with_replacement::CombinationsWithReplacement; pub use crate::cons_tuples_impl::ConsTuples; - #[cfg(feature = "use_std")] + #[cfg(any(feature = "use_std", feature = "hashbrown"))] pub use crate::duplicates_impl::{Duplicates, DuplicatesBy}; pub use crate::exactly_one_err::ExactlyOneError; pub use crate::flatten_ok::FlattenOk; @@ -112,7 +119,7 @@ pub mod structs { pub use crate::groupbylazy::GroupBy; #[cfg(feature = "use_alloc")] pub use crate::groupbylazy::{Chunk, ChunkBy, Chunks, Group, Groups, IntoChunks}; - #[cfg(feature = "use_std")] + #[cfg(any(feature = "use_std", feature = "hashbrown"))] pub use crate::grouping_map::{GroupingMap, GroupingMapBy}; pub use crate::intersperse::{Intersperse, IntersperseWith}; #[cfg(feature = "use_alloc")] @@ -140,7 +147,7 @@ pub mod structs { #[cfg(feature = "use_alloc")] pub use crate::tee::Tee; pub use crate::tuple_impl::{CircularTupleWindows, TupleBuffer, TupleWindows, Tuples}; - #[cfg(feature = "use_std")] + #[cfg(any(feature = "use_std", feature = "hashbrown"))] pub use crate::unique_impl::{Unique, UniqueBy}; pub use crate::with_position::WithPosition; pub use crate::zip_eq_impl::ZipEq; @@ -187,18 +194,18 @@ mod combinations_with_replacement; mod concat_impl; mod cons_tuples_impl; mod diff; -#[cfg(feature = "use_std")] +#[cfg(any(feature = "use_std", feature = "hashbrown"))] mod duplicates_impl; mod exactly_one_err; #[cfg(feature = "use_alloc")] mod extrema_set; mod flatten_ok; mod format; -#[cfg(feature = "use_alloc")] +#[cfg(any(feature = "use_std", feature = "hashbrown"))] mod group_map; #[cfg(feature = "use_alloc")] mod groupbylazy; -#[cfg(feature = "use_std")] +#[cfg(any(feature = "use_std", feature = "hashbrown"))] mod grouping_map; mod intersperse; mod iter_index; @@ -233,7 +240,7 @@ mod take_while_inclusive; #[cfg(feature = "use_alloc")] mod tee; mod tuple_impl; -#[cfg(feature = "use_std")] +#[cfg(any(feature = "use_std", feature = "hashbrown"))] mod unique_impl; mod unziptuple; mod with_position; @@ -1415,7 +1422,7 @@ pub trait Itertools: Iterator { /// itertools::assert_equal(data.into_iter().duplicates(), /// vec![20, 10]); /// ``` - #[cfg(feature = "use_std")] + #[cfg(any(feature = "use_std", feature = "hashbrown"))] fn duplicates(self) -> Duplicates where Self: Sized, @@ -1441,7 +1448,7 @@ pub trait Itertools: Iterator { /// itertools::assert_equal(data.into_iter().duplicates_by(|s| s.len()), /// vec!["aa", "c"]); /// ``` - #[cfg(feature = "use_std")] + #[cfg(any(feature = "use_std", feature = "hashbrown"))] fn duplicates_by(self, f: F) -> DuplicatesBy where Self: Sized, @@ -1469,7 +1476,7 @@ pub trait Itertools: Iterator { /// itertools::assert_equal(data.into_iter().unique(), /// vec![10, 20, 30, 40, 50]); /// ``` - #[cfg(feature = "use_std")] + #[cfg(any(feature = "use_std", feature = "hashbrown"))] fn unique(self) -> Unique where Self: Sized, @@ -1496,7 +1503,7 @@ pub trait Itertools: Iterator { /// itertools::assert_equal(data.into_iter().unique_by(|s| s.len()), /// vec!["a", "bb", "ccc"]); /// ``` - #[cfg(feature = "use_std")] + #[cfg(any(feature = "use_std", feature = "hashbrown"))] fn unique_by(self, f: F) -> UniqueBy where Self: Sized, @@ -2309,7 +2316,7 @@ pub trait Itertools: Iterator { /// let data: Option = None; /// assert!(data.into_iter().all_unique()); /// ``` - #[cfg(feature = "use_std")] + #[cfg(any(feature = "use_std", feature = "hashbrown"))] fn all_unique(&mut self) -> bool where Self: Sized, @@ -3744,7 +3751,7 @@ pub trait Itertools: Iterator { /// assert_eq!(lookup[&2], vec![12, 42]); /// assert_eq!(lookup[&3], vec![13, 33]); /// ``` - #[cfg(feature = "use_std")] + #[cfg(any(feature = "use_std", feature = "hashbrown"))] fn into_group_map(self) -> HashMap> where Self: Iterator + Sized, @@ -3780,7 +3787,7 @@ pub trait Itertools: Iterator { /// 30, /// ); /// ``` - #[cfg(feature = "use_std")] + #[cfg(any(feature = "use_std", feature = "hashbrown"))] fn into_group_map_by(self, f: F) -> HashMap> where Self: Iterator + Sized, @@ -3799,7 +3806,7 @@ pub trait Itertools: Iterator { /// /// See [`GroupingMap`] for more informations /// on what operations are available. - #[cfg(feature = "use_std")] + #[cfg(any(feature = "use_std", feature = "hashbrown"))] fn into_grouping_map(self) -> GroupingMap where Self: Iterator + Sized, @@ -3816,7 +3823,7 @@ pub trait Itertools: Iterator { /// /// See [`GroupingMap`] for more informations /// on what operations are available. - #[cfg(feature = "use_std")] + #[cfg(any(feature = "use_std", feature = "hashbrown"))] fn into_grouping_map_by(self, key_mapper: F) -> GroupingMapBy where Self: Iterator + Sized, @@ -4527,7 +4534,7 @@ pub trait Itertools: Iterator { /// assert_eq!(counts[&5], 1); /// assert_eq!(counts.get(&0), None); /// ``` - #[cfg(feature = "use_std")] + #[cfg(any(feature = "use_std", feature = "hashbrown"))] fn counts(self) -> HashMap where Self: Sized, @@ -4571,7 +4578,7 @@ pub trait Itertools: Iterator { /// assert_eq!(first_name_frequency["James"], 4); /// assert_eq!(first_name_frequency.contains_key("Asha"), false); /// ``` - #[cfg(feature = "use_std")] + #[cfg(any(feature = "use_std", feature = "hashbrown"))] fn counts_by(self, f: F) -> HashMap where Self: Sized, diff --git a/src/unique_impl.rs b/src/unique_impl.rs index 0f6397e48..19d36c809 100644 --- a/src/unique_impl.rs +++ b/src/unique_impl.rs @@ -1,5 +1,7 @@ -use std::collections::hash_map::Entry; -use std::collections::HashMap; +#[cfg(feature = "hashbrown")] +use hashbrown::{hash_map::Entry, HashMap}; +#[cfg(not(feature = "hashbrown"))] +use std::collections::{hash_map::Entry, HashMap}; use std::fmt; use std::hash::Hash; use std::iter::FusedIterator;