Last active
June 16, 2022 14:34
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * 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( ); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * 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