Struct MbarcMap

Source
pub struct MbarcMap<T: Hash + Eq, U> { /* private fields */ }
Expand description

The heart of this crate, a map which is safe to use in threading contexts without wrapping in a Mutex.

This map does not hold any locks beyond the duration of its member functions, it is completely safe to hold the results of get indefinitely, regardless of what happens in other threads, and this map will not cause deadlocks This means it is safe to:

  • Hold multiple DataReferences to the same value across multiple threads
  • Remove elements while a DataReference to that value is held elsewhere
  • Drop the Map itself while DataReferences exist elsewhere
  • Iterate over elements in one thread without taking a lock to the map (iterators hold a reference to each element at time of creation)

Additionally:

  • Values are stored in mostly-continuous blocks of memory, and they remain in a fixed address until dropped, making it safe to take references/pointers.
  • Values are implicitly wrapped in their own Mutex, requiring only that locks are taken on a per-element basis for data access
  • Values are only dropped when all DataReferences to them have been dropped

This map is not quite a true HashMap, implementing many non-constant (though still sub-linear) operations for managing metadata. The theory behind this approach, however, is that by keeping mutex lock duration to a minimum and everything else “fast enough”, any potential performance losses elsewhere should be more than made up accounted for in practice by allowing more saturated thread usage.

Implementations§

Source§

impl<T: Hash + Eq, U> MbarcMap<T, U>

Source

pub fn new() -> Self

Create a new, empty MbarcMap

§Example
use std::sync::Arc;
use mbarc_map::MbarcMap;

let concurrent_map = Arc::new(MbarcMap::<u64,String>::new());
Source

pub fn insert(&self, key: T, value: U) -> Option<DataReference<U>>

Inserts a key-value pair into the map.

The return of this function is identical to the insert function of the underlying map type used internally to store references. Currently, this is std::collections::HashMap

Source

pub fn contains(&self, key: &T) -> bool

Returns true if the map contains a value for the specified key.

Note that, in threaded contexts, this is only correct at the moment this function is called. It is possible that another thread could add or remove the requested key before you are able to use the return value.

If you intend to use the pattern “if contains then get”, then using get alone is sufficient

Source

pub fn get(&self, key: &T) -> Option<DataReference<U>>

Returns a DataReference to the value corresponding to the key. If the key is not present, None will be returned

Note that, in threaded contexts, it is possible for another thread to potentially remove the value you get before you can use it. In cases like this, the value referenced by the returned DataReference will not be dropped until all remaining DataReference have been dropped

Source

pub fn remove(&self, key: &T) -> Option<DataReference<U>>

Returns a DataReference to the value corresponding to the key and removes the key/value from this map. If the key is not present, None will be returned

The value referenced by the returned DataReference will not be dropped until all remaining DataReference have been dropped

Source

pub fn len(&self) -> usize

Returns the number of elements in the map.

Source

pub fn iter(&self) -> Iter<DataReference<U>>

An iterator visiting all values in arbitrary order

Important concurrency note: This iterator will represent the state of the map at creation time. Adding or removing elements during iteration (in this thread or others) will not have any impact on iteration order, and creation of this iterator has a cost.

Source

pub fn iter_exclusive(&self) -> LockedContainer<'_, T, U>

Exclusive lock on the map for iteration. This does not clone any elements, therefore requiring a lock is taken on the map. This returns a LockedContainer, which only provides an iter() function, returning the iterator you want.

Usage: given some my_hash: MbarcMap<T,U>, lock and iterate over it via

for (k,v) in my_hash.iter_exclusive().iter()

Source§

impl<T: Hash + Eq + Clone, U> MbarcMap<T, U>

Source

pub fn iter_cloned_keys(&self) -> Iter<(T, DataReference<U>)>

An iterator visiting all key-value pairs in arbitrary order, only for keys which implement Clone

Comments regarding concurrency and performance are the same as in MbarcMap::iter

Source§

impl<T: Hash + Eq + Copy, U> MbarcMap<T, U>

Source

pub fn iter_copied_keys(&self) -> Iter<(T, DataReference<U>)>

An iterator visiting all key-value pairs in arbitrary order, only for keys which implement Copy

Comments regarding concurrency and performance are the same as in MbarcMap::iter

Trait Implementations§

Source§

impl<T: Hash + Eq, U> Drop for MbarcMap<T, U>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

impl<K, V, const N: usize> From<[(K, V); N]> for MbarcMap<K, V>
where K: Eq + Hash,

Source§

fn from(arr: [(K, V); N]) -> Self

Converts to this type from the input type.
Source§

impl<T: Hash + Eq, U> Send for MbarcMap<T, U>

Source§

impl<T: Hash + Eq, U> Sync for MbarcMap<T, U>

Auto Trait Implementations§

§

impl<T, U> Freeze for MbarcMap<T, U>

§

impl<T, U> RefUnwindSafe for MbarcMap<T, U>

§

impl<T, U> Unpin for MbarcMap<T, U>

§

impl<T, U> UnwindSafe for MbarcMap<T, U>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.