server-master/srcs/WingsAPI.Game/Generics/ThreadSafeSortedList.cs
2026-02-10 18:21:30 +01:00

786 lines
No EOL
17 KiB
C#

// WingsEmu
//
// Developed by NosWings Team
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace WingsEmu.Core.Generics;
/// <summary>
/// This class is used to store key-value based items in a thread safe manner. It uses
/// <see cref="SortedList" /> publicly.
/// </summary>
/// <typeparam name="TK">Key type</typeparam>
/// <typeparam name="TV">Value type</typeparam>
public class ThreadSafeSortedList<TK, TV> : IDisposable
{
#region Instantiation
/// <summary>
/// Creates a new ThreadSafeSortedList object.
/// </summary>
public ThreadSafeSortedList()
{
_items = new SortedList<TK, TV>();
_lock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
}
#endregion
#region Properties
/// <summary>
/// Gets count of items in the collection.
/// </summary>
public int Count
{
get
{
if (_disposed)
{
return 0;
}
_lock.EnterReadLock();
try
{
return _items.Count;
}
finally
{
_lock.ExitReadLock();
}
return 0;
}
}
#endregion
#region Indexers
/// <summary>
/// Gets/adds/replaces an item by key.
/// </summary>
/// <param name="key">Key to get/set value</param>
/// <returns>Item associated with this key</returns>
public TV this[TK key]
{
get
{
if (_disposed)
{
return default;
}
_lock.EnterReadLock();
try
{
return _items.ContainsKey(key) ? _items[key] : default;
}
finally
{
_lock.ExitReadLock();
}
}
set
{
if (_disposed)
{
return;
}
_lock.EnterWriteLock();
try
{
_items[key] = value;
}
finally
{
_lock.ExitWriteLock();
}
}
}
#endregion
#region Members
/// <summary>
/// private collection to store _items.
/// </summary>
private readonly SortedList<TK, TV> _items;
/// <summary>
/// Used to synchronize access to _items list.
/// </summary>
private readonly ReaderWriterLockSlim _lock;
private bool _disposed;
#endregion
#region Methods
/// <summary>
/// Determines whether all elements of a sequence satisfy a condition.
/// </summary>
/// <param name="predicate"></param>
/// <returns><see cref="bool" /> True; if elements satisfy the condition</returns>
public bool All(Func<TV, bool> predicate)
{
if (_disposed)
{
return false;
}
_lock.EnterReadLock();
try
{
return _items.Values.All(predicate);
}
finally
{
_lock.ExitReadLock();
}
}
/// <summary>
/// Determines whether any element of a sequence satisfies a condition.
/// </summary>
/// <param name="predicate"></param>
/// <returns>
/// <see cref="bool" />
/// </returns>
public bool Any(Func<TV, bool> predicate)
{
if (_disposed)
{
return false;
}
_lock.EnterReadLock();
try
{
return _items.Values.Any(predicate);
}
finally
{
_lock.ExitReadLock();
}
}
/// <summary>
/// Removes all items from list.
/// </summary>
public void ClearAll()
{
if (_disposed)
{
return;
}
_lock.EnterWriteLock();
try
{
_items.Clear();
}
finally
{
_lock.ExitWriteLock();
}
}
/// <summary>
/// Checks if collection contains spesified key.
/// </summary>
/// <param name="key">Key to check</param>
/// <returns><see cref="bool" /> True; if collection contains given key</returns>
public bool ContainsKey(TK key)
{
if (_disposed)
{
return false;
}
_lock.EnterReadLock();
try
{
return _items.ContainsKey(key);
}
finally
{
_lock.ExitReadLock();
}
}
/// <summary>
/// Checks if collection contains spesified item.
/// </summary>
/// <param name="item">Item to check</param>
/// <returns><see cref="bool" /> True; if collection contains given item</returns>
public bool ContainsValue(TV item)
{
if (_disposed)
{
return false;
}
_lock.EnterReadLock();
try
{
return _items.ContainsValue(item);
}
finally
{
_lock.ExitReadLock();
}
}
/// <summary>
/// Returns a number that represents how many elements in the specified sequence satisfy a condition.
/// </summary>
/// <param name="predicate"></param>
/// <returns><see cref="int" /> number of found elements</returns>
public int CountLinq(Func<TV, bool> predicate)
{
if (_disposed)
{
return 0;
}
_lock.EnterReadLock();
try
{
return _items.Values.Count(predicate);
}
finally
{
_lock.ExitReadLock();
}
return 0;
}
/// <summary>
/// Disposes the current object.
/// </summary>
public void Dispose()
{
if (_disposed)
{
return;
}
_disposed = true;
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Returns the first element of the sequence that satisfies a condition or a default value
/// if no such element is found.
/// </summary>
/// <param name="predicate"></param>
/// <returns><see cref="TV" /> object</returns>
public TV FirstOrDefault(Func<TV, bool> predicate)
{
if (_disposed)
{
return default;
}
_lock.EnterReadLock();
try
{
return _items.Values.FirstOrDefault(predicate);
}
finally
{
_lock.ExitReadLock();
}
return default;
}
/// <summary>
/// Performs the specified action on each element of the <see cref="List{T}" />.
/// </summary>
/// <param name="action"></param>
public void ForEach(Action<TV> action)
{
if (_disposed)
{
return;
}
_lock.EnterReadLock();
try
{
_items.Values.ToList().ForEach(action);
}
finally
{
_lock.ExitReadLock();
}
}
/// <summary>
/// Gets all items in collection.
/// </summary>
/// <returns>
/// <see cref="List{TV}" />
/// </returns>
public List<TV> GetAllItems()
{
if (_disposed)
{
return new List<TV>();
}
_lock.EnterReadLock();
try
{
return new List<TV>(_items.Values);
}
finally
{
_lock.ExitReadLock();
}
}
/// <summary>
/// Gets then removes all items in collection.
/// </summary>
/// <returns>
/// <see cref="List{TV}" />
/// </returns>
public List<TV> GetAndClearAllItems()
{
if (_disposed)
{
return new List<TV>();
}
_lock.EnterWriteLock();
try
{
var list = new List<TV>(_items.Values);
_items.Clear();
return list;
}
finally
{
_lock.ExitWriteLock();
}
}
/// <summary>
/// Returns the last element of a sequence that satisfies a specified condition.
/// </summary>
/// <param name="predicate"></param>
/// <returns><see cref="TV" /> object</returns>
public TV Last(Func<TV, bool> predicate)
{
if (_disposed)
{
return default;
}
_lock.EnterReadLock();
try
{
return _items.Values.Last(predicate);
}
finally
{
_lock.ExitReadLock();
}
return default;
}
/// <summary>
/// Returns the last element of a sequence.
/// </summary>
/// <returns><see cref="TV" /> object</returns>
public TV Last()
{
if (_disposed)
{
return default;
}
_lock.EnterReadLock();
try
{
return _items.Values.Last();
}
finally
{
_lock.ExitReadLock();
}
return default;
}
/// <summary>
/// Returns the last element of a sequence that satisfies a condition or a default value if
/// no such element is found.
/// </summary>
/// <param name="predicate"></param>
/// <returns><see cref="TV" /> object</returns>
public TV LastOrDefault(Func<TV, bool> predicate)
{
if (_disposed)
{
return default;
}
_lock.EnterReadLock();
try
{
return _items.Values.LastOrDefault(predicate);
}
finally
{
_lock.ExitReadLock();
}
return default;
}
/// <summary>
/// Returns the last element of a sequence, or a default value if the sequence contains no elements.
/// </summary>
/// <returns><see cref="TV" /> object</returns>
public TV LastOrDefault()
{
if (_disposed)
{
return default;
}
_lock.EnterReadLock();
try
{
return _items.Values.LastOrDefault();
}
finally
{
_lock.ExitReadLock();
}
return default;
}
/// <summary>
/// Removes an item from collection.
/// </summary>
/// <param name="key">Key of item to remove</param>
/// <returns><see cref="bool" /> if removed</returns>
public bool Remove(TK key)
{
if (_disposed)
{
return false;
}
_lock.EnterWriteLock();
try
{
if (!_items.ContainsKey(key))
{
return false;
}
_items.Remove(key);
return true;
}
finally
{
_lock.ExitWriteLock();
}
}
/// <summary>
/// Removes an item from collection.
/// </summary>
/// <param name="value">Value of item to remove</param>
/// <returns><see cref="bool" /> if removed</returns>
public bool Remove(TV value)
{
if (_disposed)
{
return false;
}
_lock.EnterWriteLock();
try
{
if (!_items.ContainsValue(value))
{
return false;
}
_items.RemoveAt(_items.IndexOfValue(value));
return true;
}
finally
{
_lock.ExitWriteLock();
}
return false;
}
/// <summary>
/// Projects each element of a sequence into a new form.
/// </summary>
/// <typeparam name="TResult"></typeparam>
/// <param name="selector"></param>
public IEnumerable<TResult> Select<TResult>(Func<TV, TResult> selector)
{
if (_disposed)
{
return default;
}
_lock.EnterReadLock();
try
{
return _items.Values.Select(selector);
}
finally
{
_lock.ExitReadLock();
}
}
/// <summary>
/// Returns the only element of a sequence that satisfies a specified condition, and throws
/// an exception if more than one such element exists.
/// </summary>
/// <param name="predicate"></param>
/// <returns><see cref="TV" /> object</returns>
public TV Single(Func<TV, bool> predicate)
{
if (_disposed)
{
return default;
}
_lock.EnterReadLock();
try
{
return _items.Values.Single(predicate);
}
finally
{
_lock.ExitReadLock();
}
}
/// <summary>
/// Returns the only element of a sequence that satisfies a specified condition or a default
/// value if no such element exists; this method throws an exception if more than one element
/// satisfies the condition.
/// </summary>
/// <param name="predicate"></param>
/// <returns><see cref="TV" /> object</returns>
public TV SingleOrDefault(Func<TV, bool> predicate)
{
if (!_disposed)
{
_lock.EnterReadLock();
try
{
return _items.Values.SingleOrDefault(predicate);
}
finally
{
_lock.ExitReadLock();
}
}
return default;
}
/// <summary>
/// Returns a number that represents how many elements in the specified sequence satisfy a condition.
/// </summary>
/// <param name="selector"></param>
/// <returns><see cref="int" /> number of found elements</returns>
public int Sum(Func<TV, int> selector)
{
if (!_disposed)
{
_lock.EnterReadLock();
try
{
return _items.Values.Sum(selector);
}
finally
{
_lock.ExitReadLock();
}
}
return 0;
}
/// <summary>
/// Returns a number that represents how many elements in the specified sequence satisfy a condition.
/// </summary>
/// <param name="selector"></param>
/// <returns>int? number of found elements</returns>
public int? Sum(Func<TV, int?> selector)
{
if (!_disposed)
{
_lock.EnterReadLock();
try
{
return _items.Values.Sum(selector);
}
finally
{
_lock.ExitReadLock();
}
}
return 0;
}
/// <summary>
/// Returns a number that represents how many elements in the specified sequence satisfy a condition.
/// </summary>
/// <param name="selector"></param>
/// <returns><see cref="long" /> number of found elements</returns>
public long Sum(Func<TV, long> selector)
{
if (!_disposed)
{
_lock.EnterReadLock();
try
{
return _items.Values.Sum(selector);
}
finally
{
_lock.ExitReadLock();
}
}
return 0;
}
/// <summary>
/// Returns a number that represents how many elements in the specified sequence satisfy a condition.
/// </summary>
/// <param name="selector"></param>
/// <returns>long? number of found elements</returns>
public long? Sum(Func<TV, long?> selector)
{
if (!_disposed)
{
_lock.EnterReadLock();
try
{
return _items.Values.Sum(selector);
}
finally
{
_lock.ExitReadLock();
}
}
return 0;
}
/// <summary>
/// Returns a number that represents how many elements in the specified sequence satisfy a condition.
/// </summary>
/// <param name="selector"></param>
/// <returns><see cref="double" /> number of found elements</returns>
public double Sum(Func<TV, double> selector)
{
if (!_disposed)
{
_lock.EnterReadLock();
try
{
return _items.Values.Sum(selector);
}
finally
{
_lock.ExitReadLock();
}
}
return 0;
}
/// <summary>
/// Returns a number that represents how many elements in the specified sequence satisfy a condition.
/// </summary>
/// <param name="selector"></param>
/// <returns>double? number of found elements</returns>
public double? Sum(Func<TV, double?> selector)
{
if (!_disposed)
{
_lock.EnterReadLock();
try
{
return _items.Values.Sum(selector);
}
finally
{
_lock.ExitReadLock();
}
}
return 0;
}
/// <summary>
/// Filters a sequence of values based on a predicate.
/// </summary>
/// <param name="predicate"></param>
/// <returns>
/// <see cref="List{TV}" />
/// </returns>
public List<TV> Where(Func<TV, bool> predicate)
{
if (!_disposed)
{
_lock.EnterReadLock();
try
{
return new List<TV>(_items.Values.Where(predicate));
}
finally
{
_lock.ExitReadLock();
}
}
return new List<TV>();
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
ClearAll();
_lock.Dispose();
}
}
#endregion
}