mirror of
https://github.com/ldqk/Masuit.Tools.git
synced 2026-10-27 03:14:14 +08:00
431 lines
9.8 KiB
C#
431 lines
9.8 KiB
C#
#nullable enable
|
|
using System.Collections;
|
|
using System.Runtime.Serialization;
|
|
|
|
namespace Masuit.Tools.Abstractions.Systems
|
|
{
|
|
[Serializable]
|
|
public sealed class ConcurrentLinkedList<T> :
|
|
ICollection<T>,
|
|
IEnumerable<T>,
|
|
IEnumerable,
|
|
IReadOnlyCollection<T>,
|
|
ICollection,
|
|
IDeserializationCallback,
|
|
ISerializable,
|
|
IDisposable
|
|
{
|
|
private readonly ReaderWriterLockSlim _lock = new(LockRecursionPolicy.SupportsRecursion);
|
|
private readonly LinkedList<T> _linkedList;
|
|
|
|
#region Properties
|
|
|
|
public int Count
|
|
{
|
|
get
|
|
{
|
|
_lock.EnterReadLock();
|
|
try
|
|
{
|
|
return _linkedList.Count;
|
|
}
|
|
finally
|
|
{
|
|
if (_lock.IsReadLockHeld)
|
|
_lock.ExitReadLock();
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool IsSynchronized => false;
|
|
public object SyncRoot => false;
|
|
public bool IsReadOnly => false;
|
|
|
|
public LinkedListNode<T>? First
|
|
{
|
|
get
|
|
{
|
|
_lock.EnterReadLock();
|
|
try
|
|
{
|
|
return _linkedList.First;
|
|
}
|
|
finally
|
|
{
|
|
if (_lock.IsReadLockHeld)
|
|
_lock.ExitReadLock();
|
|
}
|
|
}
|
|
}
|
|
|
|
public LinkedListNode<T>? Last
|
|
{
|
|
get
|
|
{
|
|
_lock.EnterReadLock();
|
|
try
|
|
{
|
|
return _linkedList.Last;
|
|
}
|
|
finally
|
|
{
|
|
if (_lock.IsReadLockHeld)
|
|
_lock.ExitReadLock();
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Constructors
|
|
|
|
public ConcurrentLinkedList()
|
|
{
|
|
_linkedList = [];
|
|
}
|
|
|
|
public ConcurrentLinkedList(IEnumerable<T> collection)
|
|
{
|
|
_linkedList = new LinkedList<T>(collection);
|
|
}
|
|
|
|
public ConcurrentLinkedList(SerializationInfo info, StreamingContext context)
|
|
{
|
|
_linkedList = [];
|
|
ISerializable iSerializable = _linkedList;
|
|
iSerializable.GetObjectData(info, context);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Add methods
|
|
|
|
public void Add(T item)
|
|
{
|
|
AddLast(item);
|
|
}
|
|
|
|
public void AddAfter(LinkedListNode<T> node, LinkedListNode<T> newNode)
|
|
{
|
|
_lock.EnterWriteLock();
|
|
try
|
|
{
|
|
_linkedList.AddAfter(node, newNode);
|
|
}
|
|
finally
|
|
{
|
|
if (_lock.IsReadLockHeld)
|
|
_lock.ExitReadLock();
|
|
}
|
|
}
|
|
|
|
public LinkedListNode<T> AddAfter(LinkedListNode<T> node, T value)
|
|
{
|
|
_lock.EnterWriteLock();
|
|
try
|
|
{
|
|
return _linkedList.AddAfter(node, value);
|
|
}
|
|
finally
|
|
{
|
|
if (_lock.IsReadLockHeld)
|
|
_lock.ExitReadLock();
|
|
}
|
|
}
|
|
|
|
public void AddBefore(LinkedListNode<T> node, LinkedListNode<T> newNode)
|
|
{
|
|
_lock.EnterWriteLock();
|
|
try
|
|
{
|
|
_linkedList.AddBefore(node, newNode);
|
|
}
|
|
finally
|
|
{
|
|
if (_lock.IsReadLockHeld)
|
|
_lock.ExitReadLock();
|
|
}
|
|
}
|
|
|
|
public LinkedListNode<T> AddBefore(LinkedListNode<T> node, T value)
|
|
{
|
|
_lock.EnterWriteLock();
|
|
try
|
|
{
|
|
return _linkedList.AddBefore(node, value);
|
|
}
|
|
finally
|
|
{
|
|
if (_lock.IsReadLockHeld)
|
|
_lock.ExitReadLock();
|
|
}
|
|
}
|
|
|
|
public void AddFirst(LinkedListNode<T> node)
|
|
{
|
|
_lock.EnterWriteLock();
|
|
try
|
|
{
|
|
_linkedList.AddFirst(node);
|
|
}
|
|
finally
|
|
{
|
|
if (_lock.IsReadLockHeld)
|
|
_lock.ExitReadLock();
|
|
}
|
|
}
|
|
|
|
public LinkedListNode<T> AddFirst(T value)
|
|
{
|
|
_lock.EnterWriteLock();
|
|
try
|
|
{
|
|
return _linkedList.AddFirst(value);
|
|
}
|
|
finally
|
|
{
|
|
if (_lock.IsReadLockHeld)
|
|
_lock.ExitReadLock();
|
|
}
|
|
}
|
|
|
|
public void AddLast(LinkedListNode<T> node)
|
|
{
|
|
_lock.EnterWriteLock();
|
|
try
|
|
{
|
|
_linkedList.AddLast(node);
|
|
}
|
|
finally
|
|
{
|
|
if (_lock.IsReadLockHeld)
|
|
_lock.ExitReadLock();
|
|
}
|
|
}
|
|
|
|
public LinkedListNode<T> AddLast(T value)
|
|
{
|
|
_lock.EnterWriteLock();
|
|
try
|
|
{
|
|
return _linkedList.AddLast(value);
|
|
}
|
|
finally
|
|
{
|
|
if (_lock.IsReadLockHeld)
|
|
_lock.ExitReadLock();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region List Operations
|
|
|
|
public void Clear()
|
|
{
|
|
_lock.EnterWriteLock();
|
|
try
|
|
{
|
|
_linkedList.Clear();
|
|
}
|
|
finally
|
|
{
|
|
if (_lock.IsReadLockHeld)
|
|
_lock.ExitReadLock();
|
|
}
|
|
}
|
|
|
|
public bool Contains(T item)
|
|
{
|
|
_lock.EnterReadLock();
|
|
try
|
|
{
|
|
return _linkedList.Contains(item);
|
|
}
|
|
finally
|
|
{
|
|
if (_lock.IsReadLockHeld)
|
|
_lock.ExitReadLock();
|
|
}
|
|
}
|
|
|
|
public void CopyTo(T[] array, int arrayIndex)
|
|
{
|
|
_lock.EnterReadLock();
|
|
try
|
|
{
|
|
_linkedList.CopyTo(array, arrayIndex);
|
|
}
|
|
finally
|
|
{
|
|
if (_lock.IsReadLockHeld)
|
|
_lock.ExitReadLock();
|
|
}
|
|
}
|
|
|
|
public void CopyTo(Array array, int index)
|
|
{
|
|
_lock.EnterReadLock();
|
|
try
|
|
{
|
|
((ICollection)_linkedList).CopyTo(array, index);
|
|
}
|
|
finally
|
|
{
|
|
if (_lock.IsReadLockHeld)
|
|
_lock.ExitReadLock();
|
|
}
|
|
}
|
|
|
|
public LinkedListNode<T>? Find(T value)
|
|
{
|
|
_lock.EnterReadLock();
|
|
try
|
|
{
|
|
return _linkedList.Find(value);
|
|
}
|
|
finally
|
|
{
|
|
if (_lock.IsReadLockHeld)
|
|
_lock.ExitReadLock();
|
|
}
|
|
}
|
|
|
|
public LinkedListNode<T>? FindLast(T value)
|
|
{
|
|
_lock.EnterReadLock();
|
|
try
|
|
{
|
|
return _linkedList.FindLast(value);
|
|
}
|
|
finally
|
|
{
|
|
if (_lock.IsReadLockHeld)
|
|
_lock.ExitReadLock();
|
|
}
|
|
}
|
|
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
{
|
|
return GetEnumerator();
|
|
}
|
|
|
|
public void GetObjectData(SerializationInfo info, StreamingContext context)
|
|
{
|
|
_lock.EnterReadLock();
|
|
try
|
|
{
|
|
_linkedList.GetObjectData(info, context);
|
|
}
|
|
finally
|
|
{
|
|
if (_lock.IsReadLockHeld)
|
|
_lock.ExitReadLock();
|
|
}
|
|
}
|
|
|
|
public void OnDeserialization(object? sender)
|
|
{
|
|
_linkedList.OnDeserialization(sender);
|
|
}
|
|
|
|
public IEnumerator<T> GetEnumerator()
|
|
{
|
|
List<T> snapshot;
|
|
_lock.EnterReadLock();
|
|
try
|
|
{
|
|
snapshot = _linkedList.ToList();
|
|
}
|
|
finally
|
|
{
|
|
if (_lock.IsReadLockHeld)
|
|
_lock.ExitReadLock();
|
|
}
|
|
return snapshot.GetEnumerator();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Remove methods
|
|
|
|
public void Remove(LinkedListNode<T> node)
|
|
{
|
|
_lock.EnterWriteLock();
|
|
try
|
|
{
|
|
_linkedList.Remove(node);
|
|
}
|
|
finally
|
|
{
|
|
if (_lock.IsReadLockHeld)
|
|
_lock.ExitReadLock();
|
|
}
|
|
}
|
|
|
|
public bool Remove(T item)
|
|
{
|
|
_lock.EnterWriteLock();
|
|
try
|
|
{
|
|
return _linkedList.Remove(item);
|
|
}
|
|
finally
|
|
{
|
|
if (_lock.IsReadLockHeld)
|
|
_lock.ExitReadLock();
|
|
}
|
|
}
|
|
|
|
public void RemoveFirst()
|
|
{
|
|
_lock.EnterWriteLock();
|
|
try
|
|
{
|
|
_linkedList.RemoveFirst();
|
|
}
|
|
finally
|
|
{
|
|
if (_lock.IsReadLockHeld)
|
|
_lock.ExitReadLock();
|
|
}
|
|
}
|
|
|
|
public void RemoveLast()
|
|
{
|
|
_lock.EnterWriteLock();
|
|
try
|
|
{
|
|
_linkedList.RemoveLast();
|
|
}
|
|
finally
|
|
{
|
|
if (_lock.IsReadLockHeld)
|
|
_lock.ExitReadLock();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Dispose
|
|
|
|
public void Dispose()
|
|
{
|
|
Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
private void Dispose(bool disposing)
|
|
{
|
|
if (disposing)
|
|
_lock.Dispose();
|
|
}
|
|
|
|
~ConcurrentLinkedList()
|
|
{
|
|
Dispose(false);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
} |