diff --git a/Cargo.lock b/Cargo.lock index af1fe89..a07c4dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "anes" version = "0.1.6" @@ -243,6 +249,12 @@ dependencies = [ "regex", ] +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + [[package]] name = "errno" version = "0.3.13" @@ -265,6 +277,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "getrandom" version = "0.2.16" @@ -298,6 +316,17 @@ dependencies = [ "crunchy", ] +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + [[package]] name = "imbl" version = "6.1.0" @@ -308,6 +337,7 @@ dependencies = [ "bitmaps", "criterion", "half", + "hashbrown", "imbl-sized-chunks", "metrohash", "pretty_assertions", @@ -321,6 +351,8 @@ dependencies = [ "rpds", "serde_core", "serde_json", + "siphasher", + "spin", "static_assertions", "version_check", "wide", @@ -378,6 +410,15 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" version = "0.4.27" @@ -714,6 +755,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "serde" version = "1.0.224" @@ -756,6 +803,21 @@ dependencies = [ "serde", ] +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + +[[package]] +name = "spin" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" +dependencies = [ + "lock_api", +] + [[package]] name = "static_assertions" version = "1.1.0" diff --git a/Cargo.toml b/Cargo.toml index c250c6d..a1cc4a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,24 +34,29 @@ path = "./src/lib.rs" version_check = "0.9" [features] +default = ["std"] debug = [] +std = ["bitmaps/std", "imbl-sized-chunks/std", "siphasher/std", "spin/std", "wide/std"] serde = ["dep:serde_core"] small-chunks = [] triomphe = ["archery/triomphe"] [dependencies] -bitmaps = "3" -imbl-sized-chunks = "0.1.3" +bitmaps = { version = "3", default-features = false } +imbl-sized-chunks = { version = "0.1.3", default-features = false } rand_core = "0.9" rand_xoshiro = "0.7" archery = "1.2.1" quickcheck = { version = "1.0", optional = true } proptest = { version = "1.0", optional = true } -serde_core = { version = "1.0.224", optional = true } +serde_core = { version = "1.0.224", optional = true , features = ["alloc", "rc", "result"], default-features = false } rayon = { version = "1", optional = true } arbitrary = { version = "1.0", optional = true } bincode = {version = "2.0.1", optional = true, default-features=false, features = ["alloc", "std"]} -wide = "0.7" +wide = { version = "0.7", default-features = false } +hashbrown = "0.16.1" +siphasher = { version = "1.0.1", default-features = false } +spin = "0.10.0" [dev-dependencies] proptest = "1.0" diff --git a/src/arbitrary.rs b/src/arbitrary.rs index 498a8f8..156a8a8 100644 --- a/src/arbitrary.rs +++ b/src/arbitrary.rs @@ -3,7 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. use arbitrary::{size_hint, Arbitrary, Result, Unstructured}; -use std::hash::{BuildHasher, Hash}; +use core::hash::{BuildHasher, Hash}; use crate::{ shared_ptr::SharedPointerKind, GenericHashMap, GenericHashSet, GenericOrdMap, GenericOrdSet, diff --git a/src/bincode.rs b/src/bincode.rs index 931480a..f0882ac 100644 --- a/src/bincode.rs +++ b/src/bincode.rs @@ -2,7 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use std::hash::{BuildHasher, Hash}; +use core::hash::{BuildHasher, Hash}; use archery::SharedPointerKind; use bincode::de::Decoder; diff --git a/src/fakepool.rs b/src/fakepool.rs index 0661aeb..6be9d82 100644 --- a/src/fakepool.rs +++ b/src/fakepool.rs @@ -5,7 +5,7 @@ #![allow(dead_code)] use crate::nodes::chunk::Chunk; -use std::marker::PhantomData; +use core::marker::PhantomData; pub(crate) trait PoolDefault: Default {} pub(crate) trait PoolClone: Clone {} diff --git a/src/hash/map.rs b/src/hash/map.rs index 2d49529..d1dd3be 100644 --- a/src/hash/map.rs +++ b/src/hash/map.rs @@ -10,25 +10,26 @@ //! suitably high *x* that it should be nearly O(1) for most maps. //! Because of this, it's a great choice for a generic map as long as //! you don't mind that keys will need to implement -//! [`Hash`][std::hash::Hash] and [`Eq`][std::cmp::Eq]. +//! [`Hash`][core::hash::Hash] and [`Eq`][core::cmp::Eq]. //! //! Map entries will have a predictable order based on the hasher //! being used. Unless otherwise specified, this will be the standard -//! [`RandomState`][std::collections::hash_map::RandomState] hasher. +//! [`RandomState`][crate::RandomState] hasher. //! //! [1]: https://en.wikipedia.org/wiki/Hash_array_mapped_trie -//! [std::cmp::Eq]: https://doc.rust-lang.org/std/cmp/trait.Eq.html -//! [std::hash::Hash]: https://doc.rust-lang.org/std/hash/trait.Hash.html -//! [std::collections::hash_map::RandomState]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html - -use std::borrow::Borrow; -use std::collections; -use std::collections::hash_map::RandomState; -use std::fmt::{Debug, Error, Formatter}; -use std::hash::{BuildHasher, Hash}; -use std::iter::{FromIterator, FusedIterator, Sum}; -use std::mem; -use std::ops::{Add, Index, IndexMut}; +//! [core::cmp::Eq]: https://doc.rust-lang.org/core/cmp/trait.Eq.html +//! [core::hash::Hash]: https://doc.rust-lang.org/core/hash/trait.Hash.html +//! [crate::RandomState]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + +use alloc::borrow::ToOwned; +use alloc::collections; +use alloc::vec::Vec; +use core::borrow::Borrow; +use core::fmt::{Debug, Error, Formatter}; +use core::hash::{BuildHasher, Hash}; +use core::iter::{FromIterator, FusedIterator, Sum}; +use core::mem; +use core::ops::{Add, Index, IndexMut}; use archery::{SharedPointer, SharedPointerKind}; @@ -37,6 +38,7 @@ use crate::nodes::hamt::{ Node, }; use crate::shared_ptr::DefaultSharedPtr; +use crate::RandomState; /// Construct a hash map from a sequence of key/value pairs. /// @@ -77,10 +79,10 @@ macro_rules! hashmap { }}; } -/// Type alias for [`GenericHashMap`] that uses [`std::hash::RandomState`] as the default hasher and [`DefaultSharedPtr`] as the pointer type. +/// Type alias for [`GenericHashMap`] that uses [`crate::RandomState`] as the default hasher and [`DefaultSharedPtr`] as the pointer type. /// /// [GenericHashMap]: ./struct.GenericHashMap.html -/// [`std::hash::RandomState`]: https://doc.rust-lang.org/stable/std/collections/hash_map/struct.RandomState.html +/// [`crate::RandomState`]: https://doc.rust-lang.org/stable/std/collections/hash_map/struct.RandomState.html /// [DefaultSharedPtr]: ../shared_ptr/type.DefaultSharedPtr.html pub type HashMap = GenericHashMap; @@ -92,16 +94,16 @@ pub type HashMap = GenericHashMap; /// suitably high *x* that it should be nearly O(1) for most maps. /// Because of this, it's a great choice for a generic map as long as /// you don't mind that keys will need to implement -/// [`Hash`][std::hash::Hash] and [`Eq`][std::cmp::Eq]. +/// [`Hash`][core::hash::Hash] and [`Eq`][core::cmp::Eq]. /// /// Map entries will have a predictable order based on the hasher /// being used. Unless otherwise specified, this will be the standard -/// [`RandomState`][std::collections::hash_map::RandomState] hasher. +/// [`RandomState`][crate::RandomState] hasher. /// /// [1]: https://en.wikipedia.org/wiki/Hash_array_mapped_trie -/// [std::cmp::Eq]: https://doc.rust-lang.org/std/cmp/trait.Eq.html -/// [std::hash::Hash]: https://doc.rust-lang.org/std/hash/trait.Hash.html -/// [std::collections::hash_map::RandomState]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html +/// [core::cmp::Eq]: https://doc.rust-lang.org/core/cmp/trait.Eq.html +/// [core::hash::Hash]: https://doc.rust-lang.org/core/hash/trait.Hash.html +/// [crate::RandomState]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html pub struct GenericHashMap { size: usize, root: Option, P>>, @@ -233,7 +235,7 @@ impl GenericHashMap { /// Get a reference to the map's [`BuildHasher`][BuildHasher]. /// - /// [BuildHasher]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// [BuildHasher]: https://doc.rust-lang.org/core/hash/trait.BuildHasher.html #[must_use] pub fn hasher(&self) -> &S { &self.hasher @@ -327,7 +329,7 @@ impl GenericHashMap { #[cfg(test)] pub fn print_structure_summary(&self) { use crate::nodes::hamt::Entry as NodeEntry; - use std::collections::VecDeque; + use alloc::collections::VecDeque; println!("HashMap Structure Summary:"); @@ -489,7 +491,7 @@ where if self.len() != other.len() { return false; } - let mut seen = collections::HashSet::new(); + let mut seen = hashbrown::HashSet::new(); for (key, value) in self.iter() { if Some(value) != other.get(key) { return false; @@ -751,9 +753,7 @@ where BK: Hash + Eq + ?Sized, K: Borrow, { - let Some(root) = self.root.as_mut() else { - return None; - }; + let root = self.root.as_mut()?; match SharedPointer::make_mut(root).get_mut(hash_key(&self.hasher, key), 0, key) { None => None, Some((key, value)) => Some((key, value)), @@ -972,14 +972,14 @@ where /// the current value and overwriting it with the function's /// return value. /// - /// The function gets an [`Option`][std::option::Option] and + /// The function gets an [`Option`][core::option::Option] and /// returns the same, so that it can decide to delete a mapping /// instead of updating the value, and decide what to do if the /// key isn't in the map. /// /// Time: O(log n) /// - /// [std::option::Option]: https://doc.rust-lang.org/std/option/enum.Option.html + /// [core::option::Option]: https://doc.rust-lang.org/core/option/enum.Option.html #[must_use] pub fn alter(&self, f: F, k: K) -> Self where @@ -1601,7 +1601,7 @@ where F: FnOnce(&mut V), { match &mut self { - Entry::Occupied(ref mut entry) => f(entry.get_mut()), + Entry::Occupied(entry) => f(entry.get_mut()), Entry::Vacant(_) => (), } self @@ -2164,7 +2164,7 @@ where } } -impl From> for GenericHashMap +impl From> for GenericHashMap where K: Hash + Eq + Clone, V: Clone, @@ -2172,12 +2172,12 @@ where S2: BuildHasher, P: SharedPointerKind, { - fn from(m: collections::HashMap) -> Self { + fn from(m: hashbrown::HashMap) -> Self { m.into_iter().collect() } } -impl<'a, K, V, S1, S2, P> From<&'a collections::HashMap> for GenericHashMap +impl<'a, K, V, S1, S2, P> From<&'a hashbrown::HashMap> for GenericHashMap where K: Hash + Eq + Clone, V: Clone, @@ -2185,7 +2185,33 @@ where S2: BuildHasher, P: SharedPointerKind, { - fn from(m: &'a collections::HashMap) -> Self { + fn from(m: &'a hashbrown::HashMap) -> Self { + m.iter().map(|(k, v)| (k.clone(), v.clone())).collect() + } +} + +#[cfg(feature = "std")] +impl From> for GenericHashMap +where + K: Hash + Eq + Clone, + V: Clone, + S: BuildHasher + Default + Clone, + P: SharedPointerKind, +{ + fn from(m: std::collections::HashMap) -> Self { + m.into_iter().collect() + } +} + +#[cfg(feature = "std")] +impl<'a, K, V, S, P> From<&'a std::collections::HashMap> for GenericHashMap +where + K: Hash + Eq + Clone, + V: Clone, + S: BuildHasher + Default + Clone, + P: SharedPointerKind, +{ + fn from(m: &'a std::collections::HashMap) -> Self { m.iter().map(|(k, v)| (k.clone(), v.clone())).collect() } } @@ -2251,8 +2277,8 @@ mod test { use crate::test::LolHasher; #[rustfmt::skip] use ::proptest::{collection, num::{i16, usize}, proptest}; + use core::hash::BuildHasherDefault; use static_assertions::{assert_impl_all, assert_not_impl_any}; - use std::hash::BuildHasherDefault; assert_impl_all!(HashMap: Send, Sync); assert_not_impl_any!(HashMap: Send, Sync); @@ -2289,8 +2315,8 @@ mod test { #[test] fn remove_failing() { let pairs = [(1469, 0), (-67, 0)]; - let mut m: collections::HashMap = - collections::HashMap::with_hasher(BuildHasherDefault::::default()); + let mut m: hashbrown::HashMap = + hashbrown::HashMap::with_hasher(BuildHasherDefault::::default()); for (k, v) in &pairs { m.insert(*k, *v); } @@ -2461,8 +2487,8 @@ mod test { #[test] fn without(ref pairs in collection::vec((i16::ANY, i16::ANY), 0..100)) { - let mut m: collections::HashMap = - collections::HashMap::with_hasher(BuildHasherDefault::::default()); + let mut m: hashbrown::HashMap = + hashbrown::HashMap::with_hasher(BuildHasherDefault::::default()); for (k, v) in pairs { m.insert(*k, *v); } @@ -2498,8 +2524,8 @@ mod test { #[test] fn remove(ref pairs in collection::vec((i16::ANY, i16::ANY), 0..100)) { - let mut m: collections::HashMap = - collections::HashMap::with_hasher(BuildHasherDefault::::default()); + let mut m: hashbrown::HashMap = + hashbrown::HashMap::with_hasher(BuildHasherDefault::::default()); for (k, v) in pairs { m.insert(*k, *v); } diff --git a/src/hash/set.rs b/src/hash/set.rs index 50792ec..987856d 100644 --- a/src/hash/set.rs +++ b/src/hash/set.rs @@ -10,24 +10,26 @@ //! suitably high *x* that it should be nearly O(1) for most sets. //! Because of this, it's a great choice for a generic set as long as //! you don't mind that values will need to implement -//! [`Hash`][std::hash::Hash] and [`Eq`][std::cmp::Eq]. +//! [`Hash`][core::hash::Hash] and [`Eq`][core::cmp::Eq]. //! //! Values will have a predictable order based on the hasher //! being used. Unless otherwise specified, this will be the standard -//! [`RandomState`][std::collections::hash_map::RandomState] hasher. +//! [`RandomState`][crate::RandomState] hasher. //! //! [1]: https://en.wikipedia.org/wiki/Hash_array_mapped_trie -//! [std::cmp::Eq]: https://doc.rust-lang.org/std/cmp/trait.Eq.html -//! [std::hash::Hash]: https://doc.rust-lang.org/std/hash/trait.Hash.html -//! [std::collections::hash_map::RandomState]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html - -use std::borrow::Borrow; -use std::collections::hash_map::RandomState; -use std::collections::{self, BTreeSet}; -use std::fmt::{Debug, Error, Formatter}; -use std::hash::{BuildHasher, Hash}; -use std::iter::{FromIterator, FusedIterator, Sum}; -use std::ops::{Add, Deref, Mul}; +//! [core::cmp::Eq]: https://doc.rust-lang.org/core/cmp/trait.Eq.html +//! [core::hash::Hash]: https://doc.rust-lang.org/core/hash/trait.Hash.html +//! [crate::RandomState]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + +use crate::RandomState; +use alloc::borrow::ToOwned; +use alloc::collections::BTreeSet; +use alloc::vec::Vec; +use core::borrow::Borrow; +use core::fmt::{Debug, Error, Formatter}; +use core::hash::{BuildHasher, Hash}; +use core::iter::{FromIterator, FusedIterator, Sum}; +use core::ops::{Add, Deref, Mul}; use archery::{SharedPointer, SharedPointerKind}; @@ -71,10 +73,10 @@ macro_rules! hashset { }}; } -/// Type alias for [`GenericHashSet`] that uses [`std::hash::RandomState`] as the default hasher and [`DefaultSharedPtr`] as the pointer type. +/// Type alias for [`GenericHashSet`] that uses [`crate::RandomState`] as the default hasher and [`DefaultSharedPtr`] as the pointer type. /// /// [GenericHashSet]: ./struct.GenericHashSet.html -/// [`std::hash::RandomState`]: https://doc.rust-lang.org/stable/std/collections/hash_map/struct.RandomState.html +/// [`crate::RandomState`]: https://doc.rust-lang.org/stable/std/collections/hash_map/struct.RandomState.html /// [DefaultSharedPtr]: ../shared_ptr/type.DefaultSharedPtr.html pub type HashSet = GenericHashSet; @@ -86,16 +88,16 @@ pub type HashSet = GenericHashSet; /// suitably high *x* that it should be nearly O(1) for most sets. /// Because of this, it's a great choice for a generic set as long as /// you don't mind that values will need to implement -/// [`Hash`][std::hash::Hash] and [`Eq`][std::cmp::Eq]. +/// [`Hash`][core::hash::Hash] and [`Eq`][core::cmp::Eq]. /// /// Values will have a predictable order based on the hasher /// being used. Unless otherwise specified, this will be the standard -/// [`RandomState`][std::collections::hash_map::RandomState] hasher. +/// [`RandomState`][crate::RandomState] hasher. /// /// [1]: https://en.wikipedia.org/wiki/Hash_array_mapped_trie -/// [std::cmp::Eq]: https://doc.rust-lang.org/std/cmp/trait.Eq.html -/// [std::hash::Hash]: https://doc.rust-lang.org/std/hash/trait.Hash.html -/// [std::collections::hash_map::RandomState]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html +/// [core::cmp::Eq]: https://doc.rust-lang.org/core/cmp/trait.Eq.html +/// [core::hash::Hash]: https://doc.rust-lang.org/core/hash/trait.Hash.html +/// [crate::RandomState]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html pub struct GenericHashSet { hasher: S, root: Option, P>, P>>, @@ -142,7 +144,7 @@ where /// ``` /// # #[macro_use] extern crate imbl; /// # use imbl::hashset::HashSet; - /// # use std::sync::Arc; + /// # use alloc::sync::Arc; /// let set = HashSet::unit(123); /// assert!(set.contains(&123)); /// ``` @@ -232,7 +234,7 @@ impl GenericHashSet { /// Get a reference to the set's [`BuildHasher`][BuildHasher]. /// - /// [BuildHasher]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// [BuildHasher]: https://doc.rust-lang.org/core/hash/trait.BuildHasher.html #[must_use] pub fn hasher(&self) -> &S { &self.hasher @@ -302,7 +304,7 @@ where if self.len() != other.len() { return false; } - let mut seen = collections::HashSet::new(); + let mut seen = hashbrown::HashSet::new(); for value in self.iter() { if !other.contains(value) { return false; @@ -408,7 +410,7 @@ where /// ``` /// # #[macro_use] extern crate imbl; /// # use imbl::hashset::HashSet; - /// # use std::sync::Arc; + /// # use alloc::sync::Arc; /// let set = hashset![123]; /// assert_eq!( /// set.update(456), @@ -969,24 +971,48 @@ where } } -impl From> for GenericHashSet +#[cfg(feature = "std")] +impl From> for GenericHashSet where A: Eq + Hash + Clone, S: BuildHasher + Default + Clone, P: SharedPointerKind, { - fn from(hash_set: collections::HashSet) -> Self { + fn from(hash_set: std::collections::HashSet) -> Self { hash_set.into_iter().collect() } } -impl From<&collections::HashSet> for GenericHashSet +#[cfg(feature = "std")] +impl From<&std::collections::HashSet> for GenericHashSet where A: Eq + Hash + Clone, S: BuildHasher + Default + Clone, P: SharedPointerKind, { - fn from(hash_set: &collections::HashSet) -> Self { + fn from(hash_set: &std::collections::HashSet) -> Self { + hash_set.iter().cloned().collect() + } +} + +impl From> for GenericHashSet +where + A: Eq + Hash + Clone, + S: BuildHasher + Default + Clone, + P: SharedPointerKind, +{ + fn from(hash_set: hashbrown::HashSet) -> Self { + hash_set.into_iter().collect() + } +} + +impl From<&hashbrown::HashSet> for GenericHashSet +where + A: Eq + Hash + Clone, + S: BuildHasher + Default + Clone, + P: SharedPointerKind, +{ + fn from(hash_set: &hashbrown::HashSet) -> Self { hash_set.iter().cloned().collect() } } @@ -1044,8 +1070,8 @@ mod test { use crate::test::LolHasher; use ::proptest::num::i16; use ::proptest::proptest; + use core::hash::BuildHasherDefault; use static_assertions::{assert_impl_all, assert_not_impl_any}; - use std::hash::BuildHasherDefault; assert_impl_all!(HashSet: Send, Sync); assert_not_impl_any!(HashSet<*const i32>: Send, Sync); diff --git a/src/iter.rs b/src/iter.rs index 6086f1a..eaa2a53 100644 --- a/src/iter.rs +++ b/src/iter.rs @@ -8,16 +8,16 @@ /// value. /// /// The function is called with the current state as its argument, and should -/// return an [`Option`][std::option::Option] of a tuple of the next value to +/// return an [`Option`][core::option::Option] of a tuple of the next value to /// yield from the iterator and the updated state. If the function returns -/// [`None`][std::option::Option::None], the iterator ends. +/// [`None`][core::option::Option::None], the iterator ends. /// /// # Examples /// ``` /// # #[macro_use] extern crate imbl; /// # use imbl::iter::unfold; /// # use imbl::vector::Vector; -/// # use std::iter::FromIterator; +/// # use core::iter::FromIterator; /// // Create an infinite stream of numbers, starting at 0. /// let mut it = unfold(0, |i| Some((i, i + 1))); /// @@ -26,14 +26,14 @@ /// assert_eq!(numbers, vector![0, 1, 2, 3, 4]); /// ``` /// -/// [std::option::Option]: https://doc.rust-lang.org/std/option/enum.Option.html -/// [std::option::Option::None]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None +/// [core::option::Option]: https://doc.rust-lang.org/core/option/enum.Option.html +/// [core::option::Option::None]: https://doc.rust-lang.org/core/option/enum.Option.html#variant.None pub fn unfold(value: S, f: F) -> impl Iterator where F: Fn(S) -> Option<(A, S)>, { let mut value = Some(value); - std::iter::from_fn(move || { + core::iter::from_fn(move || { f(value.take().unwrap()).map(|(next, state)| { value = Some(state); next diff --git a/src/lib.rs b/src/lib.rs index c7fcb6f..f82e187 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,7 +62,7 @@ //! usage, indexing and operations that happen at the back of the //! list, but is terrible at insertion and removal, and gets worse the //! closer to the front of the list you get. -//! [`VecDeque`](std::collections::VecDeque) adds a little bit of +//! [`VecDeque`](alloc::collections::VecDeque) adds a little bit of //! complexity in order to make operations at the front as efficient //! as operations at the back, but is still bad at insertion and //! especially concatenation. [`Vector`] adds another @@ -112,22 +112,22 @@ //! //! On the other hand, if you want to store values for which cloning is //! expensive, or values that don't implement [`Clone`], you -//! need to wrap them in [`Rc`][std::rc::Rc] or [`Arc`][std::sync::Arc]. Thus, +//! need to wrap them in [`Rc`][alloc::rc::Rc] or [`Arc`][alloc::sync::Arc]. Thus, //! if you have a complex structure `BigBlobOfData` and you want to store a list //! of them as a `Vector`, you should instead use a //! `Vector>`, which is going to save you not only the time //! spent cloning the big blobs of data, but also the memory spent keeping -//! multiple copies of it around, as [`Rc`][std::rc::Rc] keeps a single +//! multiple copies of it around, as [`Rc`][alloc::rc::Rc] keeps a single //! reference counted copy around instead. //! //! If you're storing smaller values that aren't //! [`Copy`]able, you'll need to exercise judgement: if your //! values are going to be very cheap to clone, as would be the case for short //! [`String`] or small [`Vec`]s, you're probably better off storing them directly -//! without wrapping them in an [`Rc`][std::rc::Rc], because, like the [`Rc`][std::rc::Rc], +//! without wrapping them in an [`Rc`][alloc::rc::Rc], because, like the [`Rc`][alloc::rc::Rc], // they're just pointers to some data on the heap, and that data isn't expensive to clone - //! you might actually lose more performance from the extra redirection of -//! wrapping them in an [`Rc`][std::rc::Rc] than you would from occasionally +//! wrapping them in an [`Rc`][alloc::rc::Rc] than you would from occasionally //! cloning them. //! //! ### When does cloning happen? @@ -232,7 +232,7 @@ //! //! | Type | Algorithm | Key Constraints | Order | Insert | Remove | Lookup | //! | --- | --- | --- | --- | --- | --- | --- | -//! | [`HashMap`] | [HAMT][hamt] | [`Clone`] + [`Hash`][std::hash::Hash] + [`Eq`] | undefined | O(log n) | O(log n) | O(log n) | +//! | [`HashMap`] | [HAMT][hamt] | [`Clone`] + [`Hash`][core::hash::Hash] + [`Eq`] | undefined | O(log n) | O(log n) | O(log n) | //! | [`OrdMap`] | [B+tree][b+tree] | [`Clone`] + [`Ord`] | sorted | O(log n) | O(log n) | O(log n) | //! //! ### Sets @@ -243,7 +243,7 @@ //! //! | Type | Algorithm | Constraints | Order | Insert | Remove | Lookup | //! | --- | --- | --- | --- | --- | --- | --- | -//! | [`HashSet`] | [HAMT][hamt] | [`Clone`] + [`Hash`][std::hash::Hash] + [`Eq`] | undefined | O(log n) | O(log n) | O(log n) | +//! | [`HashSet`] | [HAMT][hamt] | [`Clone`] + [`Hash`][core::hash::Hash] + [`Eq`] | undefined | O(log n) | O(log n) | O(log n) | //! | [`OrdSet`] | [B+tree][b+tree] | [`Clone`] + [`Ord`] | sorted | O(log n) | O(log n) | O(log n) | //! //! ## In-place Mutation @@ -254,9 +254,9 @@ //! performance hit of making a copy of the data structure before //! modifying it (this is about an order of magnitude faster than //! immutable operations, almost as fast as -//! [`std::collections`]'s mutable data structures). +//! [`alloc::collections`]'s mutable data structures). //! -//! Thanks to [`Rc`][std::rc::Rc]'s reference counting, we are able to +//! Thanks to [`Rc`][alloc::rc::Rc]'s reference counting, we are able to //! determine whether a node in a data structure is being shared with //! other data structures, or whether it's safe to mutate it in place. //! When it's shared, we'll automatically make a copy of the node @@ -277,12 +277,12 @@ //! think about this kind of managed scope, it's all taken care of //! behind the scenes because of our low level access to the garbage //! collector (which, in our case, is just a simple -//! [`Rc`](std::rc::Rc)). +//! [`Rc`](alloc::rc::Rc)). //! //! ## Thread Safety //! //! The data structures in `imbl` are thread safe by default using -//! [`Arc`](std::sync::Arc). However, `imbl` also supports `Rc` as the pointer +//! [`Arc`](alloc::sync::Arc). However, `imbl` also supports `Rc` as the pointer //! type through the [`archery`] crate, just like `im-rc` in the original //! `im` crate. If you prioritise speed over thread safety, you can use //! [`GenericVector`](vector::GenericVector) that uses @@ -308,7 +308,7 @@ //! | [`serde`](https://crates.io/crates/serde) | [`Serialize`](https://docs.rs/serde/latest/serde/trait.Serialize.html) and [`Deserialize`](https://docs.rs/serde/latest/serde/trait.Deserialize.html) implementations for all `imbl` datatypes | //! | [`bincode`](https://crates.io/crates/bincode) | [`Encode`](https://docs.rs/bincode/latest/bincode/enc/trait.Encode.html) and [`Decode`](https://docs.rs/bincode/latest/bincode/de/trait.Decode.html) implementations for all `imbl` datatypes | //! | [`arbitrary`](https://crates.io/crates/arbitrary/) | [`arbitrary::Arbitrary`](https://docs.rs/arbitrary/latest/arbitrary/trait.Arbitrary.html) implementations for all `imbl` datatypes | -//! | [`triomphe`](https://crates.io/crates/triomphe/) | Use [`triomphe::Arc`](https://docs.rs/triomphe/latest/triomphe/struct.Arc.html) for the default shared pointer. This is a drop-in replacement for [`std::sync::Arc`](https://doc.rust-lang.org/std/sync/struct.Arc.html) that is faster in some cases. | +//! | [`triomphe`](https://crates.io/crates/triomphe/) | Use [`triomphe::Arc`](https://docs.rs/triomphe/latest/triomphe/struct.Arc.html) for the default shared pointer. This is a drop-in replacement for [`alloc::sync::Arc`](https://doc.rust-lang.org/alloc/sync/struct.Arc.html) that is faster in some cases. | //! //! [rrb-tree]: https://infoscience.epfl.ch/record/213452/files/rrbvector.pdf //! [hamt]: https://en.wikipedia.org/wiki/Hash_array_mapped_trie @@ -319,6 +319,9 @@ #![deny(nonstandard_style)] #![warn(unreachable_pub, missing_docs)] #![deny(unsafe_code)] +#![cfg_attr(not(any(test, feature = "std")), no_std)] + +extern crate alloc; #[cfg(test)] #[macro_use] @@ -342,6 +345,14 @@ mod hash; pub use crate::hash::map as hashmap; pub use crate::hash::set as hashset; +/// A `BuildHasher` that uses the RandomState from standard library for hashing. +#[cfg(feature = "std")] +pub type RandomState = std::collections::hash_map::RandomState; + +/// A `BuildHasher` that uses SipHasher13 for hashing. +#[cfg(not(feature = "std"))] +pub type RandomState = core::hash::BuildHasherDefault; + #[macro_use] pub mod vector; @@ -393,7 +404,7 @@ mod tests; /// /// ``` /// # #[macro_use] extern crate imbl; -/// # use std::sync::Arc; +/// # use alloc::sync::Arc; /// # use imbl::Vector; /// # fn main() { /// let vec_inside_vec = vector![vector![1, 2, 3], vector![4, 5, 6]]; @@ -427,7 +438,7 @@ macro_rules! update_in { /// /// ``` /// # #[macro_use] extern crate imbl; -/// # use std::sync::Arc; +/// # use alloc::sync::Arc; /// # use imbl::Vector; /// # fn main() { /// let vec_inside_vec: Vector> = vector![vector![1, 2, 3], vector![4, 5, 6]]; diff --git a/src/nodes/btree.rs b/src/nodes/btree.rs index ae9847b..3c2c812 100644 --- a/src/nodes/btree.rs +++ b/src/nodes/btree.rs @@ -2,12 +2,13 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use std::borrow::Borrow; -use std::collections::VecDeque; -use std::iter::FromIterator; -use std::mem; -use std::num::NonZeroUsize; -use std::ops::{Bound, RangeBounds}; +use alloc::collections::VecDeque; +use alloc::vec::Vec; +use core::borrow::Borrow; +use core::iter::FromIterator; +use core::mem; +use core::num::NonZeroUsize; +use core::ops::{Bound, RangeBounds}; use archery::{SharedPointer, SharedPointerKind}; use imbl_sized_chunks::Chunk; @@ -28,7 +29,7 @@ pub(crate) enum Node { Leaf(SharedPointer, P>), } -impl Branch { +impl Branch { #[cfg(any(test, fuzzing))] pub(crate) fn check_sane(&self, is_root: bool) -> usize { assert!(self.keys.len() >= if is_root { 1 } else { MEDIAN - 1 }); @@ -55,7 +56,7 @@ impl Branch< } } } -impl Leaf { +impl Leaf { #[cfg(any(test, fuzzing))] pub(crate) fn check_sane(&self, is_root: bool) -> usize { assert!(self.keys.windows(2).all(|w| w[0].0 < w[1].0)); @@ -63,7 +64,7 @@ impl Leaf { self.keys.len() } } -impl Node { +impl Node { /// Check invariants #[cfg(any(test, fuzzing))] pub(crate) fn check_sane(&self, is_root: bool) -> usize { @@ -936,7 +937,7 @@ impl<'a, K, V, P: SharedPointerKind> Iter<'a, K, V, P> { bwd: &Cursor<'_, K, V, P>, ) -> bool { for (&(fi, f), &(bi, b)) in fwd.stack.iter().zip(bwd.stack.iter()) { - if !std::ptr::eq(f, b) { + if !core::ptr::eq(f, b) { return false; } if fi > bi { @@ -944,7 +945,7 @@ impl<'a, K, V, P: SharedPointerKind> Iter<'a, K, V, P> { } } if let (Some((fi, f)), Some((bi, b))) = (fwd.leaf, bwd.leaf) { - if !std::ptr::eq(f, b) { + if !core::ptr::eq(f, b) { return false; } if fi > bi { @@ -984,7 +985,7 @@ impl<'a, K, V, P: SharedPointerKind> Iter<'a, K, V, P> { // This is valid even if the cursors are empty due to not being initialized yet. // If they were empty because exhaustion we would not be in this function. if let (Some((fi, f)), Some((bi, b))) = (self.fwd.leaf, self.bwd.leaf) { - if std::ptr::eq(f, b) && fi >= bi { + if core::ptr::eq(f, b) && fi >= bi { self.exhausted = true; return fi == bi && other_side_yielded; } @@ -1203,7 +1204,7 @@ impl<'a, K, V, P: SharedPointerKind> Cursor<'a, K, V, P> { debug_assert!(self.leaf.is_some()); debug_assert!(other.leaf.is_some()); if let (Some(this), Some(that)) = (self.leaf, other.leaf) { - if std::ptr::eq(this.1, that.1) { + if core::ptr::eq(this.1, that.1) { self.leaf = None; other.leaf = None; skipped_any = true; @@ -1212,7 +1213,7 @@ impl<'a, K, V, P: SharedPointerKind> Cursor<'a, K, V, P> { .iter() .rev() .zip(other.stack.iter().rev()) - .take_while(|(this, that)| std::ptr::eq(this.1, that.1)) + .take_while(|(this, that)| core::ptr::eq(this.1, that.1)) .count(); if shared_levels != 0 { self.stack.drain(self.stack.len() - shared_levels..); @@ -1288,13 +1289,13 @@ mod slice_ext { #[allow(unsafe_code)] pub(super) fn binary_search_by(slice: &[T], mut f: F) -> Result where - F: FnMut(&T) -> std::cmp::Ordering, + F: FnMut(&T) -> core::cmp::Ordering, { // Optimization: defer to std-lib if we think we're comparing integers, in which case // the stdlib implementation optimizes better using a fully branchless approach. // This branch is fully resolved at compile-time and will not incur any space or runtime overhead. // There is a mild assumption that the std-lib implementation will remain optimized for primitive types. - if !std::mem::needs_drop::() && std::mem::size_of::() <= 16 { + if !core::mem::needs_drop::() && core::mem::size_of::() <= 16 { return slice.binary_search_by(f); } @@ -1303,7 +1304,7 @@ mod slice_ext { // function returns `Equal`, which is best when the comparison function isn't trivial // (e.g. `memcmp` vs. integer comparison). - use std::cmp::Ordering::*; + use core::cmp::Ordering::*; let mut low = 0; let mut high = slice.len(); // Compared to the stdlib this implementation perform early return when the comparison @@ -1323,14 +1324,14 @@ mod slice_ext { if cmp == Equal { // Safety: same as above unsafe { - std::hint::assert_unchecked(mid < slice.len()); + core::hint::assert_unchecked(mid < slice.len()); } return Ok(mid); } } // Safety: see low assignment above unsafe { - std::hint::assert_unchecked(low <= slice.len()); + core::hint::assert_unchecked(low <= slice.len()); } Err(low) } diff --git a/src/nodes/hamt.rs b/src/nodes/hamt.rs index 0bb1c52..2bba65e 100644 --- a/src/nodes/hamt.rs +++ b/src/nodes/hamt.rs @@ -2,13 +2,15 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use std::borrow::Borrow; -use std::cell::UnsafeCell; -use std::hash::{BuildHasher, Hash}; -use std::iter::FusedIterator; -use std::mem::{ManuallyDrop, MaybeUninit}; -use std::slice::{Iter as SliceIter, IterMut as SliceIterMut}; -use std::{fmt, mem, ptr}; +use alloc::vec; +use alloc::vec::Vec; +use core::borrow::Borrow; +use core::cell::UnsafeCell; +use core::hash::{BuildHasher, Hash}; +use core::iter::FusedIterator; +use core::mem::{ManuallyDrop, MaybeUninit}; +use core::slice::{Iter as SliceIter, IterMut as SliceIterMut}; +use core::{fmt, mem, ptr}; use archery::{SharedPointer, SharedPointerKind}; use bitmaps::{Bits, BitsImpl}; @@ -214,7 +216,7 @@ where while let Some(offset) = bitmap.first_index() { let index = group * GROUP_WIDTH + offset; - let (ref value, value_hash) = self.data.get(index).unwrap(); + let (value, value_hash) = self.data.get(index).unwrap(); if hash_may_eq::(hash, *value_hash) && key == value.extract_key().borrow() { return Some(value); } @@ -238,7 +240,7 @@ where let index = group * GROUP_WIDTH + offset; #[allow(unsafe_code)] let this = unsafe { &mut *this }; - let (ref mut value, value_hash) = this.data.get_mut(index).unwrap(); + let (value, value_hash) = this.data.get_mut(index).unwrap(); if hash_may_eq::(hash, *value_hash) && key == value.extract_key().borrow() { return Some(value); } @@ -257,7 +259,7 @@ where while let Some(offset) = bitmap.first_index() { let index = group * GROUP_WIDTH + offset; - let (ref value, value_hash) = self.data.get(index).unwrap(); + let (value, value_hash) = self.data.get(index).unwrap(); if hash_may_eq::(hash, *value_hash) && key == value.extract_key().borrow() { let mut ctrl_array = self.control[group].to_array(); ctrl_array[offset] = 0; @@ -418,12 +420,12 @@ impl HamtNode { // This is less relevant in other code paths that may include // atomics, memory allocation (e.g. insert, remove) etc.. match entry { - Entry::HamtNode(ref child) => { + Entry::HamtNode(child) => { node = child; shift += HASH_SHIFT; continue; } - Entry::Value(ref value, value_hash) => { + Entry::Value(value, value_hash) => { return if hash_may_eq::(hash, *value_hash) && key == value.extract_key().borrow() { @@ -448,9 +450,9 @@ impl HamtNode { A::Key: Borrow, { match entry { - Entry::SmallSimdNode(ref small) => small.get(hash, key), - Entry::LargeSimdNode(ref large) => large.get(hash, key), - Entry::Collision(ref coll) => coll.get(key), + Entry::SmallSimdNode(small) => small.get(hash, key), + Entry::LargeSimdNode(large) => large.get(hash, key), + Entry::Collision(coll) => coll.get(key), _ => unreachable!(), } } @@ -463,25 +465,23 @@ impl HamtNode { { let index = Self::mask(hash, shift) as usize; match self.data.get_mut(index) { - Some(Entry::HamtNode(ref mut child_ref)) => { + Some(Entry::HamtNode(child_ref)) => { SharedPointer::make_mut(child_ref).get_mut(hash, shift + HASH_SHIFT, key) } - Some(Entry::SmallSimdNode(ref mut small_ref)) => { + Some(Entry::SmallSimdNode(small_ref)) => { SharedPointer::make_mut(small_ref).get_mut(hash, key) } - Some(Entry::LargeSimdNode(ref mut large_ref)) => { + Some(Entry::LargeSimdNode(large_ref)) => { SharedPointer::make_mut(large_ref).get_mut(hash, key) } - Some(Entry::Value(ref mut value, value_hash)) => { + Some(Entry::Value(value, value_hash)) => { if hash_may_eq::(hash, *value_hash) && key == value.extract_key().borrow() { Some(value) } else { None } } - Some(Entry::Collision(ref mut coll_ref)) => { - SharedPointer::make_mut(coll_ref).get_mut(key) - } + Some(Entry::Collision(coll_ref)) => SharedPointer::make_mut(coll_ref).get_mut(key), None => None, } } diff --git a/src/nodes/rrb.rs b/src/nodes/rrb.rs index b2befe1..9193570 100644 --- a/src/nodes/rrb.rs +++ b/src/nodes/rrb.rs @@ -2,8 +2,8 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use std::mem::replace; -use std::ops::Range; +use core::mem::replace; +use core::ops::Range; use archery::{SharedPointer, SharedPointerKind}; @@ -70,7 +70,7 @@ impl Size

{ if let Size::Size(size) = self { *self = Size::table_from_size(level, *size); }; - if let Size::Table(ref mut size_ref) = self { + if let Size::Table(size_ref) = self { let size_table = SharedPointer::make_mut(size_ref); debug_assert!(size_table.len() < NODE_SIZE); match side { @@ -93,14 +93,14 @@ impl Size

{ fn pop(&mut self, side: Side, level: usize, value: usize) { let size = match self { - Size::Size(ref mut size) => match side { + Size::Size(size) => match side { Left => *size, Right => { *size -= value; return; } }, - Size::Table(ref mut size_ref) => { + Size::Table(size_ref) => { let size_table = SharedPointer::make_mut(size_ref); match side { Left => { @@ -125,8 +125,8 @@ impl Size

{ fn update(&mut self, index: usize, level: usize, value: isize) { let size = match self { - Size::Size(ref size) => *size, - Size::Table(ref mut size_ref) => { + &mut Size::Size(ref size) => *size, + Size::Table(size_ref) => { let size_table = SharedPointer::make_mut(size_ref); for entry in size_table.iter_mut().skip(index) { *entry = (*entry as isize + value) as usize; @@ -175,30 +175,30 @@ impl Clone for Entry { impl Entry { fn len(&self) -> usize { match self { - Nodes(_, ref nodes) => nodes.len(), - Values(ref values) => values.len(), + Nodes(_, nodes) => nodes.len(), + Values(values) => values.len(), Empty => 0, } } fn is_full(&self) -> bool { match self { - Nodes(_, ref nodes) => nodes.is_full(), - Values(ref values) => values.is_full(), + Nodes(_, nodes) => nodes.is_full(), + Values(values) => values.is_full(), Empty => false, } } fn unwrap_values(&self) -> &Chunk { match self { - Values(ref values) => values, + Values(values) => values, _ => panic!("rrb::Entry::unwrap_values: expected values, found nodes"), } } fn unwrap_nodes(&self) -> &Chunk> { match self { - Nodes(_, ref nodes) => nodes, + Nodes(_, nodes) => nodes, _ => panic!("rrb::Entry::unwrap_nodes: expected nodes, found values"), } } @@ -211,14 +211,14 @@ impl Entry { impl Entry { fn unwrap_values_mut(&mut self) -> &mut Chunk { match self { - Values(ref mut values) => SharedPointer::make_mut(values), + Values(values) => SharedPointer::make_mut(values), _ => panic!("rrb::Entry::unwrap_values_mut: expected values, found nodes"), } } fn unwrap_nodes_mut(&mut self) -> &mut Chunk> { match self { - Nodes(_, ref mut nodes) => SharedPointer::make_mut(nodes), + Nodes(_, nodes) => SharedPointer::make_mut(nodes), _ => panic!("rrb::Entry::unwrap_nodes_mut: expected nodes, found values"), } } @@ -436,7 +436,7 @@ impl Node { 0 } else { match size { - Size::Table(ref size_table) => size_table[index - 1], + Size::Table(size_table) => size_table[index - 1], Size::Size(_) => index * NODE_SIZE.pow(level as u32), } } @@ -528,7 +528,7 @@ impl Node { let total: usize = lengths.iter().sum(); assert_eq!(*size, total); } - Size::Table(ref table) => { + Size::Table(table) => { assert_eq!(table.iter().len(), children.len()); for (index, current) in table.iter().enumerate() { let expected: usize = lengths.iter().take(index + 1).sum(); @@ -561,7 +561,7 @@ impl Node { Entry::Nodes(ref size, ref children) => { let label = match size { Size::Size(size) => size.to_string(), - Size::Table(ref table) => { + Size::Table(table) => { format!("\"{:?}\"", table.as_slice()) } }; @@ -912,7 +912,7 @@ impl Node { if let Size::Size(value) = *size { *size = Size::table_from_size(level, value); } - let size_table = if let Size::Table(ref mut size_ref) = size { + let size_table = if let Size::Table(size_ref) = size { SharedPointer::make_mut(size_ref) } else { unreachable!() @@ -938,10 +938,10 @@ impl Node { children.drop_right(drop_from); } match size { - Size::Size(ref mut size) if at_last => { + Size::Size(size) if at_last => { *size -= dropped; } - Size::Size(ref mut size) => { + Size::Size(size) => { let size_per_child = NODE_SIZE.pow(level as u32); let remainder = (target_idx + 1) * size_per_child; let new_size = remainder - dropped; @@ -954,7 +954,7 @@ impl Node { ); } } - Size::Table(ref mut size_ref) => { + Size::Table(size_ref) => { let size_table = SharedPointer::make_mut(size_ref); let dropped_size = size_table[size_table.len() - 1] - size_table[target_idx]; diff --git a/src/ord/map.rs b/src/ord/map.rs index ecac628..f5b4653 100644 --- a/src/ord/map.rs +++ b/src/ord/map.rs @@ -9,22 +9,24 @@ //! Most operations on this type of map are O(log n). A //! [`HashMap`][hashmap::HashMap] is usually a better choice for //! performance, but the `OrdMap` has the advantage of only requiring -//! an [`Ord`][std::cmp::Ord] constraint on the key, and of being +//! an [`Ord`][core::cmp::Ord] constraint on the key, and of being //! ordered, so that keys always come out from lowest to highest, //! where a [`HashMap`][hashmap::HashMap] has no guaranteed ordering. //! //! [1]: https://en.wikipedia.org/wiki/B%2B_tree //! [hashmap::HashMap]: ../hashmap/type.HashMap.html -//! [std::cmp::Ord]: https://doc.rust-lang.org/std/cmp/trait.Ord.html - -use std::borrow::Borrow; -use std::cmp::Ordering; -use std::collections; -use std::fmt::{Debug, Error, Formatter}; -use std::hash::{BuildHasher, Hash, Hasher}; -use std::iter::{FromIterator, FusedIterator, Sum}; -use std::mem; -use std::ops::{Add, Bound, Index, IndexMut, RangeBounds}; +//! [core::cmp::Ord]: https://doc.rust-lang.org/core/cmp/trait.Ord.html + +use alloc::borrow::ToOwned; +use alloc::collections; +use alloc::vec::Vec; +use core::borrow::Borrow; +use core::cmp::Ordering; +use core::fmt::{Debug, Error, Formatter}; +use core::hash::{BuildHasher, Hash, Hasher}; +use core::iter::{FromIterator, FusedIterator, Sum}; +use core::mem; +use core::ops::{Add, Bound, Index, IndexMut, RangeBounds}; use archery::{SharedPointer, SharedPointerKind}; @@ -78,13 +80,13 @@ pub type OrdMap = GenericOrdMap; /// Most operations on this type of map are O(log n). A /// [`HashMap`][hashmap::HashMap] is usually a better choice for /// performance, but the `OrdMap` has the advantage of only requiring -/// an [`Ord`][std::cmp::Ord] constraint on the key, and of being +/// an [`Ord`][core::cmp::Ord] constraint on the key, and of being /// ordered, so that keys always come out from lowest to highest, /// where a [`HashMap`][hashmap::HashMap] has no guaranteed ordering. /// /// [1]: https://en.wikipedia.org/wiki/B%2B_tree /// [hashmap::HashMap]: ../hashmap/type.HashMap.html -/// [std::cmp::Ord]: https://doc.rust-lang.org/std/cmp/trait.Ord.html +/// [core::cmp::Ord]: https://doc.rust-lang.org/core/cmp/trait.Ord.html pub struct GenericOrdMap { size: usize, root: Option>, @@ -534,8 +536,8 @@ where #[allow(unreachable_pub)] pub fn check_sane(&self) where - K: std::fmt::Debug, - V: std::fmt::Debug, + K: core::fmt::Debug, + V: core::fmt::Debug, { let size = self .root @@ -858,14 +860,14 @@ where /// the current value and overwriting it with the function's /// return value. /// - /// The function gets an [`Option`][std::option::Option] and + /// The function gets an [`Option`][core::option::Option] and /// returns the same, so that it can decide to delete a mapping /// instead of updating the value, and decide what to do if the /// key isn't in the map. /// /// Time: O(log n) /// - /// [std::option::Option]: https://doc.rust-lang.org/std/option/enum.Option.html + /// [core::option::Option]: https://doc.rust-lang.org/core/option/enum.Option.html #[must_use] pub fn alter(&self, f: F, k: K) -> Self where @@ -1548,7 +1550,7 @@ where F: FnOnce(&mut V), { match &mut self { - Entry::Occupied(ref mut entry) => f(entry.get_mut()), + Entry::Occupied(entry) => f(entry.get_mut()), Entry::Vacant(_) => (), } self @@ -2247,18 +2249,50 @@ where } } -impl From> for GenericOrdMap +#[cfg(feature = "std")] +impl From> + for GenericOrdMap +where + K: Ord + Clone + From, + V: Clone + From, + P: SharedPointerKind, +{ + fn from(m: std::collections::HashMap) -> GenericOrdMap { + m.into_iter().collect() + } +} + +#[cfg(feature = "std")] +impl<'a, K, V, OK, OV, RK, RV, P> From<&'a std::collections::HashMap> + for GenericOrdMap +where + K: Ord + Clone + From, + V: Clone + From, + OK: Borrow, + OV: Borrow, + RK: Hash + Eq + ToOwned, + RV: ToOwned, + P: SharedPointerKind, +{ + fn from(m: &'a std::collections::HashMap) -> GenericOrdMap { + m.iter() + .map(|(k, v)| (k.to_owned(), v.to_owned())) + .collect() + } +} + +impl From> for GenericOrdMap where K: Ord + Clone + From, V: Clone + From, P: SharedPointerKind, { - fn from(m: collections::HashMap) -> GenericOrdMap { + fn from(m: hashbrown::HashMap) -> GenericOrdMap { m.into_iter().collect() } } -impl<'a, K, V, OK, OV, RK, RV, P> From<&'a collections::HashMap> for GenericOrdMap +impl<'a, K, V, OK, OV, RK, RV, P> From<&'a hashbrown::HashMap> for GenericOrdMap where K: Ord + Clone + From, V: Clone + From, @@ -2268,7 +2302,7 @@ where RV: ToOwned, P: SharedPointerKind, { - fn from(m: &'a collections::HashMap) -> GenericOrdMap { + fn from(m: &'a hashbrown::HashMap) -> GenericOrdMap { m.iter() .map(|(k, v)| (k.to_owned(), v.to_owned())) .collect() @@ -2346,7 +2380,7 @@ pub mod proptest { #[cfg(test)] mod test { - use std::collections::BTreeMap; + use alloc::collections::BTreeMap; use super::*; use crate::proptest::*; @@ -2603,13 +2637,13 @@ mod test { #[test] fn range_iter_big() { use crate::nodes::btree::NODE_SIZE; - use std::ops::Bound::Included; + use core::ops::Bound::Included; const N: usize = NODE_SIZE * NODE_SIZE * NODE_SIZE / 2; // enough for a sizeable 3 level tree let data = (1usize..N).filter(|i| i % 2 == 0).map(|i| (i, ())); let bmap = data .clone() - .collect::>(); + .collect::>(); let omap = data.collect::>(); assert_eq!(bmap.len(), omap.len()); @@ -2692,11 +2726,10 @@ mod test { } #[test] - fn order(ref input in collection::hash_map(i16::ANY, i16::ANY, 0..1000)) { + fn order(ref input in collection::btree_map(i16::ANY, i16::ANY, 0..1000)) { let map: OrdMap = OrdMap::from(input.clone()); let keys = map.keys().cloned().collect::>(); - let mut expected_keys = input.keys().cloned().collect::>(); - expected_keys.sort(); + let expected_keys = input.keys().cloned().collect::>(); assert_eq!(keys, expected_keys); } @@ -2842,7 +2875,7 @@ mod test { } #[test] - fn remove_alien(ref orig in collection::hash_map(i16::ANY, i16::ANY, 0..1000)) { + fn remove_alien(ref orig in collection::btree_map(i16::ANY, i16::ANY, 0..1000)) { let mut map: OrdMap = OrdMap::from(orig.clone()); for key in orig.keys() { let len = map.len(); diff --git a/src/ord/set.rs b/src/ord/set.rs index 81afbe4..7b9da9b 100644 --- a/src/ord/set.rs +++ b/src/ord/set.rs @@ -9,21 +9,24 @@ //! Most operations on this type of set are O(log n). A //! [`GenericHashSet`] is usually a better choice for //! performance, but the `OrdSet` has the advantage of only requiring -//! an [`Ord`][std::cmp::Ord] constraint on its values, and of being +//! an [`Ord`][core::cmp::Ord] constraint on its values, and of being //! ordered, so values always come out from lowest to highest, where a //! [`GenericHashSet`] has no guaranteed ordering. //! //! [1]: https://en.wikipedia.org/wiki/B%2B_tree -use std::borrow::Borrow; -use std::cmp::Ordering; -use std::collections; -use std::fmt::{Debug, Error, Formatter}; -use std::hash::{BuildHasher, Hash, Hasher}; -use std::iter::{FromIterator, FusedIterator, Sum}; -use std::ops::{Add, Mul, RangeBounds}; +use alloc::borrow::ToOwned; +use alloc::collections; +use alloc::vec::Vec; +use core::borrow::Borrow; +use core::cmp::Ordering; +use core::fmt::{Debug, Error, Formatter}; +use core::hash::{BuildHasher, Hash, Hasher}; +use core::iter::{FromIterator, FusedIterator, Sum}; +use core::ops::{Add, Mul, RangeBounds}; use archery::SharedPointerKind; +use hashbrown::HashSet; use super::map; use crate::hashset::GenericHashSet; @@ -70,7 +73,7 @@ pub type OrdSet = GenericOrdSet; /// Most operations on this type of set are O(log n). A /// [`GenericHashSet`] is usually a better choice for /// performance, but the `OrdSet` has the advantage of only requiring -/// an [`Ord`][std::cmp::Ord] constraint on its values, and of being +/// an [`Ord`][core::cmp::Ord] constraint on its values, and of being /// ordered, so values always come out from lowest to highest, where a /// [`GenericHashSet`] has no guaranteed ordering. /// @@ -279,7 +282,7 @@ where /// ``` /// # #[macro_use] extern crate imbl; /// # use std::borrow::Borrow; - /// # use std::cmp::Ordering; + /// # use core::cmp::Ordering; /// # use imbl::ordset::OrdSet; /// # #[derive(Clone)] /// // Implements Eq and ord by delegating to id @@ -390,7 +393,7 @@ where #[allow(unreachable_pub)] pub fn check_sane(&self) where - A: std::fmt::Debug, + A: core::fmt::Debug, { self.map.check_sane(); } @@ -1100,18 +1103,14 @@ impl From<&Vec> for GenericOrdSet } } -impl From> - for GenericOrdSet -{ - fn from(hash_set: collections::HashSet) -> Self { +impl From> for GenericOrdSet { + fn from(hash_set: HashSet) -> Self { hash_set.into_iter().collect() } } -impl From<&collections::HashSet> - for GenericOrdSet -{ - fn from(hash_set: &collections::HashSet) -> Self { +impl From<&HashSet> for GenericOrdSet { + fn from(hash_set: &HashSet) -> Self { hash_set.iter().cloned().collect() } } diff --git a/src/proptest.rs b/src/proptest.rs index 5ff89aa..25b462f 100644 --- a/src/proptest.rs +++ b/src/proptest.rs @@ -5,9 +5,9 @@ use crate::{HashMap, HashSet, OrdMap, OrdSet, Vector}; use ::proptest::collection::vec; use ::proptest::strategy::{BoxedStrategy, Strategy, ValueTree}; -use std::hash::Hash; -use std::iter::FromIterator; -use std::ops::Range; +use core::hash::Hash; +use core::iter::FromIterator; +use core::ops::Range; /// A strategy for generating a [`Vector`][Vector] of a certain size. /// diff --git a/src/quickcheck.rs b/src/quickcheck.rs index c03335d..8849429 100644 --- a/src/quickcheck.rs +++ b/src/quickcheck.rs @@ -3,8 +3,8 @@ use crate::{ GenericVector, }; use ::quickcheck::{Arbitrary, Gen}; -use std::hash::{BuildHasher, Hash}; -use std::iter::FromIterator; +use core::hash::{BuildHasher, Hash}; +use core::iter::FromIterator; impl Arbitrary for GenericVector diff --git a/src/ser.rs b/src/ser.rs index d8ba69d..f6faf64 100644 --- a/src/ser.rs +++ b/src/ser.rs @@ -3,11 +3,11 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. use archery::SharedPointerKind; +use core::fmt; +use core::hash::{BuildHasher, Hash}; +use core::marker::PhantomData; use serde_core::de::{Deserialize, Deserializer, MapAccess, SeqAccess, Visitor}; use serde_core::ser::{Serialize, SerializeMap, SerializeSeq, Serializer}; -use std::fmt; -use std::hash::{BuildHasher, Hash}; -use std::marker::PhantomData; use crate::hashmap::GenericHashMap; use crate::hashset::GenericHashSet; diff --git a/src/sort.rs b/src/sort.rs index e500ad6..89d4e0c 100644 --- a/src/sort.rs +++ b/src/sort.rs @@ -4,9 +4,9 @@ use crate::vector::FocusMut; use archery::SharedPointerKind; +use core::cmp::Ordering; +use core::mem; use rand_core::{RngCore, SeedableRng}; -use std::cmp::Ordering; -use std::mem; fn gen_range(rng: &mut R, min: usize, max: usize) -> usize { let range = max - min; diff --git a/src/sync.rs b/src/sync.rs index ac1f80e..7180601 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -7,7 +7,11 @@ pub(crate) use self::lock::Lock; // FIXME: This is intended to be replaced by something else when using the non-threadsafe, `Rc` // version of this crate. We have temporarily disabled that. mod lock { - use std::sync::{Arc, Mutex, MutexGuard}; + use alloc::sync::Arc; + #[cfg(not(feature = "std"))] + use spin::{Mutex, MutexGuard}; + #[cfg(feature = "std")] + use std::sync::{Mutex, MutexGuard}; /// Thread safe lock: just wraps a `Mutex`. pub(crate) struct Lock { @@ -23,7 +27,14 @@ mod lock { #[inline] pub(crate) fn lock(&mut self) -> Option> { - self.lock.lock().ok() + #[cfg(not(feature = "std"))] + { + Some(self.lock.lock()) + } + #[cfg(feature = "std")] + { + self.lock.lock().ok() + } } } diff --git a/src/test.rs b/src/test.rs index 48aa369..7ed5c14 100644 --- a/src/test.rs +++ b/src/test.rs @@ -2,8 +2,8 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use core::hash::{BuildHasher, Hasher}; use metrohash::MetroHash64; -use std::hash::{BuildHasher, Hasher}; pub(crate) fn is_sorted(l: I) -> bool where diff --git a/src/tests/hashset.rs b/src/tests/hashset.rs index 01df2be..de849da 100644 --- a/src/tests/hashset.rs +++ b/src/tests/hashset.rs @@ -1,8 +1,12 @@ #![allow(clippy::unit_arg)] +#[cfg(not(feature = "std"))] +use hashbrown::HashSet as NatSet; +#[cfg(feature = "std")] use std::collections::HashSet as NatSet; -use std::fmt::{Debug, Error, Formatter, Write}; -use std::hash::Hash; + +use core::fmt::{Debug, Error, Formatter, Write}; +use core::hash::Hash; use crate::HashSet; @@ -30,11 +34,11 @@ where writeln!(out, "let mut set = HashSet::new();")?; for action in &self.0 { match action { - Action::Insert(ref value) => { + Action::Insert(value) => { expected.insert(value.clone()); writeln!(out, "set.insert({:?});", value)?; } - Action::Remove(ref value) => { + Action::Remove(value) => { expected.remove(value); writeln!(out, "set.remove({:?});", value)?; } diff --git a/src/tests/ordset.rs b/src/tests/ordset.rs index 80e245e..daa33ba 100644 --- a/src/tests/ordset.rs +++ b/src/tests/ordset.rs @@ -1,7 +1,7 @@ #![allow(clippy::unit_arg)] -use std::collections::BTreeSet; -use std::fmt::{Debug, Error, Formatter, Write}; +use alloc::collections::BTreeSet; +use core::fmt::{Debug, Error, Formatter, Write}; use crate::OrdSet; @@ -29,11 +29,11 @@ where writeln!(out, "let mut set = OrdSet::new();")?; for action in &self.0 { match action { - Action::Insert(ref value) => { + Action::Insert(value) => { expected.insert(value.clone()); writeln!(out, "set.insert({:?});", value)?; } - Action::Remove(ref value) => { + Action::Remove(value) => { expected.remove(value); writeln!(out, "set.remove({:?});", value)?; } diff --git a/src/tests/vector.rs b/src/tests/vector.rs index eb95929..c954617 100644 --- a/src/tests/vector.rs +++ b/src/tests/vector.rs @@ -1,7 +1,7 @@ #![allow(clippy::unit_arg)] -use std::fmt::{Debug, Error, Formatter, Write}; -use std::iter::FromIterator; +use core::fmt::{Debug, Error, Formatter, Write}; +use core::iter::FromIterator; use crate::{GenericVector, Vector}; @@ -37,11 +37,11 @@ where writeln!(out, "let mut vec = Vector::new();")?; for action in &self.0 { match action { - Action::PushFront(ref value) => { + Action::PushFront(value) => { expected.insert(0, value.clone()); writeln!(out, "vec.push_front({:?});", value)? } - Action::PushBack(ref value) => { + Action::PushBack(value) => { expected.push(value.clone()); writeln!(out, "vec.push_back({:?});", value)? } @@ -55,12 +55,12 @@ where expected.pop(); writeln!(out, "vec.pop_back();")? } - Action::Insert(ref index, ref value) => { + Action::Insert(index, value) => { let index = cap_index(expected.len(), *index); expected.insert(index, value.clone()); writeln!(out, "vec.insert({:?}, {:?});", index, value)? } - Action::Remove(ref index) => { + Action::Remove(index) => { if !expected.is_empty() { let index = cap_index(expected.len(), *index); expected.remove(index); @@ -69,7 +69,7 @@ where continue; } } - Action::JoinLeft(ref vec) => { + Action::JoinLeft(vec) => { let mut vec_new = vec.clone(); vec_new.append(&mut expected); expected = vec_new; @@ -82,7 +82,7 @@ where writeln!(out, "vec_new.append(vec);")?; writeln!(out, "vec = vec_new;")? } - Action::JoinRight(ref vec) => { + Action::JoinRight(vec) => { expected.append(&mut vec.clone()); writeln!( out, @@ -91,12 +91,12 @@ where vec.len() )? } - Action::SplitLeft(ref index) => { + Action::SplitLeft(index) => { let index = cap_index(expected.len(), *index); expected.truncate(index); writeln!(out, "vec.split_off({:?});", index)? } - Action::SplitRight(ref index) => { + Action::SplitRight(index) => { let index = cap_index(expected.len(), *index); expected = expected.split_off(index); writeln!(out, "vec = vec.split_off({:?});", index)? diff --git a/src/util.rs b/src/util.rs index b68cecd..cba1948 100644 --- a/src/util.rs +++ b/src/util.rs @@ -4,7 +4,7 @@ // Every codebase needs a `util` module. -use std::ops::{Bound, Range, RangeBounds}; +use core::ops::{Bound, Range, RangeBounds}; use archery::{SharedPointer, SharedPointerKind}; diff --git a/src/vector/focus.rs b/src/vector/focus.rs index cf577d0..a4060d2 100644 --- a/src/vector/focus.rs +++ b/src/vector/focus.rs @@ -2,10 +2,10 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use std::mem::{replace, swap}; -use std::ops::{Range, RangeBounds}; -use std::ptr::null; -use std::sync::atomic::{AtomicPtr, Ordering}; +use core::mem::{replace, swap}; +use core::ops::{Range, RangeBounds}; +use core::ptr::null; +use core::sync::atomic::{AtomicPtr, Ordering}; use archery::{SharedPointer, SharedPointerKind}; @@ -70,7 +70,7 @@ fn check_indices(len: usize, indices: &[usize; N]) -> Option<()> /// ```rust /// # #[macro_use] extern crate imbl; /// # use imbl::vector::Vector; -/// # use std::iter::FromIterator; +/// # use core::iter::FromIterator; /// let mut vec: Vector = Vector::from_iter(0..1000); /// /// // Summing a vector, the slow way: @@ -180,14 +180,14 @@ where /// ```rust /// # #[macro_use] extern crate imbl; /// # use imbl::vector::Vector; - /// # use std::iter::FromIterator; + /// # use core::iter::FromIterator; /// let vec: Vector = Vector::from_iter(0..1000); /// let narrowed = vec.focus().narrow(100..200); /// let narrowed_vec: Vector = narrowed.into_iter().cloned().collect(); /// assert_eq!(Vector::from_iter(100..200), narrowed_vec); /// ``` /// - /// [slice::split_at]: https://doc.rust-lang.org/std/primitive.slice.html#method.split_at + /// [slice::split_at]: https://doc.rust-lang.org/core/primitive.slice.html#method.split_at /// [Vector::split_at]: type.Vector.html#method.split_at #[must_use] pub fn narrow(self, range: R) -> Self @@ -221,7 +221,7 @@ where /// ```rust /// # #[macro_use] extern crate imbl; /// # use imbl::vector::Vector; - /// # use std::iter::FromIterator; + /// # use core::iter::FromIterator; /// let vec: Vector = Vector::from_iter(0..1000); /// let (left, right) = vec.focus().split_at(500); /// let left_vec: Vector = left.into_iter().cloned().collect(); @@ -230,7 +230,7 @@ where /// assert_eq!(Vector::from_iter(500..1000), right_vec); /// ``` /// - /// [slice::split_at]: https://doc.rust-lang.org/std/primitive.slice.html#method.split_at + /// [slice::split_at]: https://doc.rust-lang.org/core/primitive.slice.html#method.split_at /// [Vector::split_at]: type.Vector.html#method.split_at pub fn split_at(self, index: usize) -> (Self, Self) { if index > self.len() { @@ -445,7 +445,7 @@ impl TreeFocus { /// ```rust,compile_fail /// # #[macro_use] extern crate imbl; /// # use imbl::vector::Vector; -/// # use std::iter::FromIterator; +/// # use core::iter::FromIterator; /// let mut vec: Vector = Vector::from_iter(0..1000); /// let focus1 = vec.focus_mut(); /// // Fails here in 2015 edition because you're creating @@ -462,7 +462,7 @@ impl TreeFocus { /// ```rust /// # #[macro_use] extern crate imbl; /// # use imbl::vector::Vector; -/// # use std::iter::FromIterator; +/// # use core::iter::FromIterator; /// let mut vec: Vector = Vector::from_iter(0..1000); /// let focus = vec.focus_mut(); /// let (mut left, mut right) = focus.split_at(500); @@ -476,7 +476,7 @@ impl TreeFocus { /// ```rust,compile_fail /// # #[macro_use] extern crate imbl; /// # use imbl::vector::Vector; -/// # use std::iter::FromIterator; +/// # use core::iter::FromIterator; /// let mut vec: Vector = Vector::from_iter(0..1000); /// let (left, right) = { /// let focus = vec.focus_mut(); @@ -527,14 +527,14 @@ where /// ```rust /// # #[macro_use] extern crate imbl; /// # use imbl::vector::Vector; - /// # use std::iter::FromIterator; + /// # use core::iter::FromIterator; /// let mut vec: Vector = Vector::from_iter(0..1000); /// let narrowed = vec.focus_mut().narrow(100..200); /// let narrowed_vec: Vector = narrowed.unmut().into_iter().cloned().collect(); /// assert_eq!(Vector::from_iter(100..200), narrowed_vec); /// ``` /// - /// [slice::split_at]: https://doc.rust-lang.org/std/primitive.slice.html#method.split_at + /// [slice::split_at]: https://doc.rust-lang.org/core/primitive.slice.html#method.split_at /// [Vector::split_at]: type.Vector.html#method.split_at #[must_use] pub fn narrow(self, range: R) -> Self @@ -568,7 +568,7 @@ where /// ```rust /// # #[macro_use] extern crate imbl; /// # use imbl::vector::Vector; - /// # use std::iter::FromIterator; + /// # use core::iter::FromIterator; /// let mut vec: Vector = Vector::from_iter(0..1000); /// { /// let (left, right) = vec.focus_mut().split_at(500); @@ -584,7 +584,7 @@ where /// assert_eq!(expected, vec); /// ``` /// - /// [slice::split_at]: https://doc.rust-lang.org/std/primitive.slice.html#method.split_at + /// [slice::split_at]: https://doc.rust-lang.org/core/primitive.slice.html#method.split_at /// [Vector::split_at]: type.Vector.html#method.split_at #[allow(clippy::redundant_clone)] pub fn split_at(self, index: usize) -> (Self, Self) { @@ -719,7 +719,7 @@ where /// ```rust /// # #[macro_use] extern crate imbl; /// # use imbl::vector::Vector; - /// # use std::iter::FromIterator; + /// # use core::iter::FromIterator; /// let mut vec: Vector = vector![1, 2, 3, 4, 5]; /// vec.focus_mut().pair(1, 3, |a, b| *a += *b); /// assert_eq!(vector![1, 6, 3, 4, 5], vec); @@ -747,7 +747,7 @@ where /// ```rust /// # #[macro_use] extern crate imbl; /// # use imbl::vector::Vector; - /// # use std::iter::FromIterator; + /// # use core::iter::FromIterator; /// let mut vec: Vector = vector![1, 2, 3, 4, 5]; /// vec.focus_mut().triplet(0, 2, 4, |a, b, c| *a += *b + *c); /// assert_eq!(vector![9, 2, 3, 4, 5], vec); diff --git a/src/vector/mod.rs b/src/vector/mod.rs index 8c15725..11e37e8 100644 --- a/src/vector/mod.rs +++ b/src/vector/mod.rs @@ -40,19 +40,21 @@ //! //! [rrbpaper]: https://infoscience.epfl.ch/record/213452/files/rrbvector.pdf //! [chunkedseq]: http://deepsea.inria.fr/pasl/chunkedseq.pdf -//! [Vec]: https://doc.rust-lang.org/std/vec/struct.Vec.html -//! [VecDeque]: https://doc.rust-lang.org/std/collections/struct.VecDeque.html +//! [Vec]: https://doc.rust-lang.org/alloc/vec/struct.Vec.html +//! [VecDeque]: https://doc.rust-lang.org/alloc/collections/vec_deque/struct.VecDeque.html #![allow(unsafe_code)] -use std::borrow::Borrow; -use std::cmp::Ordering; -use std::fmt::{Debug, Error, Formatter}; -use std::hash::{Hash, Hasher}; -use std::iter::Sum; -use std::iter::{FromIterator, FusedIterator}; -use std::mem::{replace, swap}; -use std::ops::{Add, Index, IndexMut, RangeBounds}; +use alloc::borrow::ToOwned; +use alloc::vec::Vec; +use core::borrow::Borrow; +use core::cmp::Ordering; +use core::fmt::{Debug, Error, Formatter}; +use core::hash::{Hash, Hasher}; +use core::iter::Sum; +use core::iter::{FromIterator, FusedIterator}; +use core::mem::{replace, swap}; +use core::ops::{Add, Index, IndexMut, RangeBounds}; use archery::{SharedPointer, SharedPointerKind}; use imbl_sized_chunks::InlineArray; @@ -147,8 +149,8 @@ pub type Vector = GenericVector; /// /// [rrbpaper]: https://infoscience.epfl.ch/record/213452/files/rrbvector.pdf /// [chunkedseq]: http://deepsea.inria.fr/pasl/chunkedseq.pdf -/// [Vec]: https://doc.rust-lang.org/std/vec/struct.Vec.html -/// [VecDeque]: https://doc.rust-lang.org/std/collections/struct.VecDeque.html +/// [Vec]: https://doc.rust-lang.org/alloc/vec/struct.Vec.html +/// [VecDeque]: https://doc.rust-lang.org/alloc/collections/vec_deque/struct.VecDeque.html pub struct GenericVector { vector: VectorInner, } @@ -300,7 +302,7 @@ impl GenericVector { /// Test whether a vector is currently inlined. /// /// Vectors small enough that their contents could be stored entirely inside - /// the space of `std::mem::size_of::>()` bytes are stored inline on + /// the space of `core::mem::size_of::>()` bytes are stored inline on /// the stack instead of allocating any chunks. This method returns `true` if /// this vector is currently inlined, or `false` if it currently has chunks allocated /// on the heap. @@ -341,7 +343,7 @@ impl GenericVector { (left.is_empty() && right.is_empty()) || SharedPointer::ptr_eq(left, right) } - if std::ptr::eq(self, other) { + if core::ptr::eq(self, other) { return true; } @@ -866,7 +868,7 @@ impl GenericVector { // Vector's implementation of IndexMut ensures that if `i` and `j` are different // indices then `&mut self[i]` and `&mut self[j]` are non-overlapping. unsafe { - std::ptr::swap(a, b); + core::ptr::swap(a, b); } } } @@ -1007,7 +1009,7 @@ impl GenericVector { Inline(_) => unreachable!("inline vecs should have been promoted"), // If both are single chunks and left has room for right: directly // memcpy right into left - Single(ref mut right) if total_length <= CHUNK_SIZE => { + Single(right) if total_length <= CHUNK_SIZE => { SharedPointer::make_mut(left).append(SharedPointer::make_mut(right)); return; } @@ -1182,7 +1184,7 @@ impl GenericVector { middle_level: tree.middle_level, outer_f: SharedPointer::new(of2), inner_f: replace_shared_pointer(&mut tree.inner_f), - middle: std::mem::take(&mut tree.middle), + middle: core::mem::take(&mut tree.middle), inner_b: replace_shared_pointer(&mut tree.inner_b), outer_b: replace_shared_pointer(&mut tree.outer_b), }; @@ -1202,7 +1204,7 @@ impl GenericVector { middle_level: tree.middle_level, outer_f: SharedPointer::new(if2), inner_f: SharedPointer::default(), - middle: std::mem::take(&mut tree.middle), + middle: core::mem::take(&mut tree.middle), inner_b: replace_shared_pointer(&mut tree.inner_b), outer_b: replace_shared_pointer(&mut tree.outer_b), }; @@ -1743,7 +1745,7 @@ impl RRB { fn replace_shared_pointer( dest: &mut SharedPointer, ) -> SharedPointer { - std::mem::take(dest) + core::mem::take(dest) } // Core traits @@ -1959,22 +1961,22 @@ impl From<&[A]> for GenericVector { } impl From> for GenericVector { - /// Create a vector from a [`std::vec::Vec`][vec]. + /// Create a vector from a [`alloc::vec::Vec`][vec]. /// /// Time: O(n) /// - /// [vec]: https://doc.rust-lang.org/std/vec/struct.Vec.html + /// [vec]: https://doc.rust-lang.org/alloc/vec/struct.Vec.html fn from(vec: Vec) -> Self { vec.into_iter().collect() } } impl From<&Vec> for GenericVector { - /// Create a vector from a [`std::vec::Vec`][vec]. + /// Create a vector from a [`alloc::vec::Vec`][vec]. /// /// Time: O(n) /// - /// [vec]: https://doc.rust-lang.org/std/vec/struct.Vec.html + /// [vec]: https://doc.rust-lang.org/alloc/vec/struct.Vec.html fn from(vec: &Vec) -> Self { vec.iter().cloned().collect() } @@ -2633,13 +2635,13 @@ mod test { #[test] fn issue_131() { - let smol = std::iter::repeat_n(42, 64).collect::>(); + let smol = core::iter::repeat_n(42, 64).collect::>(); let mut smol2 = smol.clone(); assert!(smol.ptr_eq(&smol2)); smol2.set(63, 420); assert!(!smol.ptr_eq(&smol2)); - let huge = std::iter::repeat_n(42, 65).collect::>(); + let huge = core::iter::repeat_n(42, 65).collect::>(); let mut huge2 = huge.clone(); assert!(huge.ptr_eq(&huge2)); huge2.set(63, 420); @@ -2650,7 +2652,7 @@ mod test { fn ptr_eq() { const MAX: usize = if cfg!(miri) { 64 } else { 256 }; for len in 32..MAX { - let input = std::iter::repeat_n(42, len).collect::>(); + let input = core::iter::repeat_n(42, len).collect::>(); let mut inp2 = input.clone(); assert!(input.ptr_eq(&inp2)); inp2.set(len - 1, 98);