Added no_std support

This commit is contained in:
Chase Wilson 2020-03-26 10:26:29 -05:00
parent db0ea63343
commit a01b693478
8 changed files with 100 additions and 29 deletions

View File

@ -13,7 +13,9 @@ keywords = ["atomic", "concurrent", "hashmap"]
categories = ["concurrency", "algorithms", "data-structures"]
[features]
default = []
raw-api = []
no_std = ["hashbrown"]
[dev-dependencies]
criterion = "0.3.0"
@ -44,6 +46,7 @@ num_cpus = "1.11.1"
ahash = "0.3.1"
serde = { version = "1.0.104", optional = true, features = ["derive"] }
cfg-if = "0.1.10"
hashbrown = { version = "0.7.1", optional = true }
[package.metadata.docs.rs]
all-features = true

View File

@ -4,10 +4,18 @@ use crate::lock::{RwLockReadGuard, RwLockWriteGuard};
use crate::t::Map;
use crate::util::SharedValue;
use crate::{DashMap, HashMap};
use std::collections::hash_map;
use std::hash::{BuildHasher, Hash};
use std::mem;
use std::sync::Arc;
use core::hash::{BuildHasher, Hash};
use core::mem;
cfg_if::cfg_if! {
if #[cfg(feature = "no_std")] {
use alloc::sync::Arc;
use hashbrown::hash_map;
} else {
use std::sync::Arc;
use std::collections::hash_map;
}
}
/// Iterator over a DashMap yielding key value pairs.
///

View File

@ -1,3 +1,4 @@
#![cfg_attr(all(feature = "no_std", not(test)), no_std)] // Note: Concurrency tests require std for threading/channels
#![allow(clippy::type_complexity)]
pub mod iter;
@ -11,17 +12,17 @@ mod serde;
use ahash::RandomState;
use cfg_if::cfg_if;
use core::borrow::Borrow;
use core::fmt;
use core::hash::{BuildHasher, Hash, Hasher};
use core::iter::FromIterator;
use core::ops::{BitAnd, BitOr, Shl, Shr, Sub};
use iter::{Iter, IterMut, OwningIter};
use lock::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use mapref::entry::{Entry, OccupiedEntry, VacantEntry};
use mapref::multiple::RefMulti;
use mapref::one::{Ref, RefMut};
use std::borrow::Borrow;
use std::fmt;
use std::hash::Hasher;
use std::hash::{BuildHasher, Hash};
use std::iter::FromIterator;
use std::ops::{BitAnd, BitOr, Shl, Shr, Sub};
pub use t::Map;
cfg_if! {
@ -32,7 +33,17 @@ cfg_if! {
}
}
type HashMap<K, V, S> = std::collections::HashMap<K, SharedValue<V>, S>;
cfg_if! {
if #[cfg(feature = "no_std")] {
extern crate alloc;
use alloc::{vec::Vec, boxed::Box};
type HashMap<K, V, S> = hashbrown::HashMap<K, SharedValue<V>, S>;
} else {
type HashMap<K, V, S> = std::collections::HashMap<K, SharedValue<V>, S>;
}
}
#[inline]
fn shard_amount() -> usize {
@ -249,12 +260,12 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
/// ```
#[inline]
pub fn determine_shard(&self, hash: usize) -> usize {
(hash >> self.shift)
hash >> self.shift
}
} else {
#[inline]
fn determine_shard(&self, hash: usize) -> usize {
(hash >> self.shift)
hash >> self.shift
}
}
}
@ -843,6 +854,15 @@ impl<K: Eq + Hash, V> FromIterator<(K, V)> for DashMap<K, V, RandomState> {
mod tests {
use crate::DashMap;
cfg_if::cfg_if! {
if #[cfg(feature = "no_std")] {
use alloc::string::String;
use ahash::RandomState;
} else {
use std::collections::hash_map::RandomState;
}
}
#[test]
fn test_basic() {
let dm = DashMap::new();
@ -894,7 +914,6 @@ mod tests {
#[test]
fn test_different_hashers_randomstate() {
use std::collections::hash_map::RandomState;
let dm_hm_default: DashMap<u32, u32, RandomState> =
DashMap::with_hasher(RandomState::new());
for i in 0..10 {

View File

@ -4,9 +4,9 @@ use crate::util;
use crate::util::SharedValue;
use crate::HashMap;
use ahash::RandomState;
use std::hash::{BuildHasher, Hash};
use std::mem;
use std::ptr;
use core::hash::{BuildHasher, Hash};
use core::mem;
use core::ptr;
pub enum Entry<'a, K, V, S = RandomState> {
Occupied(OccupiedEntry<'a, K, V, S>),

View File

@ -1,10 +1,17 @@
use crate::lock::{RwLockReadGuard, RwLockWriteGuard};
use crate::HashMap;
use ahash::RandomState;
use std::hash::BuildHasher;
use std::hash::Hash;
use std::ops::{Deref, DerefMut};
use std::sync::Arc;
use core::hash::BuildHasher;
use core::hash::Hash;
use core::ops::{Deref, DerefMut};
cfg_if::cfg_if! {
if #[cfg(feature = "no_std")] {
use alloc::sync::Arc;
} else {
use std::sync::Arc;
}
}
// -- Shared

View File

@ -1,8 +1,8 @@
use crate::lock::{RwLockReadGuard, RwLockWriteGuard};
use crate::HashMap;
use ahash::RandomState;
use std::hash::{BuildHasher, Hash};
use std::ops::{Deref, DerefMut};
use core::hash::{BuildHasher, Hash};
use core::ops::{Deref, DerefMut};
// -- Shared

View File

@ -5,8 +5,8 @@ use crate::lock::{RwLockReadGuard, RwLockWriteGuard};
use crate::mapref::entry::Entry;
use crate::mapref::one::{Ref, RefMut};
use crate::HashMap;
use std::borrow::Borrow;
use std::hash::{BuildHasher, Hash};
use core::borrow::Borrow;
use core::hash::{BuildHasher, Hash};
/// Implementation detail that is exposed due to generic constraints in public types.
pub trait Map<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + Clone + BuildHasher> {

View File

@ -1,8 +1,8 @@
//! This module is full of hackery and dark magic.
//! Either spend a day fixing it and quietly submit a PR or don't mention it to anybody.
use std::cell::UnsafeCell;
use std::{mem, ptr};
use core::cell::UnsafeCell;
use core::{mem, ptr};
#[inline(always)]
pub const fn ptr_size_bits() -> usize {
@ -104,8 +104,42 @@ struct AbortOnPanic;
impl Drop for AbortOnPanic {
#[inline]
fn drop(&mut self) {
if std::thread::panicking() {
std::process::abort()
cfg_if::cfg_if! {
if #[cfg(feature = "no_std")] {
// Note: This is hard, as core/no_std has no concept of threads or knowledge of panicking.
// An alternative would be to do this:
//
// ```rust
// // Elsewhere in the library/host binary
// use core::sync::atomic::{AtomicBool, Ordering};
//
// static UNWINDING: AtomicBool = AtomicBool::new(false);
//
// #[panic_handler]
// fn panic(info: &PanicInfo) -> ! {
// UNWINDING.store(true, Ordering::Relaxed);
//
// unsafe {
// core::intrinsics::abort();
// }
// }
//
// // In AbortOnPanic::drop
// if UNWINDING.load(Ordering::Relaxed) {
// unsafe {
// core::intrinsics::abort();
// }
// }
// ```
//
// Now, this isn't an ideal solution for multiple reasons, as it uses intrinsics which require a feature
// and can be overwritten by the user without them even knowing. That being said, *most* users of no_std
// do tend to use panic = "abort", which solves this problem for us by aborting on panics.
} else {
if std::thread::panicking() {
std::process::abort()
}
}
}
}
}