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 : IReadOnlyCollection, ICollection { [DebuggerBrowsable(DebuggerBrowsableState.Never)] [IgnoreDataMember] private readonly object locker = new(); [DebuggerBrowsable(DebuggerBrowsableState.Never)] [JsonProperty, ProtoIgnore] private Queue 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(value); } } } public int Count { get { lock (locker) { return queue.Count; } } } public object SyncRoot => locker; public bool IsSynchronized => true; public ThreadSafeQueue() { queue = new Queue(); } public ThreadSafeQueue(int initialCapacity) { queue = new Queue(initialCapacity); } public ThreadSafeQueue(IEnumerable values) { queue = new Queue(values); } public ThreadSafeQueue(Queue 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 Clone() { lock (locker) { return CreateCopy(queue); } } private Queue CreateCopy(IEnumerable data) { return new Queue(data); } public IEnumerator GetEnumerator() { lock (locker) { return CreateCopy(queue).GetEnumerator(); } } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); }