Files
Nitrox/NitroxModel/DataStructures/ThreadSafeQueue.cs
2025-07-06 00:23:46 +02:00

176 lines
3.3 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.Serialization;
using Newtonsoft.Json;
using ProtoBufNet;
namespace NitroxModel.DataStructures;
[DebuggerDisplay($"Items = {{{nameof(queue)}}}")]
[ProtoContract, JsonObject(MemberSerialization.OptIn)]
[Serializable]
public class ThreadSafeQueue<T> : IReadOnlyCollection<T>, ICollection
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
[IgnoreDataMember]
private readonly object locker = new();
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
[JsonProperty, ProtoIgnore]
private Queue<T> queue;
// Protobuf serialization workaround, see: https://stackoverflow.com/a/31021014
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
[ProtoMember(1), JsonIgnore]
private T[] Items
{
get
{
lock (locker)
{
return queue.ToArray();
}
}
init
{
lock (locker)
{
queue = new Queue<T>(value);
}
}
}
public int Count
{
get
{
lock (locker)
{
return queue.Count;
}
}
}
public object SyncRoot => locker;
public bool IsSynchronized => true;
public ThreadSafeQueue()
{
queue = new Queue<T>();
}
public ThreadSafeQueue(int initialCapacity)
{
queue = new Queue<T>(initialCapacity);
}
public ThreadSafeQueue(IEnumerable<T> values)
{
queue = new Queue<T>(values);
}
public ThreadSafeQueue(Queue<T> queue, bool createCopy = true)
{
this.queue = createCopy ? CreateCopy(queue) : queue;
}
public void Clear()
{
lock (locker)
{
queue.Clear();
}
}
public bool Contains(T item)
{
lock (locker)
{
return queue.Contains(item);
}
}
public void CopyTo(Array array, int arrayIndex)
{
lock (locker)
{
T[] tmpArray = ToArray();
tmpArray.CopyTo(array, arrayIndex);
}
}
public void CopyTo(T[] array, int arrayIndex)
{
lock (locker)
{
queue.CopyTo(array, arrayIndex);
}
}
public T Dequeue()
{
lock (locker)
{
return queue.Dequeue();
}
}
public void Enqueue(T item)
{
lock (locker)
{
queue.Enqueue(item);
}
}
public T Peek()
{
lock (locker)
{
return queue.Peek();
}
}
public T[] ToArray()
{
lock (locker)
{
return queue.ToArray();
}
}
public void TrimExcess()
{
lock (locker)
{
queue.TrimExcess();
}
}
public IEnumerable<T> Clone()
{
lock (locker)
{
return CreateCopy(queue);
}
}
private Queue<T> CreateCopy(IEnumerable<T> data)
{
return new Queue<T>(data);
}
public IEnumerator<T> GetEnumerator()
{
lock (locker)
{
return CreateCopy(queue).GetEnumerator();
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}