Skip to content

Instantly share code, notes, and snippets.

@rajibchy
Last active June 16, 2022 14:34
Show Gist options
  • Select an option

  • Save rajibchy/422226e7bd5fa8f694c2b785fc5f36bd to your computer and use it in GitHub Desktop.

Select an option

Save rajibchy/422226e7bd5fa8f694c2b785fc5f36bd to your computer and use it in GitHub Desktop.
Thread-safe collection of key/value pairs that can be accessed by multiple threads concurrently
/**
* Copyright (c) 2018, Sow ( https://safeonline.world, https://www.facebook.com/safeonlineworld). (https://github.com/RKTUXYN) All rights reserved.
* Copyrights licensed under the New BSD License.
* See the accompanying LICENSE file for terms.
*/
// 5/26/2021 2:05:50 AM
// Rajib Chy
using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.Concurrent;
namespace Sow.Framework {
public class ConcurrentStorage<TKey, TValue> : IConcurrentStorage<TKey, TValue> {
private ConcurrentDictionary<TKey, TValue> _storage;
public int Count => _storage.Count;
public bool IsEmpty => _storage.IsEmpty;
public ConcurrentStorage( ) {
_storage = new ConcurrentDictionary<TKey, TValue>( );
}
private void ThrowIfKeyIsNull( TKey key ) {
if ( key == null ) throw new ArgumentNullException( "Key required in ConcurrentStorage" );
}
public bool TryAdd( TKey key, TValue value ) {
ThrowIfKeyIsNull( key );
if ( _storage.ContainsKey( key ) ) return false;
return _storage.TryAdd( key, value );
}
public bool TryAddOrUpdate( TKey key, TValue value ) {
ThrowIfKeyIsNull( key );
if ( _storage.ContainsKey( key ) ) {
// Thread safe
// see more https://referencesource.microsoft.com/#mscorlib/system/Collections/Concurrent/ConcurrentDictionary.cs,968
_storage[ key ] = value;
return true;
}
return _storage.TryAdd( key, value );
}
public bool TryUpdate( TKey key, TValue value ) {
ThrowIfKeyIsNull( key );
// Thread safe
// see more https://referencesource.microsoft.com/#mscorlib/system/Collections/Concurrent/ConcurrentDictionary.cs,968
_storage[ key ] = value;
return true;
}
public TValue TryGet( TKey key ) {
ThrowIfKeyIsNull( key );
_storage.TryGetValue( key, out TValue result );
return result;
}
/// <summary>
/// Determines whether the <see cref="ConcurrentDictionary{TKey, TValue}"/> contains the specified key.
/// </summary>
/// <param name="key">The key to locate in the <see cref="ConcurrentDictionary{TKey, TValue}"/></param>
/// <returns>true if the <see cref="ConcurrentDictionary{TKey, TValue}"/> contains an element with the specified key; otherwise, false.</returns>
/// <exception cref="T:System.ArgumentNullException">key is null.</exception>
public bool ContainsKey( TKey key ) => _storage.ContainsKey( key );
public bool TryGet( TKey key, out TValue value ) => _storage.TryGetValue( key, out value );
public bool TryRemove( TKey key ) => _storage.TryRemove( key, out _ );
public bool TryRemove( TKey key, out TValue value ) => _storage.TryRemove( key, out value );
/// <summary>
/// Copies the key and value pairs stored in the <see cref="ConcurrentDictionary{TKey,TValue}"/> to a new array.
/// <para>
/// see more <see href="https://referencesource.microsoft.com/#mscorlib/system/Collections/Concurrent/ConcurrentDictionary.cs,691"/>
/// </para>
/// </summary>
/// <returns>A new array containing a snapshot of key and value pairs copied from the <see cref="ConcurrentDictionary{TKey,TValue}"/>.</returns>
public KeyValuePair<TKey, TValue>[] ToArray( ) => _storage.ToArray( );
public List<KeyValuePair<TKey, TValue>> ToList( ) => _storage.ToArray( ).ToList( );
public List<TValue> ToListObject( ) {
List<TValue> dct = new List<TValue>( );
foreach ( KeyValuePair<TKey, TValue> kv in ToArray( ) ) {
dct.Add( kv.Value );
}
return dct;
}
public List<T> ToListObject<T>( Func<TValue, T> selector ) {
List<T> dct = new List<T>( );
foreach ( KeyValuePair<TKey, TValue> kv in ToArray( ) ) {
dct.Add( selector( kv.Value ) );
}
return dct;
}
public List<T> ToCloneObject<T>( Func<TValue, T> clone ) where T : TValue {
List<T> dct = new List<T>( );
foreach ( KeyValuePair<TKey, TValue> kv in ToArray( ) ) {
dct.Add( clone( kv.Value ) );
}
return dct;
}
public List<T> Distinct<T>( Func<TValue, T> comparator ) => ToList( ).Select( a => comparator( a.Value ) ).Distinct( ).ToList( );
public TValue Where( Func<TValue, bool> predicate ) {
TValue result;
lock ( _storage ) {
result = _storage.FirstOrDefault( a => predicate( a.Value ) ).Value;
}
return result;
}
public TValue Where( Func<TKey, bool> predicate ) {
TValue result;
lock ( _storage ) {
result = _storage.FirstOrDefault( a => predicate( a.Key ) ).Value;
}
return result;
}
public IList<TValue> SelectOne( Func<TValue, bool> predicate ) {
IList<TValue> result = new List<TValue>( );
foreach ( KeyValuePair<TKey, TValue> kv in ToArray( ) ) {
if ( !predicate( kv.Value ) ) continue;
result.Add( kv.Value ); break;
}
return result;
}
public IList<TValue> Select( Func<TValue, bool> predicate ) {
IList<TValue> result = new List<TValue>( );
foreach ( KeyValuePair<TKey, TValue> kv in ToArray( ) ) {
if ( !predicate( kv.Value ) ) continue;
result.Add( kv.Value );
}
return result;
}
public IDictionary<TKey, TValue> ToDictionary( ) {
Dictionary<TKey, TValue> dct = new Dictionary<TKey, TValue>( );
foreach ( KeyValuePair<TKey, TValue> kv in ToArray( ) ) {
dct.Add( kv.Key, kv.Value );
}
return dct;
}
public void Each( Action<TValue> predicate ) {
foreach ( KeyValuePair<TKey, TValue> kv in ToArray( ) ) {
predicate( kv.Value );
}
}
public void Each( Action<TKey, TValue> predicate ) {
foreach ( KeyValuePair<TKey, TValue> kv in ToArray( ) ) {
predicate( kv.Key, kv.Value );
}
}
public bool Exists( Func<TValue, bool> predicate ) {
bool result = false;
lock ( _storage ) {
result = _storage.Any( a => predicate( a.Value ) );
}
return result;
}
public bool Exists( Func<TKey, bool> predicate ) {
bool result = false;
lock ( _storage ) {
result = _storage.Any( a => predicate( a.Key ) );
}
return result;
}
public void Clear( ) {
if ( !_storage.IsEmpty )
_storage.Clear( );
}
public void InitilizeFromList( IList<TValue> data, Func<TValue, TKey> valueSelector ) {
ThreadSafe.Exchange( ref _storage, data.ToConcurrentDictionary( valueSelector ) );
}
public IEnumerable<KeyValuePair<TKey, TValue>> GetEnumerator( ) => _storage;
public void Dispose( ) => Clear( );
}
}
/**
* Copyright (c) 2018, Sow ( https://safeonline.world, https://www.facebook.com/safeonlineworld). (https://github.com/RKTUXYN) All rights reserved.
* Copyrights licensed under the New BSD License.
* See the accompanying LICENSE file for terms.
*/
// created 5/26/2021 2:05:50 AM and updated 10:14 PM 6/14/2022
// Rajib Chy
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
namespace Sow.Framework {
public interface IConcurrentStorage<TKey, TValue> : IDisposable {
/// <summary>
/// Gets the number of key/value pairs contained in the <see cref="IConcurrentStorage{TKey,TValue}"/>
/// </summary>
/// <returns>The number of key/value pairs contained in the <see cref="IConcurrentStorage{TKey,TValue}"/></returns>
int Count { get; }
/// <summary>
/// Gets a value that indicates whether the <see cref="IConcurrentStorage{TKey,TValue}"/> is empty.
/// </summary>
/// <returns>true if the <see cref="IConcurrentStorage{TKey,TValue}"/> is empty; otherwise,</returns>
bool IsEmpty { get; }
/// <summary>
/// Removes all keys (<typeparamref name="TKey"/>) and values (<typeparamref name="TValue"/>) from the <see cref="IConcurrentStorage{TKey,TValue}"/>
/// </summary>
void Clear( );
TValue TryGet( TKey key );
bool TryGet( TKey key, out TValue value );
void Each( Action<TValue> predicate );
void Each( Action<TKey, TValue> predicate );
bool TryAdd( TKey key, TValue value );
bool TryAddOrUpdate( TKey key, TValue value );
bool TryUpdate( TKey key, TValue value );
bool TryRemove( TKey key );
bool TryRemove( TKey key, out TValue value );
/// <summary>
/// Copies the key (<typeparamref name="TKey"/>) and value (<typeparamref name="TValue"/>) pairs stored in the <see cref="IConcurrentStorage{TKey,TValue}"/> to a new array.
/// <para>
/// see more <see href="https://referencesource.microsoft.com/#mscorlib/system/Collections/Concurrent/ConcurrentDictionary.cs,691"/>
/// </para>
/// </summary>
/// <returns>A new array containing a snapshot of key (<typeparamref name="TKey"/>) and value (<typeparamref name="TValue"/>) pairs copied from the <see cref="ConcurrentDictionary{TKey,TValue}"/>.</returns>
KeyValuePair<TKey, TValue>[] ToArray( );
List<KeyValuePair<TKey, TValue>> ToList( );
bool Exists( Func<TValue, bool> predicate );
bool Exists( Func<TKey, bool> predicate );
TValue Where( Func<TValue, bool> predicate );
TValue Where( Func<TKey, bool> predicate );
/// <summary>
/// Determines whether the <see cref="IConcurrentStorage{TKey, TValue}"/> contains the specified key.
/// </summary>
/// <param name="key">The key to locate in the <see cref="IConcurrentStorage{TKey, TValue}"/></param>
/// <returns>true if the <see cref="IConcurrentStorage{TKey, TValue}"/> contains an element with the specified key; otherwise, false.</returns>
/// <exception cref="T:System.ArgumentNullException">key is null.</exception>
bool ContainsKey( TKey key );
IDictionary<TKey, TValue> ToDictionary( );
IList<TValue> Select( Func<TValue, bool> predicate );
List<TValue> ToListObject( );
List<T> ToListObject<T>( Func<TValue, T> selector );
/// <summary>
/// Select first match <typeparamref name="TValue"/> by <paramref name="predicate"/> from <see cref="IConcurrentStorage{TKey,TValue}"/>
/// </summary>
/// <param name="predicate">Predication by <typeparamref name="TValue"/> </param>
/// <returns><see cref="IList{TValue}"/>; Count 0 when don't match any by <paramref name="predicate"/> </returns>
IList<TValue> SelectOne( Func<TValue, bool> predicate );
List<T> ToCloneObject<T>( Func<TValue, T> clone ) where T : TValue;
IEnumerable<KeyValuePair<TKey, TValue>> GetEnumerator( );
void InitilizeFromList( IList<TValue> data, Func<TValue, TKey> valueSelector );
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment