using System; using System.Collections.Generic; namespace BizHawk.Common { // If you're wondering what the point of this is: It's mostly to have .Clear() be fast. // only intended to be used with value types. If used on references you may get GC issues. // Also, being in the same assembly means the JITer might inline these calls. // There is less overhead by not being dynamically resizable and stuff. public sealed class QuickList where T : struct { public T[] buffer; public int Position; public QuickList(int capacity) { buffer = new T[capacity]; } public T this[int index] { get => buffer[index]; set => buffer[index] = value; } public int Count => Position; public void Add(T item) { buffer[Position++] = item; } public void Clear() { Position = 0; } } // and the point of this one is to be easier to serialize quickly. AND fast to clear. // only intended to be used with value types. If used on references you may get GC issues. public sealed class QuickQueue where T : struct { public T[] buffer; public int head; public int tail; public int size; public QuickQueue(int capacity) { buffer = new T[capacity]; } public int Count => size; /// called while at capacity public void Enqueue(T item) { if (size >= buffer.Length) throw new Exception($"{nameof(QuickQueue)} capacity breached!"); buffer[tail] = item; tail = (tail + 1) % buffer.Length; size++; } public T[] ToArray(int elemSize) { T[] ret = new T[size]; int todo; if (tail > head) todo = tail - head; else todo = buffer.Length - head; Buffer.BlockCopy(buffer, head, ret, 0, elemSize * todo); int todo2; if (tail < head) todo2 = tail; else todo2 = 0; if (todo2 != 0) Buffer.BlockCopy(buffer, 0, ret, todo, elemSize * todo2); return ret; } /// called while empty public T Dequeue() { if (size == 0) throw new Exception($"{nameof(QuickQueue)} is empty!"); T item = buffer[head]; head = (head + 1) % buffer.Length; size--; return item; } public void Clear() { head = 0; tail = 0; size = 0; } public T[] GetBuffer() { return buffer; } public void SignalBufferFilled(int count) { head = 0; tail = count; size = count; } } // .net has no built-in read only dictionary public sealed class ReadOnlyDictionary : IDictionary { private readonly IDictionary dict; public ReadOnlyDictionary(IDictionary dictionary) { dict = dictionary; } /// always public void Add(TKey key, TValue value) { throw new InvalidOperationException(); } public bool ContainsKey(TKey key) { return dict.ContainsKey(key); } public ICollection Keys => dict.Keys; /// always public bool Remove(TKey key) { throw new InvalidOperationException(); } public bool TryGetValue(TKey key, out TValue value) { return dict.TryGetValue(key, out value); } public ICollection Values => dict.Values; /// (from setter) always public TValue this[TKey key] { get => dict[key]; set => throw new InvalidOperationException(); } /// always public void Add(KeyValuePair item) { throw new InvalidOperationException(); } /// always public void Clear() { throw new InvalidOperationException(); } public bool Contains(KeyValuePair item) { return dict.Contains(item); } public void CopyTo(KeyValuePair[] array, int arrayIndex) { dict.CopyTo(array, arrayIndex); } public int Count => dict.Count; public bool IsReadOnly => true; /// always public bool Remove(KeyValuePair item) { throw new InvalidOperationException(); } public IEnumerator> GetEnumerator() { return dict.GetEnumerator(); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return ((System.Collections.IEnumerable)dict).GetEnumerator(); } } }