Struct incr::AtomicMap

source ·
pub struct AtomicMap<K: Eq + Hash>(/* private fields */);
Expand description

Like Map, AtomicMap provides simple, fast sequence checking by key, but with the thread-safe backing storage of AtomicIncr.

Tradeoffs

AtomicMap is not a concurrent hashmap. Importantly key insertion is not synchronized. The intended use case is to initialize the map fully on program start, inserting whatever keys will be used throughout its life, and cloning this master instance to be used by any threads tracking sequences by those keys.

A fully synchronized map was not chosen for performance reasons. If keys are not fully known when threads are launched, the best options include:

  • wrap a normal Map in an Arc<Mutex<Map>> or Arc<RwLock<Map>>,
  • utilize a third-party crate providing a concurrent hashmap implementation (with Incr values).

For a given (already inserted) key, any clone()d AtomicMap will use/have a value at that key that is synchronized across threads (the inner value is an Arc<AtomicU64>).

Examples

use incr::AtomicMap;

let mut last: AtomicMap<&'static str> = Default::default();

assert_eq!(last.insert("a", 1), true);
assert_eq!(last.is_new("missing_key", 1), false); // note difference from `Map`
assert_eq!(last.insert("b", 1), true);
assert_eq!(last.is_new("a", 1), false);
assert_eq!(last.is_new("b", 3), true);
assert_eq!(last.is_new_or_insert("c", 1), true);
assert_eq!(last.is_new("c", 1), false);
assert_eq!(last.get("b"), 3);
assert_eq!(last.get("not a key"), 0);

Implementations§

source§

impl<K> AtomicMap<K>where K: Eq + Hash,

source

pub fn is_new<Q>(&self, key: &Q, val: u64) -> boolwhere K: Borrow<Q>, Q: ?Sized + Hash + Eq,

Returns true if key exists and val is greater than the largest previously observed value (for key). Returns false if key does not exist in the inner map. See AtomicMap::check_or_insert for a function that behaves similarly to Map::is_new.

Tradeoffs

This function has a different signature and works differently than Map::is_new.

Specifically, Map::is_new:

  • takes &mut self
  • consumes key
  • inserts val at key if key was not already present in the map.

By contrast, AtomicIncr:

  • takes &self
  • borrows &key
  • does not insert val on a key miss, instead “silently” returning false

This design was chosen for several reasons, including:

  • key insertions are not synchronized across threads. Instead, the map is expected to have been initialized on program start, and a key miss is most likely an error
  • A &self signature provides more flexibility, and is possible, unlike with Map, because the AtomicIncr::is_new function takes &self

The AtomicMap::check_or_insert function provides insert-on-key-miss functionality if desired.

Possibly, it would be less confusing if this function returned Option<bool>, where a key miss would return None. Feedback on this issue would be appreciated.

Examples
use incr::AtomicMap;
let mut last: AtomicMap<&'static str> = Default::default();

assert_eq!(last.is_new("a", 1), false);
assert_eq!(last.contains_key("a"), false);
assert_eq!(last.is_new_or_insert("a", 1), true);
assert_eq!(last.get("a"), 1);
assert_eq!(last.insert("b", 1), true);
assert_eq!(last.is_new("b", 2), true);
assert_eq!(last.is_new("b", 2), false);
source

pub fn is_new_or_insert(&mut self, key: K, val: u64) -> bool

Like is_new, but inserts val at key if the inner map did not previously contain key.

This may be renamed to check_or_insert in the future.

source

pub fn insert(&mut self, key: K, val: u64) -> bool

An alias for, and Works identically to, is_new_or_insert. It’s not possible, using the public api, to decrease the value at a given key, so calling this with a val lower than the current value would simply return false and leave the higher value in the map unchanged.

source

pub fn get<Q>(&self, key: &Q) -> u64where K: Borrow<Q>, Q: ?Sized + Hash + Eq,

Returns the highest observed value at key, or, if key does not exist, returns 0.

source

pub fn contains_key<Q>(&self, key: &Q) -> boolwhere K: Borrow<Q>, Q: ?Sized + Hash + Eq,

source

pub fn len(&self) -> usize

source

pub fn is_empty(&self) -> bool

Trait Implementations§

source§

impl<K: Clone + Eq + Hash> Clone for AtomicMap<K>

source§

fn clone(&self) -> AtomicMap<K>

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<K: Debug + Eq + Hash> Debug for AtomicMap<K>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<K: Default + Eq + Hash> Default for AtomicMap<K>

source§

fn default() -> AtomicMap<K>

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl<K> RefUnwindSafe for AtomicMap<K>where K: RefUnwindSafe,

§

impl<K> Send for AtomicMap<K>where K: Send,

§

impl<K> Sync for AtomicMap<K>where K: Sync,

§

impl<K> Unpin for AtomicMap<K>where K: Unpin,

§

impl<K> UnwindSafe for AtomicMap<K>where K: UnwindSafe,

Blanket Implementations§

source§

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

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

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

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere 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 Twhere 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> ToOwned for Twhere T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

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

§

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 Twhere U: TryFrom<T>,

§

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.