RaspberryIO_26/Swan.Lite/Collections/ConcurrentDataDictionary`2.cs

270 lines
13 KiB
C#
Raw Normal View History

2019-12-04 18:57:18 +01:00
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
2019-12-08 19:54:52 +01:00
namespace Swan.Collections {
/// <summary>
/// Represents a thread-safe collection of key/value pairs that does not store null values
/// and can be accessed by multiple threads concurrently.
/// </summary>
/// <typeparam name="TKey">The type of keys in the dictionary. This must be a reference type.</typeparam>
/// <typeparam name="TValue">The type of values in the dictionary. This must be a reference type.</typeparam>
/// <seealso cref="IDataDictionary{TKey,TValue}"/>
public sealed class ConcurrentDataDictionary<TKey, TValue> : IDataDictionary<TKey, TValue> where TKey : class where TValue : class {
#region Private data
private readonly ConcurrentDictionary<TKey, TValue> _dictionary;
#endregion
#region Instance management
2019-12-04 18:57:18 +01:00
/// <summary>
2019-12-08 19:54:52 +01:00
/// Initializes a new instance of the <see cref="ConcurrentDataDictionary{TKey,TValue}"/> class
/// that is empty, has the default concurrency level, has the default initial capacity,
/// and uses the default comparer for <typeparamref name="TKey"/>.
2019-12-04 18:57:18 +01:00
/// </summary>
2019-12-08 19:54:52 +01:00
/// <see cref="ConcurrentDictionary{TKey,TValue}()"/>
public ConcurrentDataDictionary() => this._dictionary = new ConcurrentDictionary<TKey, TValue>();
/// <summary>
/// Initializes a new instance of the <see cref="ConcurrentDataDictionary{TKey,TValue}"/> class
/// that contains elements copied from the specified <see cref="IEnumerable{T}"/>, has the default concurrency level,
/// has the default initial capacity, and uses the default comparer for <typeparamref name="TKey"/>.
/// </summary>
/// <param name="collection">The <see cref="IEnumerable{T}"/> whose elements are copied
/// to the new <see cref="ConcurrentDataDictionary{TKey,TValue}"/>.</param>
/// <exception cref="ArgumentNullException"><paramref name="collection"/> is <see langword="null"/>.</exception>
/// <remarks>
/// <para>Since <see cref="ConcurrentDataDictionary{TKey,TValue}"/> does not store null values,
/// key/value pairs whose value is <see langword="null"/> will not be copied from <paramref name="collection"/>.</para>
/// </remarks>
/// <see cref="ConcurrentDictionary{TKey,TValue}(IEnumerable{KeyValuePair{TKey,TValue}})"/>
public ConcurrentDataDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection) {
if(collection == null) {
throw new ArgumentNullException(nameof(collection));
}
this._dictionary = new ConcurrentDictionary<TKey, TValue>(collection.Where(pair => pair.Value != null));
}
/// <summary>
/// Initializes a new instance of the <see cref="ConcurrentDataDictionary{TKey,TValue}"/> class
/// that is empty, has the default concurrency level and capacity, and uses the specified <see cref="IEqualityComparer{T}"/>.
/// </summary>
/// <param name="comparer">The equality comparison implementation to use when comparing keys.</param>
/// <exception cref="ArgumentNullException"><paramref name="comparer"/> is <see langword="null"/>.</exception>
/// <see cref="ConcurrentDictionary{TKey,TValue}(IEqualityComparer{TKey})"/>
public ConcurrentDataDictionary(IEqualityComparer<TKey> comparer) => this._dictionary = new ConcurrentDictionary<TKey, TValue>(comparer);
/// <summary>
/// Initializes a new instance of the <see cref="ConcurrentDataDictionary{TKey, TValue}"/> class
/// that contains elements copied from the specified <see cref="IEnumerable{T}"/>, has the default concurrency level,
/// has the default initial capacity, and uses the specified <see cref="IEqualityComparer{T}"/>.
/// </summary>
/// <param name="collection">The <see cref="IEnumerable{T}"/> whose elements are copied
/// to the new <see cref="ConcurrentDataDictionary{TKey,TValue}"/>.</param>
/// <param name="comparer">The equality comparison implementation to use when comparing keys.</param>
/// <remarks>
/// <para>Since <see cref="ConcurrentDataDictionary{TKey,TValue}"/> does not store null values,
/// key/value pairs whose value is <see langword="null"/> will not be copied from <paramref name="collection"/>.</para>
/// </remarks>
/// <exception cref="ArgumentNullException">
/// <para><paramref name="collection"/> is <see langword="null"/>.</para>
/// <para>- or -.</para>
/// <para><paramref name="comparer"/> is <see langword="null"/>.</para>
/// </exception>
/// <see cref="ConcurrentDictionary{TKey,TValue}(IEnumerable{KeyValuePair{TKey,TValue}},IEqualityComparer{TKey})"/>
public ConcurrentDataDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer) {
if(collection == null) {
throw new ArgumentNullException(nameof(collection));
}
this._dictionary = new ConcurrentDictionary<TKey, TValue>(collection.Where(pair => pair.Value != null), comparer);
}
/// <summary>
/// Initializes a new instance of the <see cref="ConcurrentDataDictionary{TKey, TValue}"/> class
/// that is empty, has the specified concurrency level and capacity, and uses the default comparer for the key type.
/// </summary>
/// <param name="concurrencyLevel">The estimated number of threads that will update
/// the <see cref="ConcurrentDataDictionary{TKey, TValue}"/> concurrently.</param>
/// <param name="capacity">The initial number of elements that the <see cref="ConcurrentDataDictionary{TKey, TValue}"/> can contain.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// <para><paramref name="concurrencyLevel"/> is less than 1.</para>
/// <para>- or -.</para>
/// <para><paramref name="capacity"/> is less than 0.</para>
/// </exception>
/// <see cref="ConcurrentDictionary{TKey,TValue}(Int32,Int32)"/>
public ConcurrentDataDictionary(Int32 concurrencyLevel, Int32 capacity) => this._dictionary = new ConcurrentDictionary<TKey, TValue>(concurrencyLevel, capacity);
/// <summary>
/// Initializes a new instance of the <see cref="ConcurrentDataDictionary{TKey, TValue}"/> class
/// that contains elements copied from the specified <see cref="IEnumerable{T}"/>, has the specified concurrency level,
/// has the default initial capacity, and uses the specified <see cref="IEqualityComparer{T}"/>.
/// </summary>
/// <param name="concurrencyLevel">The estimated number of threads that will update
/// the <see cref="ConcurrentDataDictionary{TKey, TValue}"/> concurrently.</param>
/// <param name="collection">The <see cref="IEnumerable{T}"/> whose elements are copied
/// to the new <see cref="ConcurrentDataDictionary{TKey,TValue}"/>.</param>
/// <param name="comparer">The equality comparison implementation to use when comparing keys.</param>
/// <remarks>
/// <para>Since <see cref="ConcurrentDataDictionary{TKey,TValue}"/> does not store null values,
/// key/value pairs whose value is <see langword="null"/> will not be copied from <paramref name="collection"/>.</para>
/// </remarks>
/// <exception cref="ArgumentNullException">
/// <para><paramref name="collection"/> is <see langword="null"/>.</para>
/// <para>- or -.</para>
/// <para><paramref name="comparer"/> is <see langword="null"/>.</para>
/// </exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="concurrencyLevel"/> is less than 1.</exception>
/// <see cref="ConcurrentDictionary{TKey,TValue}(Int32,IEnumerable{KeyValuePair{TKey,TValue}},IEqualityComparer{TKey})"/>
public ConcurrentDataDictionary(Int32 concurrencyLevel, IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer) {
if(collection == null) {
throw new ArgumentNullException(nameof(collection));
}
this._dictionary = new ConcurrentDictionary<TKey, TValue>(concurrencyLevel, collection.Where(pair => pair.Value != null), comparer);
}
#endregion
#region Public APIs
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.Count"/>
public Int32 Count => this._dictionary.Count;
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.IsEmpty"/>
public Boolean IsEmpty => this._dictionary.IsEmpty;
/// <inheritdoc cref="IDictionary{TKey,TValue}.Keys"/>
public ICollection<TKey> Keys => this._dictionary.Keys;
/// <inheritdoc cref="IDictionary{TKey,TValue}.Values"/>
public ICollection<TValue> Values => this._dictionary.Values;
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.this"/>
public TValue this[TKey key] {
get => this._dictionary.TryGetValue(key ?? throw new ArgumentNullException(nameof(key)), out TValue value) ? value : null;
set {
if(value != null) {
this._dictionary[key] = value;
} else {
_ = this._dictionary.TryRemove(key, out _);
}
}
}
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.Clear"/>
public void Clear() => this._dictionary.Clear();
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.ContainsKey"/>
public Boolean ContainsKey(TKey key) => this._dictionary.ContainsKey(key);
/// <inheritdoc cref="ConcurrentDictionary{TKey,TValue}.GetOrAdd(TKey,TValue)"/>
public TValue GetOrAdd(TKey key, TValue value) {
if(key == null) {
throw new ArgumentNullException(nameof(key));
}
return value != null ? this._dictionary.GetOrAdd(key, value) : this._dictionary.TryGetValue(key, out TValue retrievedValue) ? retrievedValue : null;
}
/// <inheritdoc cref="IDictionary{TKey,TValue}.Remove(TKey)"/>
public Boolean Remove(TKey key) => this._dictionary.TryRemove(key, out _);
/// <inheritdoc cref="ConcurrentDictionary{TKey,TValue}.TryAdd"/>
public Boolean TryAdd(TKey key, TValue value) {
if(key == null) {
throw new ArgumentNullException(nameof(key));
}
return value == null || this._dictionary.TryAdd(key, value);
}
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.TryGetValue"/>
public Boolean TryGetValue(TKey key, out TValue value) => this._dictionary.TryGetValue(key, out value);
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.TryRemove"/>
public Boolean TryRemove(TKey key, out TValue value) => this._dictionary.TryRemove(key, out value);
/// <inheritdoc cref="ConcurrentDictionary{TKey,TValue}.TryUpdate"/>
public Boolean TryUpdate(TKey key, TValue newValue, TValue comparisonValue) {
if(key == null) {
throw new ArgumentNullException(nameof(key));
}
return newValue != null && comparisonValue != null && this._dictionary.TryUpdate(key, newValue, comparisonValue);
}
#endregion
#region Implementation of IDictionary<TKey, TValue>
/// <inheritdoc cref="IDictionary{TKey,TValue}.Add(TKey,TValue)"/>
void IDictionary<TKey, TValue>.Add(TKey key, TValue value) {
if(value != null) {
((IDictionary<TKey, TValue>)this._dictionary).Add(key, value);
} else {
_ = this._dictionary.TryRemove(key, out _);
}
}
#endregion
#region Implementation of IReadOnlyDictionary<TKey, TValue>
/// <inheritdoc cref="IReadOnlyDictionary{TKey,TValue}.Keys"/>
IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys => this._dictionary.Keys;
/// <inheritdoc cref="IReadOnlyDictionary{TKey,TValue}.Values"/>
IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values => this._dictionary.Values;
#endregion
#region Implementation of ICollection<KeyValuePair<TKey, TValue>>
/// <inheritdoc cref="ICollection{T}.IsReadOnly"/>
/// <remarks>
/// <para>This property is always <see langword="false"/> for a <see cref="ConcurrentDataDictionary{TKey,TValue}"/>.</para>
/// </remarks>
Boolean ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly => false;
/// <inheritdoc cref="ICollection{T}.Add"/>
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item) {
if(item.Value != null) {
((ICollection<KeyValuePair<TKey, TValue>>)this._dictionary).Add(item);
} else {
_ = this._dictionary.TryRemove(item.Key, out _);
}
}
/// <inheritdoc cref="ICollection{T}.Contains"/>
Boolean ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item) => ((ICollection<KeyValuePair<TKey, TValue>>)this._dictionary).Contains(item);
/// <inheritdoc cref="ICollection{T}.CopyTo"/>
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, Int32 arrayIndex) => ((ICollection<KeyValuePair<TKey, TValue>>)this._dictionary).CopyTo(array, arrayIndex);
/// <inheritdoc cref="ICollection{T}.Remove"/>
Boolean ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item) => ((ICollection<KeyValuePair<TKey, TValue>>)this._dictionary).Remove(item);
#endregion
#region Implementation of IEnumerable<KeyValuePair<TKey, TValue>>
/// <inheritdoc cref="IEnumerable{T}.GetEnumerator"/>
IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator() => this._dictionary.GetEnumerator();
#endregion
#region Implementation of IEnumerable
/// <inheritdoc cref="IEnumerable.GetEnumerator"/>
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this._dictionary).GetEnumerator();
#endregion
}
2019-12-04 18:57:18 +01:00
}