using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Runtime.Serialization; using BinaryPack.Attributes; using NitroxModel.Helper; namespace NitroxModel.DataStructures { [DebuggerDisplay($"Items = {{{nameof(list)}}}")] [DataContract] [Serializable] public class ThreadSafeList : IList { [DebuggerBrowsable(DebuggerBrowsableState.Never)] [IgnoreDataMember] private readonly object locker = new(); [DebuggerBrowsable(DebuggerBrowsableState.Never)] [DataMember(Order = 1)] [SerializableMember] private List list; public T this[int i] { get { lock (locker) { return list[i]; } } set { lock (locker) { list[i] = value; } } } public int Count { get { lock (locker) { return list.Count; } } } public bool IsReadOnly => false; public ThreadSafeList() { list = new List(); } public ThreadSafeList(int initialCapacity) { list = new List(initialCapacity); } public ThreadSafeList(IEnumerable values) { list = new List(values); } public ThreadSafeList(List list, bool createCopy = true) { this.list = createCopy ? CreateCopy(list) : list; } public void Add(T item) { lock (locker) { list.Add(item); } } public void AddRange(IEnumerable collection) { lock (locker) { list.AddRange(collection); } } public void Clear() { lock (locker) { list.Clear(); } } public void CopyTo(T[] array, int arrayIndex) { lock (locker) { list.CopyTo(array, arrayIndex); } } public bool Remove(T item) { lock (locker) { return list.Remove(item); } } public int IndexOf(T item) { lock (locker) { return list.IndexOf(item); } } public void Insert(int index, T item) { lock (locker) { list.Insert(index, item); } } public bool RemoveAt(int index) { lock (locker) { if (index >= list.Count || index < 0) { return false; } list.RemoveAt(index); return true; } } public bool Contains(T item) { lock (locker) { return list.Contains(item); } } public bool TryGetValue(int index, out T item) { lock (locker) { if (index <= list.Count || index < 0) { item = default; return false; } item = list[index]; return true; } } public List ToList() { lock (locker) { return new List(list); } } public IEnumerator GetEnumerator() { lock (locker) { return CreateCopy(list).GetEnumerator(); } } /// /// Clears the list and adds the given items. /// /// Items to add onto the empty list. public void Set(IEnumerable items) { lock (locker) { list.Clear(); foreach (T item in items) { list.Add(item); } } } public void RemoveAll(Predicate predicate) { lock (locker) { for (int i = list.Count - 1; i >= 0; i--) { if (predicate(list.ElementAt(i))) { list.RemoveAt(i); } } } } public IEnumerable Clone() { lock (locker) { return CreateCopy(list); } } public T Find(Predicate predicate) { Validate.NotNull(predicate); lock (locker) { foreach (T item in list) { if (predicate(item)) { return item; } } return default; } } void IList.RemoveAt(int index) { lock (locker) { list.RemoveAt(index); } } private List CreateCopy(IEnumerable data) { return new List(data); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } }