mirror of https://github.com/xacrimon/dashmap
Added no_std support
This commit is contained in:
parent
db0ea63343
commit
a01b693478
|
@ -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
|
||||
|
|
16
src/iter.rs
16
src/iter.rs
|
@ -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.
|
||||
///
|
||||
|
|
39
src/lib.rs
39
src/lib.rs
|
@ -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 {
|
||||
|
|
|
@ -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>),
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
4
src/t.rs
4
src/t.rs
|
@ -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> {
|
||||
|
|
42
src/util.rs
42
src/util.rs
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue