Good idea

This commit is contained in:
Archi
2024-02-21 03:46:25 +01:00
parent ab983099cc
commit 36a78b55a4
4 changed files with 122 additions and 19 deletions

View File

@@ -46,6 +46,8 @@ public sealed class ConcurrentHashSet<T> : IReadOnlySet<T>, ISet<T> where T : no
}
public bool Add(T item) {
ArgumentNullException.ThrowIfNull(item);
if (!BackingCollection.TryAdd(item, true)) {
return false;
}
@@ -65,9 +67,18 @@ public sealed class ConcurrentHashSet<T> : IReadOnlySet<T>, ISet<T> where T : no
OnModified?.Invoke(this, EventArgs.Empty);
}
public bool Contains(T item) => BackingCollection.ContainsKey(item);
public bool Contains(T item) {
ArgumentNullException.ThrowIfNull(item);
public void CopyTo(T[] array, int arrayIndex) => BackingCollection.Keys.CopyTo(array, arrayIndex);
return BackingCollection.ContainsKey(item);
}
public void CopyTo(T[] array, int arrayIndex) {
ArgumentNullException.ThrowIfNull(array);
ArgumentOutOfRangeException.ThrowIfNegative(arrayIndex);
BackingCollection.Keys.CopyTo(array, arrayIndex);
}
public void ExceptWith(IEnumerable<T> other) {
ArgumentNullException.ThrowIfNull(other);
@@ -80,6 +91,8 @@ public sealed class ConcurrentHashSet<T> : IReadOnlySet<T>, ISet<T> where T : no
public IEnumerator<T> GetEnumerator() => BackingCollection.Keys.GetEnumerator();
public void IntersectWith(IEnumerable<T> other) {
ArgumentNullException.ThrowIfNull(other);
ISet<T> otherSet = other as ISet<T> ?? other.ToHashSet();
foreach (T item in this.Where(item => !otherSet.Contains(item))) {
@@ -88,36 +101,48 @@ public sealed class ConcurrentHashSet<T> : IReadOnlySet<T>, ISet<T> where T : no
}
public bool IsProperSubsetOf(IEnumerable<T> other) {
ArgumentNullException.ThrowIfNull(other);
ISet<T> otherSet = other as ISet<T> ?? other.ToHashSet();
return (otherSet.Count > Count) && IsSubsetOf(otherSet);
}
public bool IsProperSupersetOf(IEnumerable<T> other) {
ArgumentNullException.ThrowIfNull(other);
ISet<T> otherSet = other as ISet<T> ?? other.ToHashSet();
return (otherSet.Count < Count) && IsSupersetOf(otherSet);
}
public bool IsSubsetOf(IEnumerable<T> other) {
ArgumentNullException.ThrowIfNull(other);
ISet<T> otherSet = other as ISet<T> ?? other.ToHashSet();
return this.All(otherSet.Contains);
}
public bool IsSupersetOf(IEnumerable<T> other) {
ArgumentNullException.ThrowIfNull(other);
ISet<T> otherSet = other as ISet<T> ?? other.ToHashSet();
return otherSet.All(Contains);
}
public bool Overlaps(IEnumerable<T> other) {
ArgumentNullException.ThrowIfNull(other);
ISet<T> otherSet = other as ISet<T> ?? other.ToHashSet();
return otherSet.Any(Contains);
}
public bool Remove(T item) {
ArgumentNullException.ThrowIfNull(item);
if (!BackingCollection.TryRemove(item, out _)) {
return false;
}
@@ -128,12 +153,16 @@ public sealed class ConcurrentHashSet<T> : IReadOnlySet<T>, ISet<T> where T : no
}
public bool SetEquals(IEnumerable<T> other) {
ArgumentNullException.ThrowIfNull(other);
ISet<T> otherSet = other as ISet<T> ?? other.ToHashSet();
return (otherSet.Count == Count) && otherSet.All(Contains);
}
public void SymmetricExceptWith(IEnumerable<T> other) {
ArgumentNullException.ThrowIfNull(other);
ISet<T> otherSet = other as ISet<T> ?? other.ToHashSet();
HashSet<T> removed = [];
@@ -155,12 +184,18 @@ public sealed class ConcurrentHashSet<T> : IReadOnlySet<T>, ISet<T> where T : no
}
}
void ICollection<T>.Add(T item) => Add(item);
void ICollection<T>.Add(T item) {
ArgumentNullException.ThrowIfNull(item);
Add(item);
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
[PublicAPI]
public bool AddRange(IEnumerable<T> items) {
ArgumentNullException.ThrowIfNull(items);
bool result = false;
foreach (T _ in items.Where(Add)) {
@@ -172,6 +207,8 @@ public sealed class ConcurrentHashSet<T> : IReadOnlySet<T>, ISet<T> where T : no
[PublicAPI]
public bool RemoveRange(IEnumerable<T> items) {
ArgumentNullException.ThrowIfNull(items);
bool result = false;
foreach (T _ in items.Where(Remove)) {
@@ -182,10 +219,16 @@ public sealed class ConcurrentHashSet<T> : IReadOnlySet<T>, ISet<T> where T : no
}
[PublicAPI]
public int RemoveWhere(Predicate<T> match) => BackingCollection.Keys.Where(match.Invoke).Count(key => BackingCollection.TryRemove(key, out _));
public int RemoveWhere(Predicate<T> match) {
ArgumentNullException.ThrowIfNull(match);
return BackingCollection.Keys.Where(match.Invoke).Count(key => BackingCollection.TryRemove(key, out _));
}
[PublicAPI]
public bool ReplaceIfNeededWith(IReadOnlyCollection<T> other) {
ArgumentNullException.ThrowIfNull(other);
if (SetEquals(other)) {
return false;
}
@@ -197,6 +240,8 @@ public sealed class ConcurrentHashSet<T> : IReadOnlySet<T>, ISet<T> where T : no
[PublicAPI]
public void ReplaceWith(IEnumerable<T> other) {
ArgumentNullException.ThrowIfNull(other);
Clear();
UnionWith(other);
}

View File

@@ -27,7 +27,7 @@ using Nito.AsyncEx;
namespace ArchiSteamFarm.Collections;
public sealed class ConcurrentList<T> : IList<T>, IReadOnlyList<T> {
public sealed class ConcurrentList<T> : IList<T>, IReadOnlyList<T> where T : notnull {
[PublicAPI]
public event EventHandler? OnModified;
@@ -55,6 +55,8 @@ public sealed class ConcurrentList<T> : IList<T>, IReadOnlyList<T> {
}
set {
ArgumentNullException.ThrowIfNull(value);
using (Lock.WriterLock()) {
BackingCollection[index] = value;
}
@@ -64,6 +66,8 @@ public sealed class ConcurrentList<T> : IList<T>, IReadOnlyList<T> {
}
public void Add(T item) {
ArgumentNullException.ThrowIfNull(item);
using (Lock.WriterLock()) {
BackingCollection.Add(item);
}
@@ -80,12 +84,17 @@ public sealed class ConcurrentList<T> : IList<T>, IReadOnlyList<T> {
}
public bool Contains(T item) {
ArgumentNullException.ThrowIfNull(item);
using (Lock.ReaderLock()) {
return BackingCollection.Contains(item);
}
}
public void CopyTo(T[] array, int arrayIndex) {
ArgumentNullException.ThrowIfNull(array);
ArgumentOutOfRangeException.ThrowIfNegative(arrayIndex);
using (Lock.ReaderLock()) {
BackingCollection.CopyTo(array, arrayIndex);
}
@@ -94,12 +103,17 @@ public sealed class ConcurrentList<T> : IList<T>, IReadOnlyList<T> {
public IEnumerator<T> GetEnumerator() => new ConcurrentEnumerator<T>(BackingCollection, Lock.ReaderLock());
public int IndexOf(T item) {
ArgumentNullException.ThrowIfNull(item);
using (Lock.ReaderLock()) {
return BackingCollection.IndexOf(item);
}
}
public void Insert(int index, T item) {
ArgumentOutOfRangeException.ThrowIfNegative(index);
ArgumentNullException.ThrowIfNull(item);
using (Lock.WriterLock()) {
BackingCollection.Insert(index, item);
}
@@ -108,6 +122,8 @@ public sealed class ConcurrentList<T> : IList<T>, IReadOnlyList<T> {
}
public bool Remove(T item) {
ArgumentNullException.ThrowIfNull(item);
using (Lock.WriterLock()) {
if (!BackingCollection.Remove(item)) {
return false;
@@ -120,6 +136,8 @@ public sealed class ConcurrentList<T> : IList<T>, IReadOnlyList<T> {
}
public void RemoveAt(int index) {
ArgumentOutOfRangeException.ThrowIfNegative(index);
using (Lock.WriterLock()) {
BackingCollection.RemoveAt(index);
}
@@ -130,6 +148,8 @@ public sealed class ConcurrentList<T> : IList<T>, IReadOnlyList<T> {
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
internal void ReplaceWith(IEnumerable<T> collection) {
ArgumentNullException.ThrowIfNull(collection);
using (Lock.WriterLock()) {
BackingCollection.Clear();
BackingCollection.AddRange(collection);

View File

@@ -23,22 +23,17 @@ using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using ArchiSteamFarm.Core;
namespace ArchiSteamFarm.Collections;
internal sealed class FixedSizeConcurrentQueue<T> : IEnumerable<T> {
internal sealed class FixedSizeConcurrentQueue<T> : IEnumerable<T> where T : notnull {
private readonly ConcurrentQueue<T> BackingQueue = new();
internal byte MaxCount {
get => BackingMaxCount;
set {
if (value == 0) {
ASF.ArchiLogger.LogNullError(value);
return;
}
ArgumentOutOfRangeException.ThrowIfZero(value);
BackingMaxCount = value;
@@ -58,6 +53,8 @@ internal sealed class FixedSizeConcurrentQueue<T> : IEnumerable<T> {
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
internal void Enqueue(T obj) {
ArgumentNullException.ThrowIfNull(obj);
BackingQueue.Enqueue(obj);
Resize();

View File

@@ -54,6 +54,8 @@ public sealed class ObservableConcurrentDictionary<TKey, TValue> : IDictionary<T
get => BackingDictionary[key];
set {
ArgumentNullException.ThrowIfNull(value);
if (BackingDictionary.TryGetValue(key, out TValue? savedValue) && EqualityComparer<TValue>.Default.Equals(savedValue, value)) {
return;
}
@@ -69,7 +71,11 @@ public sealed class ObservableConcurrentDictionary<TKey, TValue> : IDictionary<T
Add(key, value);
}
public void Add(TKey key, TValue value) => TryAdd(key, value);
public void Add(TKey key, TValue value) {
ArgumentNullException.ThrowIfNull(key);
TryAdd(key, value);
}
public void Clear() {
if (BackingDictionary.IsEmpty) {
@@ -81,7 +87,14 @@ public sealed class ObservableConcurrentDictionary<TKey, TValue> : IDictionary<T
}
public bool Contains(KeyValuePair<TKey, TValue> item) => ((ICollection<KeyValuePair<TKey, TValue>>) BackingDictionary).Contains(item);
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) => ((ICollection<KeyValuePair<TKey, TValue>>) BackingDictionary).CopyTo(array, arrayIndex);
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) {
ArgumentNullException.ThrowIfNull(array);
ArgumentOutOfRangeException.ThrowIfNegative(arrayIndex);
((ICollection<KeyValuePair<TKey, TValue>>) BackingDictionary).CopyTo(array, arrayIndex);
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() => BackingDictionary.GetEnumerator();
public bool Remove(KeyValuePair<TKey, TValue> item) {
@@ -97,6 +110,8 @@ public sealed class ObservableConcurrentDictionary<TKey, TValue> : IDictionary<T
}
public bool Remove(TKey key) {
ArgumentNullException.ThrowIfNull(key);
if (!BackingDictionary.TryRemove(key, out _)) {
return false;
}
@@ -106,14 +121,36 @@ public sealed class ObservableConcurrentDictionary<TKey, TValue> : IDictionary<T
return true;
}
bool IDictionary<TKey, TValue>.ContainsKey(TKey key) => BackingDictionary.ContainsKey(key);
bool IReadOnlyDictionary<TKey, TValue>.ContainsKey(TKey key) => BackingDictionary.ContainsKey(key);
bool IDictionary<TKey, TValue>.ContainsKey(TKey key) {
ArgumentNullException.ThrowIfNull(key);
return BackingDictionary.ContainsKey(key);
}
bool IReadOnlyDictionary<TKey, TValue>.ContainsKey(TKey key) {
ArgumentNullException.ThrowIfNull(key);
return BackingDictionary.ContainsKey(key);
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
bool IReadOnlyDictionary<TKey, TValue>.TryGetValue(TKey key, out TValue value) => BackingDictionary.TryGetValue(key, out value!);
bool IDictionary<TKey, TValue>.TryGetValue(TKey key, out TValue value) => BackingDictionary.TryGetValue(key, out value!);
bool IReadOnlyDictionary<TKey, TValue>.TryGetValue(TKey key, out TValue value) {
ArgumentNullException.ThrowIfNull(key);
return BackingDictionary.TryGetValue(key, out value!);
}
bool IDictionary<TKey, TValue>.TryGetValue(TKey key, out TValue value) {
ArgumentNullException.ThrowIfNull(key);
return BackingDictionary.TryGetValue(key, out value!);
}
[PublicAPI]
public bool TryAdd(TKey key, TValue value) {
ArgumentNullException.ThrowIfNull(key);
if (!BackingDictionary.TryAdd(key, value)) {
return false;
}
@@ -124,5 +161,9 @@ public sealed class ObservableConcurrentDictionary<TKey, TValue> : IDictionary<T
}
[PublicAPI]
public bool TryGetValue(TKey key, out TValue? value) => BackingDictionary.TryGetValue(key, out value);
public bool TryGetValue(TKey key, out TValue? value) {
ArgumentNullException.ThrowIfNull(key);
return BackingDictionary.TryGetValue(key, out value);
}
}