mirror of
https://github.com/DCFApixels/DragonECS-Graphs.git
synced 2025-09-17 19:24:36 +08:00
update
This commit is contained in:
parent
e2b68d2b08
commit
cde2952bf9
@ -3,7 +3,7 @@ using System;
|
|||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
public static class EcsGraphExtensions
|
public static class EntityGraphExtensions
|
||||||
{
|
{
|
||||||
private static EntityGraph[] _worldGraphs = new EntityGraph[4];
|
private static EntityGraph[] _worldGraphs = new EntityGraph[4];
|
||||||
|
|
@ -27,12 +27,15 @@ namespace DCFApixels.DragonECS
|
|||||||
private LinkedList _linkedList;
|
private LinkedList _linkedList;
|
||||||
private LinkedListHead[] _linkedListSourceHeads;
|
private LinkedListHead[] _linkedListSourceHeads;
|
||||||
|
|
||||||
private int[] _startEntities;
|
private int[] _sourceEntities;
|
||||||
private int _startEntitiesCount;
|
private int _sourceEntitiesCount;
|
||||||
|
|
||||||
private int _targetWorldCapacity = -1;
|
private int _targetWorldCapacity = -1;
|
||||||
private EcsProfilerMarker _executeMarker = new EcsProfilerMarker("Join");
|
private EcsProfilerMarker _executeMarker = new EcsProfilerMarker("Join");
|
||||||
|
|
||||||
|
public bool _isDestroyed = false;
|
||||||
|
|
||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
public sealed override long Version
|
public sealed override long Version
|
||||||
{
|
{
|
||||||
@ -62,13 +65,17 @@ namespace DCFApixels.DragonECS
|
|||||||
_versionsChecker = new WorldStateVersionsChecker(Mask);
|
_versionsChecker = new WorldStateVersionsChecker(Mask);
|
||||||
_linkedList = new OnlyAppendHeadLinkedList(World.Capacity);
|
_linkedList = new OnlyAppendHeadLinkedList(World.Capacity);
|
||||||
_linkedListSourceHeads = new LinkedListHead[World.Capacity];
|
_linkedListSourceHeads = new LinkedListHead[World.Capacity];
|
||||||
|
_sourceEntities = new int[World.Capacity * 2];
|
||||||
World.AddListener(this);
|
World.AddListener(this);
|
||||||
_graph = World.GetGraph();
|
_graph = World.GetGraph();
|
||||||
_iterator = Mask.GetIterator();
|
_iterator = Mask.GetIterator();
|
||||||
}
|
}
|
||||||
protected override void OnDestroy()
|
protected override void OnDestroy()
|
||||||
{
|
{
|
||||||
|
if (_isDestroyed) { return; }
|
||||||
|
_isDestroyed = true;
|
||||||
World.RemoveListener(this);
|
World.RemoveListener(this);
|
||||||
|
_versionsChecker.Dispose();
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -79,24 +86,16 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
World.ReleaseDelEntityBufferAllAuto();
|
World.ReleaseDelEntityBufferAllAuto();
|
||||||
|
|
||||||
if (Mask.IsEmpty)
|
if (Mask.IsEmpty || _versionsChecker.CheckAndNext() == false)
|
||||||
{
|
|
||||||
_filteredAllEntitiesCount = World.Entities.ToArray(ref _filteredAllEntities);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (_versionsChecker.CheckAndNext() == false)
|
|
||||||
{
|
{
|
||||||
_filteredAllEntitiesCount = _iterator.IterateTo(World.Entities, ref _filteredAllEntities);
|
_filteredAllEntitiesCount = _iterator.IterateTo(World.Entities, ref _filteredAllEntities);
|
||||||
////Подготовка массивов
|
//Подготовка массивов
|
||||||
//if (_startEntities.Length < _filteredAllEntitiesCount * 2)
|
if (_sourceEntities.Length < _filteredAllEntitiesCount * 2)
|
||||||
//{
|
{
|
||||||
// _startEntities = new int[_filteredAllEntitiesCount * 2];
|
_sourceEntities = new int[_filteredAllEntitiesCount * 2];
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//установка текущего массива
|
//установка текущего массива
|
||||||
_currentFilteredEntities = _filteredAllEntities;
|
_currentFilteredEntities = _filteredAllEntities;
|
||||||
_currentFilteredEntitiesCount = _filteredAllEntitiesCount;
|
_currentFilteredEntitiesCount = _filteredAllEntitiesCount;
|
||||||
@ -106,13 +105,17 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
_targetWorldCapacity = World.Capacity;
|
_targetWorldCapacity = World.Capacity;
|
||||||
_linkedListSourceHeads = new LinkedListHead[_targetWorldCapacity];
|
_linkedListSourceHeads = new LinkedListHead[_targetWorldCapacity];
|
||||||
_startEntities = new int[_targetWorldCapacity];
|
//_startEntities = new int[_targetWorldCapacity];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ArrayUtility.Fill(_linkedListSourceHeads, default); //TODO оптимизировать, сделав не полную отчистку а только по элементов с прошлого раза
|
//ArrayUtility.Fill(_linkedListSourceHeads, default); //TODO оптимизировать, сделав не полную отчистку а только по элементов с прошлого раза
|
||||||
|
for (int i = 0; i < _sourceEntitiesCount; i++)
|
||||||
|
{
|
||||||
|
_linkedListSourceHeads[_sourceEntities[i]] = default;
|
||||||
}
|
}
|
||||||
_startEntitiesCount = 0;
|
}
|
||||||
|
_sourceEntitiesCount = 0;
|
||||||
_linkedList.Clear();
|
_linkedList.Clear();
|
||||||
|
|
||||||
//Заполнение массивов
|
//Заполнение массивов
|
||||||
@ -249,7 +252,7 @@ namespace DCFApixels.DragonECS
|
|||||||
ref var basket = ref _linkedListSourceHeads[sourceEntityID];
|
ref var basket = ref _linkedListSourceHeads[sourceEntityID];
|
||||||
if (basket.head == 0)
|
if (basket.head == 0)
|
||||||
{
|
{
|
||||||
_startEntities[_startEntitiesCount++] = sourceEntityID;
|
_sourceEntities[_sourceEntitiesCount++] = sourceEntityID;
|
||||||
basket.head = _linkedList.NewHead(relationEntityID);
|
basket.head = _linkedList.NewHead(relationEntityID);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -309,7 +312,7 @@ namespace DCFApixels.DragonECS
|
|||||||
#region GetEntites
|
#region GetEntites
|
||||||
internal EcsSpan GetSourceEntities()
|
internal EcsSpan GetSourceEntities()
|
||||||
{
|
{
|
||||||
return UncheckedCoreUtility.CreateSpan(WorldID, _startEntities, _startEntitiesCount);
|
return UncheckedCoreUtility.CreateSpan(WorldID, _sourceEntities, _sourceEntitiesCount);
|
||||||
}
|
}
|
||||||
internal EcsSpan GetRelEntities()
|
internal EcsSpan GetRelEntities()
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
@ -46,64 +43,18 @@ namespace DCFApixels.DragonECS.Graphs.Internal
|
|||||||
{
|
{
|
||||||
return 1 << (GetHighBitNumber((uint)minSize - 1u) + 1);
|
return 1 << (GetHighBitNumber((uint)minSize - 1u) + 1);
|
||||||
}
|
}
|
||||||
public static void Fill<T>(T[] array, T value, int startIndex = 0, int length = -1)
|
|
||||||
{
|
|
||||||
if (length < 0)
|
|
||||||
{
|
|
||||||
length = array.Length;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
length = startIndex + length;
|
|
||||||
}
|
|
||||||
for (int i = startIndex; i < length; i++)
|
|
||||||
{
|
|
||||||
array[i] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
internal readonly struct EnumerableInt : IEnumerable<int>
|
|
||||||
{
|
|
||||||
public readonly int start;
|
|
||||||
public readonly int length;
|
|
||||||
private EnumerableInt(int start, int length)
|
|
||||||
{
|
|
||||||
this.start = start;
|
|
||||||
this.length = length;
|
|
||||||
}
|
|
||||||
public static EnumerableInt Range(int start, int length) => new EnumerableInt(start, length);
|
|
||||||
public static EnumerableInt StartEnd(int start, int end) => new EnumerableInt(start, end - start);
|
|
||||||
IEnumerator<int> IEnumerable<int>.GetEnumerator() => GetEnumerator();
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public Enumerator GetEnumerator() => new Enumerator(start, start + length);
|
|
||||||
public struct Enumerator : IEnumerator<int>
|
|
||||||
{
|
|
||||||
private readonly int _max;
|
|
||||||
private int _current;
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public Enumerator(int max, int current)
|
|
||||||
{
|
|
||||||
_max = max;
|
|
||||||
_current = current - 1;
|
|
||||||
}
|
|
||||||
public int Current
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get => _current;
|
|
||||||
}
|
|
||||||
object IEnumerator.Current => Current;
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool MoveNext() => ++_current < _max;
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void Reset() { }
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void Dispose() { }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
internal static unsafe class UnmanagedArrayUtility
|
internal static unsafe class UnmanagedArrayUtility
|
||||||
{
|
{
|
||||||
|
private static class MetaCache<T>
|
||||||
|
{
|
||||||
|
public readonly static int Size;
|
||||||
|
static MetaCache()
|
||||||
|
{
|
||||||
|
T def = default;
|
||||||
|
Size = Marshal.SizeOf(def);
|
||||||
|
}
|
||||||
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static T* New<T>(int capacity) where T : unmanaged
|
public static T* New<T>(int capacity) where T : unmanaged
|
||||||
{
|
{
|
||||||
@ -112,28 +63,32 @@ namespace DCFApixels.DragonECS.Graphs.Internal
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void New<T>(out T* ptr, int capacity) where T : unmanaged
|
public static void New<T>(out T* ptr, int capacity) where T : unmanaged
|
||||||
{
|
{
|
||||||
ptr = (T*)Marshal.AllocHGlobal(Marshal.SizeOf<T>(default) * capacity).ToPointer();
|
ptr = (T*)Marshal.AllocHGlobal(Marshal.SizeOf<T>() * capacity).ToPointer();
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static T* NewAndInit<T>(int capacity) where T : unmanaged
|
public static T* NewAndInit<T>(int capacity) where T : unmanaged
|
||||||
{
|
{
|
||||||
int newSize = Marshal.SizeOf(typeof(T)) * capacity;
|
int newSize = MetaCache<T>.Size * capacity;
|
||||||
byte* newPointer = (byte*)Marshal.AllocHGlobal(newSize).ToPointer();
|
byte* newPointer = (byte*)Marshal.AllocHGlobal(newSize).ToPointer();
|
||||||
|
|
||||||
for (int i = 0; i < newSize; i++)
|
for (int i = 0; i < newSize; i++)
|
||||||
|
{
|
||||||
*(newPointer + i) = 0;
|
*(newPointer + i) = 0;
|
||||||
|
}
|
||||||
|
|
||||||
return (T*)newPointer;
|
return (T*)newPointer;
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void NewAndInit<T>(out T* ptr, int capacity) where T : unmanaged
|
public static void NewAndInit<T>(out T* ptr, int capacity) where T : unmanaged
|
||||||
{
|
{
|
||||||
int newSize = Marshal.SizeOf(typeof(T)) * capacity;
|
int newSize = MetaCache<T>.Size * capacity;
|
||||||
byte* newPointer = (byte*)Marshal.AllocHGlobal(newSize).ToPointer();
|
byte* newPointer = (byte*)Marshal.AllocHGlobal(newSize).ToPointer();
|
||||||
|
|
||||||
for (int i = 0; i < newSize; i++)
|
for (int i = 0; i < newSize; i++)
|
||||||
|
{
|
||||||
*(newPointer + i) = 0;
|
*(newPointer + i) = 0;
|
||||||
|
}
|
||||||
|
|
||||||
ptr = (T*)newPointer;
|
ptr = (T*)newPointer;
|
||||||
}
|
}
|
||||||
@ -167,12 +122,12 @@ namespace DCFApixels.DragonECS.Graphs.Internal
|
|||||||
{
|
{
|
||||||
return (T*)Marshal.ReAllocHGlobal(
|
return (T*)Marshal.ReAllocHGlobal(
|
||||||
new IntPtr(oldPointer),
|
new IntPtr(oldPointer),
|
||||||
new IntPtr(Marshal.SizeOf<T>(default) * newCount)).ToPointer();
|
new IntPtr(MetaCache<T>.Size * newCount)).ToPointer();
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static T* ResizeAndInit<T>(void* oldPointer, int oldSize, int newSize) where T : unmanaged
|
public static T* ResizeAndInit<T>(void* oldPointer, int oldSize, int newSize) where T : unmanaged
|
||||||
{
|
{
|
||||||
int sizeT = Marshal.SizeOf<T>(default);
|
int sizeT = MetaCache<T>.Size;
|
||||||
T* result = (T*)Marshal.ReAllocHGlobal(
|
T* result = (T*)Marshal.ReAllocHGlobal(
|
||||||
new IntPtr(oldPointer),
|
new IntPtr(oldPointer),
|
||||||
new IntPtr(sizeT * newSize)).ToPointer();
|
new IntPtr(sizeT * newSize)).ToPointer();
|
||||||
@ -189,16 +144,4 @@ namespace DCFApixels.DragonECS.Graphs.Internal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class CollectionUtility
|
|
||||||
{
|
|
||||||
public static string EntitiesToString(IEnumerable<int> range, string name)
|
|
||||||
{
|
|
||||||
return $"{name}({range.Count()}) {{{string.Join(", ", range.OrderBy(o => o))}}})";
|
|
||||||
}
|
|
||||||
public static string AutoToString<T>(IEnumerable<T> range, string name)
|
|
||||||
{
|
|
||||||
return $"{name}({range.Count()}) {{{string.Join(", ", range.Select(o => o.ToString()))}}})";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load Diff
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 20978cdfe73c32d49952cb225e32a5b8
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -55,7 +55,17 @@ namespace DCFApixels.DragonECS.Graphs.Internal
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool Equals(RelationInfo other) { return this == other; }
|
public bool Equals(RelationInfo other) { return this == other; }
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public override int GetHashCode() { return start ^ BitsUtility.NextXorShiftState(end); }
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
unchecked
|
||||||
|
{
|
||||||
|
uint endHash = (uint)end;
|
||||||
|
endHash ^= endHash << 13;
|
||||||
|
endHash ^= endHash >> 17;
|
||||||
|
endHash ^= endHash << 5;
|
||||||
|
return start ^ (int)endHash;
|
||||||
|
}
|
||||||
|
}
|
||||||
public override string ToString() { return $"arc({start} -> {end})"; }
|
public override string ToString() { return $"arc({start} -> {end})"; }
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
@ -1,217 +0,0 @@
|
|||||||
//SparseArray. Analogous to Dictionary<int, T>, 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.Graphs.Internal
|
|
||||||
{
|
|
||||||
internal class SparseArray<TValue>
|
|
||||||
{
|
|
||||||
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<int>();
|
|
||||||
private Entry[] _entries = Array.Empty<Entry>();
|
|
||||||
|
|
||||||
private int _count;
|
|
||||||
|
|
||||||
private int _freeList;
|
|
||||||
private int _freeCount;
|
|
||||||
|
|
||||||
private int _modBitMask;
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
public TValue this[int keyX, int keyY]
|
|
||||||
{
|
|
||||||
get => _entries[FindEntry((keyX << 32) | keyY)].value;
|
|
||||||
set => Insert(keyX + (keyY << 32), value);
|
|
||||||
}
|
|
||||||
public TValue this[int key]
|
|
||||||
{
|
|
||||||
get => _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/Contains/Remove
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void Add(int keyX, int keyY, TValue value) => Add((keyX << 32) | keyY, value);
|
|
||||||
[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);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Contains(int keyX, int keyY) => FindEntry((keyX << 32) | keyY) >= 0;
|
|
||||||
public bool Contains(int key) => FindEntry(key) >= 0;
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool Remove(int keyX, int keyY) => Remove((keyX << 32) | keyY);
|
|
||||||
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 Find/Insert
|
|
||||||
[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;
|
|
||||||
}
|
|
||||||
#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 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 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
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: c3dd2571d8641a142a77b4dc93c8a33b
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
Loading…
Reference in New Issue
Block a user