use crossbeam_epoch::{Guard, Shared};
use std::borrow::Borrow;
use std::collections::hash_map::RandomState;
use std::fmt;
use std::hash::{BuildHasher, Hash, Hasher};
use std::num::Wrapping;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::Duration;
use atomic::{AtomicBox, AtomicPtr, MaybeNull, NotNull, NotNullOwned};
#[derive(Debug)]
pub enum KeySlot<K> {
Key(K),
SeeNewTable,
}
#[derive(Debug, PartialEq)]
pub enum ValueSlot<'v, V: 'v> {
Value(V),
Tombstone,
ValuePrime(&'v ValueSlot<'v, V>),
SeeNewTable,
}
impl<'v, V> ValueSlot<'v, V> {
pub fn is_tombstone(&self) -> bool {
match self {
&ValueSlot::Tombstone => true,
_ => false,
}
}
pub fn is_valueprime(&self) -> bool {
match self {
&ValueSlot::ValuePrime(_) => true,
_ => false,
}
}
pub fn is_value(&self) -> bool {
match self {
&ValueSlot::Value(_) => true,
_ => false,
}
}
pub fn is_tombprime(&self) -> bool {
match self {
&ValueSlot::SeeNewTable => true,
_ => false,
}
}
pub fn is_prime(&self) -> bool {
match self {
&ValueSlot::SeeNewTable | &ValueSlot::ValuePrime(_) => true,
_ => false,
}
}
pub fn as_inner(value: Option<&Self>) -> Option<&V> {
match value {
Some(&ValueSlot::Value(ref v)) => Some(&v),
Some(&ValueSlot::ValuePrime(v)) => ValueSlot::as_inner(Some(v)),
_ => None,
}
}
}
#[derive(Debug)]
pub enum Match {
Empty,
AnyKeyValuePair,
Always,
}
pub enum KeyCompare<'k, 'q, K: 'k + Borrow<Q>, Q: 'q + ?Sized> {
Owned(NotNullOwned<K>),
Shared(NotNull<'k, KeySlot<K>>),
OnlyCompare(&'q Q),
}
impl<'k, 'q, K: Borrow<Q>, Q: ?Sized> KeyCompare<'k, 'q, K, Q> {
pub fn new(key: K) -> Self {
KeyCompare::Owned(NotNullOwned::new(key))
}
fn as_qref(&self) -> QRef<K, Q> {
match self {
&KeyCompare::Owned(ref owned) => QRef::Owned(owned),
&KeyCompare::Shared(ref not_null) => QRef::Shared(not_null),
&KeyCompare::OnlyCompare(q) => QRef::Borrow(q),
}
}
}
enum QRef<'k, 'q, K: 'k + Borrow<Q>, Q: 'q + ?Sized> {
Owned(&'k NotNullOwned<K>),
Shared(&'k KeySlot<K>),
Borrow(&'q Q),
}
impl<'k, 'q, K: Borrow<Q>, Q: ?Sized> QRef<'k, 'q, K, Q> {
fn as_qref2(&self) -> QRef2<K, Q> {
match self {
&QRef::Owned(not_null) => QRef2::Shared(&**not_null),
&QRef::Shared(&KeySlot::Key(ref k)) => QRef2::Shared(k),
&QRef::Shared(&KeySlot::SeeNewTable) =>
unreachable!("KeyCompare must contain a `NotNull(KeySlot::Key(K))`"),
&QRef::Borrow(q) => QRef2::Borrow(q),
}
}
}
enum QRef2<'k, 'q, K: 'k + Borrow<Q>, Q: 'q + ?Sized> {
Shared(&'k K),
Borrow(&'q Q),
}
impl<'k, 'q, K: Borrow<Q>, Q: ?Sized> QRef2<'k, 'q, K, Q> {
fn as_q(&self) -> &Q {
match self {
&QRef2::Shared(k) => k.borrow(),
&QRef2::Borrow(q) => q,
}
}
}
#[derive(Debug)]
pub enum PutValue<'v, V: 'v> {
Owned(NotNullOwned<ValueSlot<'v, V>>),
Shared(NotNull<'v, ValueSlot<'v, V>>),
}
impl<'v, V: PartialEq> PutValue<'v, V> {
pub fn new(value: V) -> Self {
PutValue::Owned(NotNullOwned::new(ValueSlot::Value(value)))
}
pub fn new_tombstone() -> Self {
PutValue::Owned(NotNullOwned::new(ValueSlot::Tombstone))
}
pub fn is_tombstone(&self) -> bool {
match self {
&PutValue::Owned(ref owned) => if let ValueSlot::Tombstone = **owned {
true
} else {
false
},
&PutValue::Shared(ref not_null) => {
if let &ValueSlot::Tombstone = &**not_null {
true
} else {
false
}
},
}
}
pub fn ptr_equals(&self, value: NotNull<ValueSlot<V>>) -> bool {
if (&*value as *const _) == self.as_raw() {
true
} else {
false
}
}
pub fn as_raw(&self) -> *const ValueSlot<'v, V> {
match self {
&PutValue::Owned(ref not_null) => &**not_null as *const _,
&PutValue::Shared(ref not_null) => &**not_null as *const _,
}
}
}
pub type KVPair<'v, K, V> = (AtomicPtr<KeySlot<K>>, AtomicPtr<ValueSlot<'v, V>>);
pub struct MapInner<'v, K, V: 'v, S = RandomState> {
map: Vec<KVPair<'v,K,V>>,
size: AtomicUsize,
newer_map: AtomicPtr<MapInner<'v,K,V,S>>,
resizers_count: AtomicUsize,
chunks_copied: AtomicUsize,
hash_builder: S,
}
impl<'v, K, V, S> MapInner<'v, K, V, S> {
pub const DEFAULT_CAPACITY: usize = ::LockFreeHashMap::<K, V, S>::DEFAULT_CAPACITY;
pub unsafe fn drop_newer_maps(&self, guard: &Guard) {
if let Some(newer_map) = self.newer_map.take(guard) {
newer_map.drop_self_and_newer_maps(guard);
}
}
pub unsafe fn drop_self_and_newer_maps(self, guard: &Guard) {
let newer_map = self.newer_map.take(guard);
drop(self);
if let Some(newer_map) = newer_map {
newer_map.drop_self_and_newer_maps(guard);
}
}
}
impl<'v, K: Hash + Eq, V: PartialEq> MapInner<'v,K,V,RandomState> {
pub fn with_capacity(size: usize) -> Self {
MapInner::with_capacity_and_hasher(size, RandomState::new())
}
}
impl<'guard, 'v: 'guard, K, V, S> MapInner<'v, K,V,S>
where K: Hash + Eq,
V: PartialEq,
S: BuildHasher + Clone,
{
pub fn with_capacity_and_hasher(size: usize, hasher: S) -> Self {
let size = usize::checked_next_power_of_two(size).unwrap_or(Self::DEFAULT_CAPACITY);
let mut map = Vec::with_capacity(size);
for _ in 0..size {
map.push((AtomicPtr::new(None), AtomicPtr::new(None)));
}
MapInner {
map: map,
size: AtomicUsize::new(0),
newer_map: AtomicPtr::new(None),
resizers_count: AtomicUsize::new(0),
chunks_copied: AtomicUsize::new(0),
hash_builder: hasher,
}
}
pub fn help_copy(
&self,
newer_map: NotNull<Self>,
copy_everything: bool,
outer_map: &AtomicBox<Self>,
guard: &'guard Guard,
) {
fn checked_times(first: usize, second: usize, upper_bound: usize) -> usize {
let result = first * second;
if first != 0 && result/first != second {
upper_bound
} else if result > upper_bound {
upper_bound
} else {
result
}
}
loop {
let chunks_copied = self.chunks_copied.fetch_add(1, Ordering::SeqCst);
let next_chunk = chunks_copied + 1;
let lower_bound = checked_times(chunks_copied, ::COPY_CHUNK_SIZE, self.capacity());
let upper_bound = checked_times(next_chunk, ::COPY_CHUNK_SIZE, self.capacity());
debug_assert!(lower_bound <= upper_bound);
if lower_bound >= upper_bound {
self.chunks_copied.fetch_sub(1, Ordering::SeqCst);
self.promote(newer_map, outer_map, guard);
return;
}
for i in lower_bound..upper_bound {
self.copy_slot(&*newer_map, i, outer_map, guard);
}
if upper_bound == self.capacity() {
self.promote(newer_map, outer_map, guard);
return;
} else if !copy_everything {
return
}
}
}
pub fn promote(
&self,
new_map: NotNull<Self>,
outer_map: &AtomicBox<Self>,
guard: &'guard Guard,
) -> bool
{
let current_map_shared: NotNull<_> = outer_map.load(guard);
let current_map: &MapInner<_,_,_> = &*current_map_shared;
if current_map as *const _ != self as *const _ {
return false;
}
match outer_map.compare_and_set_shared(current_map_shared, new_map, guard) {
Ok(_) => {
unsafe { guard.defer(move || current_map_shared.as_shared().into_owned()); }
return true;
},
Err((_current, _)) => {
debug_assert!(&*_current as *const _ != self as *const _);
return false;
},
}
}
fn ensure_slot_copied(
&self,
copy_index: usize,
outer_map: &AtomicBox<Self>,
guard: &'guard Guard,
) -> NotNull<'guard, Self> {
let newer_map_shared = self.newer_map.load(&guard);
if let Some(new_map) = newer_map_shared.as_option() {
self.copy_slot(&*new_map, copy_index, outer_map, guard);
self.help_copy(new_map, false, outer_map, guard);
new_map
} else {
unreachable!("can't call ensure_slot_copied() unless found a prime value");
}
}
pub fn copy_slot(
&self,
new_map: &Self,
old_map_index: usize,
outer_map: &AtomicBox<Self>,
guard: &'guard Guard
) {
fn cheat_lifetime<'guard, 'v, V>(maybe: MaybeNull<'guard, V>) -> MaybeNull<'v, V> {
MaybeNull::from_shared(Shared::from(maybe.as_shared().as_raw()))
}
let (ref atomic_key_slot, ref atomic_value_slot) = self.map[old_map_index];
let old_key: NotNull<_>;
let mut new_key = NotNullOwned::new(KeySlot::SeeNewTable);
loop {
let cas_key_result = atomic_key_slot.compare_and_set_owned_weak(
MaybeNull::from_shared(Shared::null()), new_key, guard);
match cas_key_result {
Ok(_new_key) => {
debug_assert!(if let &KeySlot::SeeNewTable = &*_new_key {true} else {false});
return;
},
Err((current, new)) => {
new_key = new; let _old_key_shared = current;
match current.as_option() {
None => continue,
Some(k) => {
match k.deref() {
&KeySlot::SeeNewTable => return,
&KeySlot::Key(_) => {
debug_assert!(current.as_option().is_some());
old_key = k;
break;
},
}
}
}
},
}
}
let mut old_value: MaybeNull<_> = cheat_lifetime(atomic_value_slot.load(guard));
let not_null_old_value: NotNull<_>;
let primed_old_value: NotNull<ValueSlot<_>>;
let mut original_valueslot_value = None;
loop {
match old_value.as_option() {
None => {
match atomic_value_slot.compare_and_set_owned(
MaybeNull::from_shared(Shared::null()),
NotNullOwned::new(ValueSlot::SeeNewTable),
guard,
) {
Err((current, _)) => {
debug_assert!(current.as_option().is_some());
old_value = cheat_lifetime(current);
continue;
},
Ok(current) => {
debug_assert!(current.deref().is_tombprime());
return;
},
}
},
Some(not_null) => match not_null.deref() {
&ValueSlot::SeeNewTable => return,
&ValueSlot::Tombstone => {
match atomic_value_slot.compare_and_set_owned(
old_value,
NotNullOwned::new(ValueSlot::SeeNewTable),
guard,
) {
Err((current, _)) => {
debug_assert!(current.as_option().is_some());
old_value = cheat_lifetime(current);
continue;
},
Ok(_new) => {
debug_assert!(_new.is_tombprime());
unsafe { guard.defer(move || not_null.drop()); }
return;
}
}
},
&ValueSlot::Value(_) => {
let primed_old_value_owned = NotNullOwned::new(ValueSlot::ValuePrime(not_null.deref()));
match atomic_value_slot.compare_and_set_owned(
old_value, primed_old_value_owned,
guard
) {
Err((current, _dropped_because_owned)) => {
debug_assert!(current.as_option().is_some());
old_value = cheat_lifetime(current);
continue;
},
Ok(shared_primed_value) => {
original_valueslot_value = Some(not_null);
debug_assert!(shared_primed_value.is_valueprime());
not_null_old_value = not_null;
primed_old_value = shared_primed_value;
break;
},
}
}
&ValueSlot::ValuePrime(_) => {
not_null_old_value = not_null;
primed_old_value = not_null;
break;
}
}
}
}
debug_assert!(not_null_old_value.is_value() || not_null_old_value.is_valueprime());
debug_assert!(primed_old_value.is_valueprime());
let put_value = match not_null_old_value.deref() {
&ValueSlot::Value(_) => PutValue::Shared(not_null_old_value),
&ValueSlot::ValuePrime(v) => match v {
&ValueSlot::Value(_) =>
PutValue::Shared(MaybeNull::from_shared(Shared::from(v as *const _))
.as_option().expect("v is a reference and can't be null")
),
_ => unreachable!("`ValuePrime` can only be a reference to a `Value`"),
}
&ValueSlot::Tombstone => unreachable!(),
&ValueSlot::SeeNewTable => unreachable!(),
};
let copied_into_new = new_map.put_if_match(
KeyCompare::Shared(old_key),
put_value,
Match::Empty,
outer_map,
guard
).is_none();
if copied_into_new {
debug_assert!(!atomic_key_slot.is_tagged(guard));
debug_assert!(!atomic_value_slot.is_tagged(guard));
atomic_key_slot.tag(guard);
atomic_value_slot.tag(guard);
debug_assert!(atomic_key_slot.is_tagged(guard));
debug_assert!(atomic_value_slot.is_tagged(guard));
}
let mut primed_old_value_maybe: MaybeNull<_> = primed_old_value.as_maybe_null();
loop {
match atomic_value_slot.compare_and_set_owned_weak(
primed_old_value_maybe, NotNullOwned::new(ValueSlot::SeeNewTable), guard
) {
Ok(_current) => {
debug_assert!(_current.is_tombprime());
unsafe { primed_old_value_maybe.try_defer_drop(guard); }
break;
},
Err((current, _)) => {
debug_assert!(current.as_option()
.map(|v| v.is_tombprime() || v.is_valueprime())
.expect("can't be null again")
);
primed_old_value_maybe = current;
},
}
}
if let Some(original_value) = original_valueslot_value {
unsafe { guard.defer(move || {
if atomic_value_slot.is_tagged(guard) {
original_value.drop();
}
})}
}
return;
}
pub fn create_newer_map(&self, guard: &'guard Guard) -> NotNull<'guard, Self>
{
fn try_double(current_size: usize) -> usize {
let doubled_size = current_size << 1;
if doubled_size < current_size {
current_size
} else {
doubled_size
}
}
let newer_map: MaybeNull<Self> = self.newer_map.load(guard);
if let Some(not_null) = newer_map.as_option() {
return not_null;
}
let size = self.capacity();
let mut new_size = size;
if size > (self.capacity() >> 2) {
new_size = try_double(new_size);
if size > (self.capacity() >> 1) {
new_size = try_double(new_size);
}
}
let array_element_byte_size: usize = ::std::mem::size_of::<KVPair<K,V>>();
let Wrapping(size_in_megabytes)
= (Wrapping(array_element_byte_size) * Wrapping(size)) >> (2^10 * 2^10);
let current_resizers = self.resizers_count.fetch_add(1, Ordering::SeqCst);
if current_resizers >= 2 && size_in_megabytes > 0 {
let newer_map: MaybeNull<Self> = self.newer_map.load(guard);
if let Some(not_null) = newer_map.as_option() {
return not_null;
}
::std::thread::sleep(Duration::from_millis(size_in_megabytes as u64));
}
let newer_map: MaybeNull<Self> = self.newer_map.load(guard);
if let Some(not_null) = newer_map.as_option() {
return not_null;
}
debug_assert!(new_size >= self.capacity());
match self.newer_map.compare_null_and_set_owned(
NotNullOwned::new(Self::with_capacity_and_hasher(new_size, self.hash_builder.clone())),
guard
) {
Ok(shared_newer_map) => {
shared_newer_map
},
Err((current, _drop_our_map)) => {
debug_assert!((&*current as *const _) != (self as *const _));
current
},
}
}
pub fn hash_key<Q: ?Sized>(&self, key: &Q) -> usize
where K: Borrow<Q>,
Q: Hash + Eq,
{
let mut hasher = self.hash_builder.build_hasher();
key.hash(&mut hasher);
let hash = hasher.finish() as usize;
hash & (self.capacity() - 1)
}
pub fn keys_are_equal<T1: ?Sized, T2: ?Sized>(&self, first: &T1, second: &T2) -> bool
where T2: PartialEq<T1>,
{
second == first
}
pub fn capacity(&self) -> usize {
self.map.capacity()
}
pub fn len(&self) -> usize {
self.size.load(Ordering::SeqCst)
}
pub fn get<Q: ?Sized>(
&self,
key: &Q,
outer_map: &AtomicBox<Self>,
guard: &'guard Guard
) -> Option<&'guard V>
where K: Borrow<Q>,
Q: Hash + Eq + PartialEq<K>,
{
let initial_index = self.hash_key(key);
let len = self.capacity();
for index in (initial_index..len).chain(0..initial_index) {
let (ref atomic_key_slot, ref atomic_value_slot) = self.map[index];
match &*atomic_key_slot.load(&guard).as_option()? {
&KeySlot::Key(ref k) => if self.keys_are_equal(k, key) {
match atomic_value_slot.load(&guard).as_option()?.deref() {
&ValueSlot::Value(ref v) => return Some(&v),
&ValueSlot::Tombstone => return None,
&ValueSlot::ValuePrime(_) | &ValueSlot::SeeNewTable => {
return self.ensure_slot_copied(index, outer_map, guard)
.get(key, outer_map, guard)
}
}
} else {
continue
},
&KeySlot::SeeNewTable => {
return self.newer_map.load(&guard)
.as_option()
.expect("Can't set `KeySlot` to `SeeNewTable` before setting `newer_map`")
.get(key, outer_map, guard);
},
}
}
return None;
}
pub fn update_size_and_defer(
&'guard self,
old_value_slot: MaybeNull<'guard, ValueSlot<V>>,
insert_tombstone: bool,
guard: &'guard Guard,
) -> Option<&'guard ValueSlot<V>>
{
let increment = if !insert_tombstone {
match old_value_slot.as_option() {
None => true,
Some(ref old_value) if old_value.is_tombstone() => true,
Some(ref old_value) if old_value.is_tombprime() => unreachable!(),
Some(ref old_value) if old_value.is_valueprime() => unreachable!(),
Some(_) => false,
}
} else {
false
};
if increment {
self.size.fetch_add(1, Ordering::SeqCst);
}
let decrement = if insert_tombstone {
match old_value_slot.as_option() {
None => false,
Some(ref old_value) if old_value.is_tombstone() => false,
Some(ref old_value) if old_value.is_tombprime() => unreachable!(),
Some(ref old_value) if old_value.is_valueprime() => unreachable!(),
Some(_) => true,
}
} else {
false
};
if decrement {
self.size.fetch_sub(1, Ordering::SeqCst);
}
match old_value_slot.as_option() {
None => None,
Some(value) => {
unsafe { guard.defer(move || { value.drop(); })}
Some(value.deref())
}
}
}
pub fn put_if_match<Q>(
&'guard self,
key: KeyCompare<K, Q>,
mut put: PutValue<'v, V>,
matcher: Match,
outer_map: &AtomicBox<Self>,
guard: &'guard Guard
) -> Option<&'guard ValueSlot<V>>
where K: Borrow<Q>,
Q: Hash + Eq + PartialEq<K> + ?Sized,
{
fn cheat_lifetime<'guard, 'v, V>(maybe: NotNull<'guard, V>) -> NotNull<'v, V> {
MaybeNull::from_shared(Shared::from(maybe.as_shared().as_raw()))
.as_option()
.expect("parameter was `NotNull` to begin with")
}
let initial_index = self.hash_key(key.as_qref().as_qref2().as_q());
let len = self.capacity();
let mut key_index = None;
let mut key = key;
'find_key_loop:
for index in (initial_index..len).chain(0..initial_index) {
let atomic_key_slot: &AtomicPtr<KeySlot<K>> = &self.map[index].0;
let option_key: Option<_> = atomic_key_slot.load(&guard)
.as_option();
let current_key: NotNull<KeySlot<K>> = match option_key {
Some(existing_key) => existing_key,
None => if put.is_tombstone() {
return None;
} else if let Match::AnyKeyValuePair = matcher {
return None;
} else {
match key {
KeyCompare::Owned(owned) => {
let insert_key = NotNullOwned::new(KeySlot::Key(*owned.into_owned().into_box()));
match atomic_key_slot.compare_null_and_set_owned(insert_key, guard) {
Ok(shared_key) => {
key = KeyCompare::Shared(shared_key);
key_index = Some(index);
break 'find_key_loop;
},
Err((not_null, _return)) => {
let _return = match *_return.into_owned().into_box() {
KeySlot::Key(owned) => owned,
KeySlot::SeeNewTable => unreachable!(),
};
key = KeyCompare::Owned(NotNullOwned::new(_return));
not_null
},
}
},
KeyCompare::Shared(not_null) => {
match atomic_key_slot.compare_null_and_set(not_null, guard) {
Ok(shared_key) => {
key = KeyCompare::Shared(shared_key);
key_index = Some(index);
break 'find_key_loop;
},
Err((not_null, _return)) => {
key = KeyCompare::Shared(_return);
not_null
}
}
},
KeyCompare::OnlyCompare(_) => {
return None;
}
}
},
};
match &*current_key {
&KeySlot::Key(ref current_key) => if self.keys_are_equal(key.as_qref().as_qref2().as_q(), current_key.borrow()) {
key_index = Some(index);
break 'find_key_loop;
}, &KeySlot::SeeNewTable => {
break 'find_key_loop;
},
}
}
let key_index: usize = match key_index {
Some(k) => k,
None => {
let new_table: NotNull<Self> = self.create_newer_map(guard);
self.help_copy(new_table, true, outer_map, guard);
return new_table.deref().put_if_match(key, put, matcher, outer_map, guard);
},
};
let atomic_value_slot = &self.map[key_index].1;
let mut old_value_slot: MaybeNull<_> = atomic_value_slot.load(&guard);
let insert_tombstone = put.is_tombstone();
loop {
let value_slot_option = old_value_slot.as_option();
if let Some(v) = value_slot_option {
if put.ptr_equals(v) {
return Some(v.deref());
}
}
match matcher {
Match::Empty => if let Some(v) = value_slot_option {
return Some(v.deref())
},
Match::AnyKeyValuePair => match value_slot_option.map(|v| v.deref()) {
Some(&ValueSlot::Tombstone) | None => return None,
_ => (),
}
Match::Always => (),
}
if value_slot_option.map_or(false, |v| v.is_prime()) {
let newer_map = self.newer_map
.load(&guard)
.as_option()
.expect("Can't set a `ValueSlot` to `ValuePrime` before setting `newer_map`");
self.copy_slot(&*newer_map, key_index, outer_map, guard);
return newer_map.deref().put_if_match(key, put, matcher, outer_map, guard);
}
if self.newer_map.relaxed_exists(guard) {
return self.ensure_slot_copied(key_index, outer_map, guard)
.deref()
.put_if_match(key, put, matcher, outer_map, guard);
}
debug_assert!(value_slot_option.map_or(true, |v| !v.is_prime()));
match put {
PutValue::Owned(owned) => match atomic_value_slot.compare_and_set_owned(
old_value_slot, owned, &guard
) {
Ok(_) => {
return self.update_size_and_defer(old_value_slot, insert_tombstone, guard);
},
Err((current, _return_ownership)) => {
debug_assert!(current.as_option().is_some());
old_value_slot = current;
put = PutValue::Owned(_return_ownership);
},
},
PutValue::Shared(shared) => match atomic_value_slot.compare_and_set(
old_value_slot, shared, &guard
) {
Ok(_) => {
return self.update_size_and_defer(old_value_slot, insert_tombstone, guard);
},
Err((current, _return_ownership)) => {
debug_assert!(current.as_option().is_some());
old_value_slot = current;
put = PutValue::Shared(cheat_lifetime(_return_ownership));
},
},
}
}
}
}
impl<'v, K, V, S> Drop for MapInner<'v, K, V, S> {
fn drop(&mut self) {
let guard = &::pin();
for (mut k_ptr, mut v_ptr) in self.map.drain(..) {
unsafe {
guard.defer(move || {
if !k_ptr.is_tagged(&guard) {
k_ptr.try_drop(&guard);
}
v_ptr.try_drop(&guard);
})
}
}
}
}
impl<'v, K: fmt::Debug, V: fmt::Debug, S> fmt::Debug for MapInner<'v, K, V, S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let guard = &::pin();
write!(f, "MapInner {{ map: {:?}, size: {:?}, capacity: {}, newer_map: {:?}, resizers: {:?}, chunks_copied: {:?} }}",
self.map.iter()
.map(|&(ref k, ref v)| (k.load(guard).as_option(), v.load(guard).as_option()))
.collect::<Vec<_>>(),
self.size.load(Ordering::SeqCst),
self.map.capacity(),
format!("{:?}", self.newer_map),
self.resizers_count.load(Ordering::SeqCst),
self.chunks_copied.load(Ordering::SeqCst),
)
}
}