diff --git a/src/Utils/ArrayUtility.cs b/src/Utils/ArrayUtility.cs index fe8b188..9eab0b6 100644 --- a/src/Utils/ArrayUtility.cs +++ b/src/Utils/ArrayUtility.cs @@ -1,7 +1,4 @@ -using System; -using System.Runtime.InteropServices; - -namespace DCFApixels.DragonECS.Utils +namespace DCFApixels.DragonECS.Utils { internal static class ArrayUtility { @@ -15,34 +12,4 @@ namespace DCFApixels.DragonECS.Utils array[i] = value; } } - - internal static unsafe class UnmanagedArrayUtility - { - public static void* New(int elementCount) where T : struct - { - return Marshal.AllocHGlobal(Marshal.SizeOf(typeof(T)) * elementCount).ToPointer(); - } - - public static void* NewAndInit(int elementCount) where T : struct - { - int newSizeInBytes = Marshal.SizeOf(typeof(T)) * elementCount; - byte* newArrayPointer = (byte*)Marshal.AllocHGlobal(newSizeInBytes).ToPointer(); - - for (int i = 0; i < newSizeInBytes; i++) - *(newArrayPointer + i) = 0; - - return newArrayPointer; - } - - public static void Free(void* pointerToUnmanagedMemory) - { - Marshal.FreeHGlobal(new IntPtr(pointerToUnmanagedMemory)); - } - - public static void* Resize(void* oldPointer, int newElementCount) where T : struct - { - return (Marshal.ReAllocHGlobal(new IntPtr(oldPointer), - new IntPtr(Marshal.SizeOf(typeof(T)) * newElementCount))).ToPointer(); - } - } } diff --git a/src/Utils/SparseArray.cs b/src/Utils/SparseArray.cs deleted file mode 100644 index 8d9dccb..0000000 --- a/src/Utils/SparseArray.cs +++ /dev/null @@ -1,259 +0,0 @@ -//SparseArray. Analogous to Dictionary, but faster. -//Benchmark result of indexer.get speed test with 300 elements: -//[Dictinary: 5.786us] [SparseArray: 2.047us]. -using System; -using System.Diagnostics.Contracts; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace DCFApixels.DragonECS.Utils -{ - public class SparseArray - { - public const int MIN_CAPACITY_BITS_OFFSET = 4; - public const int MIN_CAPACITY = 1 << MIN_CAPACITY_BITS_OFFSET; - private const int EMPTY = -1; - - private int[] _buckets = Array.Empty(); - private Entry[] _entries = Array.Empty(); - private int[] _dense; - - private int _count; - - private int _freeList; - private int _freeCount; - - private int _modBitMask; - - #region Properties - public ref TValue this[int key] - { - get => ref _entries[FindEntry(key)].value; - //set => Insert(key, value); - } - - public int Count => _count; - #endregion - - #region Constructors - public SparseArray(int minCapacity = MIN_CAPACITY) - { - minCapacity = NormalizeCapacity(minCapacity); - _buckets = new int[minCapacity]; - for (int i = 0; i < minCapacity; i++) - _buckets[i] = EMPTY; - _entries = new Entry[minCapacity]; - _modBitMask = (minCapacity - 1) & 0x7FFFFFFF; - } - #endregion - - #region Add - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Add(int key, TValue value) - { -#if DEBUG - if (Contains(key)) - throw new ArgumentException("Contains(hashKey) is true"); -#endif - Insert(key, value); - } - #endregion - - #region Find/Insert/Remove - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private int FindEntry(int key) - { - for (int i = _buckets[key & _modBitMask]; i >= 0; i = _entries[i].next) - if (_entries[i].hashKey == key) return i; - return -1; - } - private void Insert(int key, TValue value) - { - int targetBucket = key & _modBitMask; - - for (int i = _buckets[targetBucket]; i >= 0; i = _entries[i].next) - { - if (_entries[i].hashKey == key) - { - _entries[i].value = value; - return; - } - } - - int index; - if (_freeCount > 0) - { - index = _freeList; - _freeList = _entries[index].next; - _freeCount--; - } - else - { - if (_count == _entries.Length) - { - Resize(); - targetBucket = key & _modBitMask; - } - index = _count++; - } - - _entries[index].next = _buckets[targetBucket]; - _entries[index].hashKey = key; - _entries[index].value = value; - _buckets[targetBucket] = index; - } - public bool Remove(int key) - { - int bucket = key & _modBitMask; - int last = -1; - for (int i = _buckets[bucket]; i >= 0; last = i, i = _entries[i].next) - { - if (_entries[i].hashKey == key) - { - if (last < 0) - { - _buckets[bucket] = _entries[i].next; - } - else - { - _entries[last].next = _entries[i].next; - } - _entries[i].next = _freeList; - _entries[i].hashKey = -1; - _entries[i].value = default; - _freeList = i; - _freeCount++; - return true; - } - } - return false; - } - #endregion - - #region TryGetValue - public bool TryGetValue(int key, out TValue value) - { - int index = FindEntry(key); - if (index < 0) - { - value = default; - return false; - } - value = _entries[index].value; - return true; - } - #endregion - - #region Contains - public bool Contains(int key) - { - return FindEntry(key) >= 0; - } - #endregion - - #region Clear - public void Clear() - { - if (_count > 0) - { - for (int i = 0; i < _buckets.Length; i++) - { - _buckets[i] = -1; - } - Array.Clear(_entries, 0, _count); - _count = 0; - } - } - #endregion - - #region Resize - private void Resize() - { - int newSize = _buckets.Length << 1; - _modBitMask = (newSize - 1) & 0x7FFFFFFF; - - Contract.Assert(newSize >= _entries.Length); - int[] newBuckets = new int[newSize]; - for (int i = 0; i < newBuckets.Length; i++) - newBuckets[i] = EMPTY; - - Entry[] newEntries = new Entry[newSize]; - Array.Copy(_entries, 0, newEntries, 0, _count); - for (int i = 0; i < _count; i++) - { - if (newEntries[i].hashKey >= 0) - { - int bucket = newEntries[i].hashKey % newSize; - newEntries[i].next = newBuckets[bucket]; - newBuckets[bucket] = i; - } - } - _buckets = newBuckets; - _entries = newEntries; - } - - private int NormalizeCapacity(int capacity) - { - int result = MIN_CAPACITY; - while (result < capacity) result <<= 1; - return result; - } - #endregion - - - //#region Enumerator - // public Enumerator GetEnumerator() => new Enumerator(this); - // public struct Enumerator - // { - // private SparseArray _source; - // private int index; - // private int curretnItmeIndex; - // - // public ref readonly TValue Current - // { - // get - // { - // return ref _source._entries[curretnItmeIndex].value; - // } - // } - // - // public Enumerator(SparseArray source) - // { - // _source = source; - // index = 0; - // curretnItmeIndex = 0; - // } - // - // public bool MoveNext() - // { - // // Use unsigned comparison since we set index to dictionary.count+1 when the enumeration ends. - // // dictionary.count+1 could be negative if dictionary.count is Int32.MaxValue - // while ((uint)index < (uint)_source.count) - // { - // if (dictionary.entries[index].hashCode >= 0) - // { - // current = new KeyValuePair(dictionary.entries[index].key, dictionary.entries[index].value); - // index++; - // return true; - // } - // index++; - // } - // - // index = dictionary.count + 1; - // current = new KeyValuePair(); - // return false; - // } - // } - // #endregion - - #region Utils - [StructLayout(LayoutKind.Sequential, Pack = 4)] - private struct Entry - { - public int next; // Index of next entry, -1 if last - public int hashKey; - public TValue value; - } - #endregion - } -} \ No newline at end of file diff --git a/src/Utils/SparseSet.cs b/src/Utils/SparseSet.cs deleted file mode 100644 index 9bc7b4d..0000000 --- a/src/Utils/SparseSet.cs +++ /dev/null @@ -1,409 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using System.Text; - -namespace DCFApixels.DragonECS.Utils -{ - public class SparseSet : IEnumerable, ICollection, IReadOnlyCollection - { - public const int DEFAULT_DENSE_CAPACITY = 8; - public const int DEFAULT_SPARSE_CAPACITY = 16; - - public const int MIN_CAPACITY = 4; - - public const int MAX_CAPACITY = int.MaxValue; - - private int[] _dense; - private int[] _sparse; - - private int _count; - - #region Properties - public int Count - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _count; - } - public int CapacityDense - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _dense.Length; - } - public int CapacitySparse - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _sparse.Length; - } - - public int this[int index] - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { -#if DEBUG - ThrowHalper.CheckOutOfRange(this, index); -#endif - return _dense[index]; - } - } - #endregion - - #region Constructors - public SparseSet() : this(DEFAULT_DENSE_CAPACITY, DEFAULT_SPARSE_CAPACITY) { } - public SparseSet(int denseCapacity, int sparseCapacity) - { - denseCapacity = denseCapacity < MIN_CAPACITY ? MIN_CAPACITY : NormalizeCapacity(denseCapacity); - sparseCapacity = sparseCapacity < MIN_CAPACITY ? MIN_CAPACITY : NormalizeCapacity(sparseCapacity); - - _dense = new int[denseCapacity]; - _sparse = new int[sparseCapacity]; - - Reset(); - } - #endregion - - #region Add/AddRange - public void Add(int value, ref T[] normalizedArray) - { - Add(value); - Normalize(ref normalizedArray); - } - - public void Add(int value) - { -#if DEBUG - ThrowHalper.CheckValueIsPositive(value); - ThrowHalper.CheckValueNotContained(this, value); -#endif - if (_count >= _dense.Length) - Array.Resize(ref _dense, _dense.Length << 1); - - if (value >= _sparse.Length) - { - int neadedSpace = _sparse.Length; - while (value >= neadedSpace) - neadedSpace <<= 1; - int i = _sparse.Length; - Array.Resize(ref _sparse, neadedSpace); - //loop unwinding - for (; i < neadedSpace;) - { - _sparse[i++] = -1; - _sparse[i++] = -1; - _sparse[i++] = -1; - _sparse[i++] = -1; - } - } - - _dense[_count] = value; - _sparse[value] = _count++; - } - - public bool TryAdd(int value, ref T[] normalizedArray) - { - if (Contains(value)) return false; - Add(value); - Normalize(ref normalizedArray); - return true; - } - public bool TryAdd(int value) - { - if (Contains(value)) return false; - Add(value); - return true; - } - - public void AddRange(IEnumerable range, ref T[] normalizedArray) - { - AddRange(range); - Normalize(ref normalizedArray); - } - public void AddRange(IEnumerable range) - { - foreach (var item in range) - { - if (Contains(item)) continue; - Add(item); - } - } - #endregion - - #region Contains - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(int value) - { - return value >= 0 && value < CapacitySparse && _sparse[value] >= 0; - } - #endregion - - #region Remove - public void Remove(int value) - { -#if DEBUG - ThrowHalper.CheckValueContained(this, value); -#endif - _dense[_sparse[value]] = _dense[--_count]; - _sparse[_dense[_count]] = _sparse[value]; - _sparse[value] = -1; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryRemove(int value) - { - if (!Contains(value)) return false; - Remove(value); - return true; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void RemoveAt(int index) - { -#if DEBUG - ThrowHalper.CheckOutOfRange(this, index); -#endif - Remove(_dense[index]); - } - #endregion - - #region Other - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Normalize(ref T[] array) - { - if (array.Length < CapacityDense) Array.Resize(ref array, CapacityDense); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int IndexOf(int value) - { - if (value < 0 || !Contains(value)) return -1; - return _sparse[value]; - } - - public void Sort() - { - int increment = 0; - for (int i = 0; i < CapacitySparse; i++) - { - if (_sparse[i] < _count) - { - _sparse[i] = increment; - _dense[increment++] = i; - } - } - } - - public void HardSort() - { - int inc = 0; - int inc2 = _count; - for (int i = 0; i < CapacitySparse; i++) - { - if (_sparse[i] >= 0) - { - _sparse[i] = inc; - _dense[inc++] = i; - } - else - { - _dense[inc2++] = i; - } - } - } - - public void CopyTo(SparseSet other) - { - other._count = _count; - if (CapacitySparse != other.CapacitySparse) - Array.Resize(ref other._sparse, CapacitySparse); - if (CapacityDense != other.CapacityDense) - Array.Resize(ref other._dense, CapacityDense); - _sparse.CopyTo(other._sparse, 0); - _dense.CopyTo(other._dense, 0); - } - - public void CopyTo(int[] array, int arrayIndex) - { -#if DEBUG - if (arrayIndex < 0) throw new ArgumentException("arrayIndex is less than 0"); - if (arrayIndex + _count >= array.Length) throw new ArgumentException("The number of elements in the source List is greater than the available space from arrayIndex to the end of the destination array."); -#endif - for (int i = 0; i < _count; i++, arrayIndex++) - { - array[arrayIndex] = this[i]; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private int NormalizeCapacity(int value) - { - return value + (MIN_CAPACITY - (value % MIN_CAPACITY)); - } - #endregion - - #region Clear/Reset - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Clear() => _count = 0; - public void Reset() - { - Clear(); - //loop unwinding - for (int i = 0; i < _sparse.Length;) - { - _sparse[i++] = -1; - _sparse[i++] = -1; - _sparse[i++] = -1; - _sparse[i++] = -1; - } - } - - public void Reset(int newDenseCapacity, int newSparseCapacity) - { - newDenseCapacity = newDenseCapacity < MIN_CAPACITY ? MIN_CAPACITY : NormalizeCapacity(newDenseCapacity); - newSparseCapacity = newSparseCapacity < MIN_CAPACITY ? MIN_CAPACITY : NormalizeCapacity(newSparseCapacity); - - if (CapacitySparse != newSparseCapacity) - Array.Resize(ref _sparse, newSparseCapacity); - if (CapacityDense != newDenseCapacity) - Array.Resize(ref _dense, newDenseCapacity); - Reset(); - } - #endregion - - #region Enumerator - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public RefEnumerator GetEnumerator() => new RefEnumerator(_dense, _count); - - public ref struct RefEnumerator - { - private readonly int[] _dense; - private readonly int _count; - private int _index; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public RefEnumerator(int[] values, int count) - { - _dense = values; - _count = count; - _index = -1; - } - - public int Current - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _dense[_index]; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Dispose() { } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool MoveNext() => ++_index < _count; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Reset() => _index = -1; - } - - IEnumerator IEnumerable.GetEnumerator() => new Enumerator(_dense, _count); - IEnumerator IEnumerable.GetEnumerator() => new Enumerator(_dense, _count); - public struct Enumerator : IEnumerator //to implement the IEnumerable interface and use the ref structure, 2 Enumerators were created. - { - private readonly int[] _dense; - private readonly int _count; - private int _index; - public Enumerator(int[] values, int count) - { - _dense = values; - _count = count; - _index = -1; - } - public int Current => _dense[_index]; - object IEnumerator.Current => _dense[_index]; - public void Dispose() { } - public bool MoveNext() => ++_index < _count; - public void Reset() => _index = -1; - } - #endregion - - #region ICollection - bool ICollection.IsReadOnly => false; - - bool ICollection.Remove(int value) => TryRemove(value); - #endregion - - #region Debug - public string Log() - { - StringBuilder logbuild = new StringBuilder(); - for (int i = 0; i < CapacityDense; i++) - { - logbuild.Append(_dense[i] + ", "); - } - logbuild.Append("\n\r"); - for (int i = 0; i < CapacitySparse; i++) - { - logbuild.Append(_sparse[i] + ", "); - } - logbuild.Append("\n\r --------------------------"); - logbuild.Append("\n\r"); - for (int i = 0; i < CapacityDense; i++) - { - logbuild.Append((i < _count ? _dense[i].ToString() : "_") + ", "); - } - logbuild.Append("\n\r"); - for (int i = 0; i < CapacitySparse; i++) - { - logbuild.Append((_sparse[i] >= 0 ? _sparse[i].ToString() : "_") + ", "); - } - logbuild.Append("\n\r Count: " + _count); - logbuild.Append("\n\r Capacity: " + CapacitySparse); - logbuild.Append("\n\r IsValide: " + IsValide_Debug()); - - logbuild.Append("\n\r"); - return logbuild.ToString(); - } - - public bool IsValide_Debug() - { - bool isPass = true; - for (int index = 0; index < _count; index++) - { - int value = _dense[index]; - isPass = isPass && _sparse[value] == index; - } - return isPass; - } - -#if DEBUG - private static class ThrowHalper - { - public static void CheckCapacity(int capacity) - { - if (capacity < 0) - throw new ArgumentException("Capacity cannot be a negative number"); - } - public static void CheckValueIsPositive(int value) - { - if (value < 0) - throw new ArgumentException("The SparseSet can only contain positive numbers"); - } - public static void CheckValueContained(SparseSet source, int value) - { - if (!source.Contains(value)) - throw new ArgumentException($"Value {value} is not contained"); - } - public static void CheckValueNotContained(SparseSet source, int value) - { - if (source.Contains(value)) - throw new ArgumentException($"Value {value} is already contained"); - } - public static void CheckOutOfRange(SparseSet source, int index) - { - if (index < 0 || index >= source.Count) - throw new ArgumentOutOfRangeException($"Index {index} was out of range. Must be non-negative and less than the size of the collection."); - } - } -#endif - #endregion - } -} \ No newline at end of file