2025-03-14 16:53:25 +08:00
|
|
|
|
#if DISABLE_DEBUG
|
|
|
|
|
#undef DEBUG
|
|
|
|
|
#endif
|
|
|
|
|
using System;
|
2023-06-29 00:56:26 +08:00
|
|
|
|
using System.Collections;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.Runtime.CompilerServices;
|
|
|
|
|
|
2025-05-18 10:52:24 +08:00
|
|
|
|
namespace DCFApixels.DragonECS.Core.Internal
|
2023-06-29 00:56:26 +08:00
|
|
|
|
{
|
2024-04-28 19:43:10 +08:00
|
|
|
|
#if ENABLE_IL2CPP
|
|
|
|
|
using Unity.IL2CPP.CompilerServices;
|
|
|
|
|
[Il2CppSetOption(Option.NullChecks, false)]
|
|
|
|
|
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
|
|
|
|
#endif
|
2023-06-29 00:56:26 +08:00
|
|
|
|
[Serializable]
|
|
|
|
|
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
2025-05-17 14:55:31 +08:00
|
|
|
|
[DebuggerDisplay("Count: {Count}")]
|
2024-04-28 19:43:10 +08:00
|
|
|
|
internal class IdDispenser : IEnumerable<int>, IReadOnlyCollection<int>
|
2023-06-29 00:56:26 +08:00
|
|
|
|
{
|
|
|
|
|
private const int MIN_SIZE = 4;
|
|
|
|
|
|
|
|
|
|
private int[] _dense = Array.Empty<int>();
|
2024-02-13 21:00:01 +08:00
|
|
|
|
private int[] _sparse = Array.Empty<int>(); //hibit free flag
|
2023-06-29 00:56:26 +08:00
|
|
|
|
|
2024-02-14 01:04:22 +08:00
|
|
|
|
private int _usedCount; //[uuuu| ]
|
|
|
|
|
private int _size; //[uuuu|ffffff]
|
2023-06-29 00:56:26 +08:00
|
|
|
|
|
|
|
|
|
private int _nullID;
|
|
|
|
|
|
|
|
|
|
#region Properties
|
|
|
|
|
/// <summary> Used Count </summary>
|
2024-02-13 21:00:01 +08:00
|
|
|
|
public int Count
|
|
|
|
|
{
|
2024-04-28 19:43:10 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-02-13 21:00:01 +08:00
|
|
|
|
get { return _usedCount; }
|
|
|
|
|
}
|
2025-03-24 19:29:58 +08:00
|
|
|
|
public int Capacity
|
2024-02-13 21:00:01 +08:00
|
|
|
|
{
|
2024-04-28 19:43:10 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-02-13 21:00:01 +08:00
|
|
|
|
get { return _size; }
|
|
|
|
|
}
|
|
|
|
|
public int NullID
|
|
|
|
|
{
|
2024-04-28 19:43:10 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-02-13 21:00:01 +08:00
|
|
|
|
get { return _nullID; }
|
|
|
|
|
}
|
2023-06-29 00:56:26 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
2024-02-13 21:00:01 +08:00
|
|
|
|
#region Constructors
|
|
|
|
|
public IdDispenser(int minCapacity = MIN_SIZE, int nullID = 0, ResizedHandler resizedHandler = null)
|
2023-06-29 00:56:26 +08:00
|
|
|
|
{
|
2024-02-13 21:00:01 +08:00
|
|
|
|
Resized += resizedHandler;
|
|
|
|
|
if (minCapacity < MIN_SIZE)
|
|
|
|
|
{
|
|
|
|
|
minCapacity = MIN_SIZE;
|
|
|
|
|
}
|
|
|
|
|
Resize(minCapacity);
|
2023-06-29 00:56:26 +08:00
|
|
|
|
SetNullID(nullID);
|
|
|
|
|
}
|
2024-02-13 21:00:01 +08:00
|
|
|
|
#endregion
|
2023-06-29 00:56:26 +08:00
|
|
|
|
|
2024-02-13 21:00:01 +08:00
|
|
|
|
#region Use/Reserve/Realese
|
2023-06-29 00:56:26 +08:00
|
|
|
|
/// <summary>Marks as used and returns next free id.</summary>
|
2024-02-15 20:28:38 +08:00
|
|
|
|
public int UseFree()
|
2023-06-29 00:56:26 +08:00
|
|
|
|
{
|
2024-02-13 21:00:01 +08:00
|
|
|
|
int ptr = _usedCount;
|
2024-02-15 20:28:38 +08:00
|
|
|
|
CheckIDOrUpsize(ptr);
|
2024-02-13 21:00:01 +08:00
|
|
|
|
int id = _dense[ptr];
|
|
|
|
|
Move_FromFree_ToUsed(id);
|
2023-06-29 00:56:26 +08:00
|
|
|
|
return id;
|
|
|
|
|
}
|
|
|
|
|
/// <summary>Marks as used a free or reserved id, after this id cannot be retrieved via UseFree.</summary>
|
2024-02-15 20:28:38 +08:00
|
|
|
|
public void Use(int id)
|
2023-06-29 00:56:26 +08:00
|
|
|
|
{
|
2024-02-15 20:28:38 +08:00
|
|
|
|
CheckIDOrUpsize(id);
|
2023-06-29 00:56:26 +08:00
|
|
|
|
#if DEBUG
|
2024-02-13 21:00:01 +08:00
|
|
|
|
if (IsUsed(id) || IsNullID(id))
|
2023-06-29 00:56:26 +08:00
|
|
|
|
{
|
2024-02-13 21:00:01 +08:00
|
|
|
|
if (IsNullID(id)) { ThrowHalper.ThrowIsNullID(id); }
|
|
|
|
|
else { ThrowHalper.ThrowIsAlreadyInUse(id); }
|
2023-06-29 00:56:26 +08:00
|
|
|
|
}
|
|
|
|
|
#endif
|
2024-02-13 21:00:01 +08:00
|
|
|
|
Move_FromFree_ToUsed(id);
|
2023-06-29 00:56:26 +08:00
|
|
|
|
}
|
2024-02-13 21:00:01 +08:00
|
|
|
|
|
2024-02-15 20:28:38 +08:00
|
|
|
|
public void Release(int id)
|
2023-06-29 00:56:26 +08:00
|
|
|
|
{
|
2024-02-15 20:28:38 +08:00
|
|
|
|
CheckIDOrUpsize(id);
|
2023-06-29 00:56:26 +08:00
|
|
|
|
#if DEBUG
|
2024-02-13 21:00:01 +08:00
|
|
|
|
if (IsFree(id) || IsNullID(id))
|
|
|
|
|
{
|
|
|
|
|
if (IsFree(id)) { ThrowHalper.ThrowIsNotUsed(id); }
|
|
|
|
|
else { ThrowHalper.ThrowIsNullID(id); }
|
|
|
|
|
}
|
2023-06-29 00:56:26 +08:00
|
|
|
|
#endif
|
2024-02-13 21:00:01 +08:00
|
|
|
|
Move_FromUsed_ToFree(id);
|
2023-06-29 00:56:26 +08:00
|
|
|
|
}
|
2024-02-13 21:00:01 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Range Methods
|
|
|
|
|
public void UseFreeRange(ref int[] array, int range)
|
2023-06-29 00:56:26 +08:00
|
|
|
|
{
|
2024-02-13 21:00:01 +08:00
|
|
|
|
if (array.Length < range)
|
|
|
|
|
{
|
|
|
|
|
Array.Resize(ref array, range);
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < range; i++)
|
|
|
|
|
{
|
|
|
|
|
array[i] = UseFree();
|
|
|
|
|
}
|
2023-06-29 00:56:26 +08:00
|
|
|
|
}
|
2024-02-13 21:00:01 +08:00
|
|
|
|
public void UseFreeRange(List<int> list, int range)
|
2023-06-29 00:56:26 +08:00
|
|
|
|
{
|
2024-02-13 21:00:01 +08:00
|
|
|
|
for (int i = 0; i < range; i++)
|
2023-06-29 00:56:26 +08:00
|
|
|
|
{
|
2024-02-13 21:00:01 +08:00
|
|
|
|
list.Add(UseFree());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
public void UseRange(IEnumerable<int> ids)
|
|
|
|
|
{
|
|
|
|
|
foreach (var item in ids)
|
|
|
|
|
{
|
|
|
|
|
Use(item);
|
2023-06-29 00:56:26 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
public void ReleaseRange(IEnumerable<int> ids)
|
|
|
|
|
{
|
|
|
|
|
foreach (var item in ids)
|
2024-02-13 21:00:01 +08:00
|
|
|
|
{
|
2023-06-29 00:56:26 +08:00
|
|
|
|
Release(item);
|
2024-02-13 21:00:01 +08:00
|
|
|
|
}
|
2023-06-29 00:56:26 +08:00
|
|
|
|
}
|
|
|
|
|
public void ReleaseAll()
|
|
|
|
|
{
|
|
|
|
|
_usedCount = 0;
|
2024-02-13 21:00:01 +08:00
|
|
|
|
for (int i = 0; i < _size; i++)
|
2023-06-29 00:56:26 +08:00
|
|
|
|
{
|
2024-02-14 15:00:07 +08:00
|
|
|
|
_sparse[i] = i;
|
2024-02-13 21:00:01 +08:00
|
|
|
|
_dense[i] = i;
|
2023-06-29 00:56:26 +08:00
|
|
|
|
}
|
|
|
|
|
SetNullID(_nullID);
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Checks
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-02-13 21:00:01 +08:00
|
|
|
|
public bool IsFree(int id)
|
|
|
|
|
{
|
2024-02-14 15:00:07 +08:00
|
|
|
|
return _sparse[id] >= _usedCount;
|
2024-02-13 21:00:01 +08:00
|
|
|
|
}
|
2023-06-29 00:56:26 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-02-13 21:00:01 +08:00
|
|
|
|
public bool IsUsed(int id)
|
|
|
|
|
{
|
2024-02-14 15:00:07 +08:00
|
|
|
|
return _sparse[id] < _usedCount;
|
2024-02-13 21:00:01 +08:00
|
|
|
|
}
|
2023-06-29 00:56:26 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-02-13 21:00:01 +08:00
|
|
|
|
public bool IsNullID(int id)
|
|
|
|
|
{
|
|
|
|
|
return id == _nullID;
|
|
|
|
|
}
|
2023-06-29 00:56:26 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Sort
|
|
|
|
|
/// <summary>O(n) Sort. n = Size. Allows the UseFree method to return denser ids.</summary>
|
|
|
|
|
public void Sort()
|
|
|
|
|
{
|
2024-02-13 21:00:01 +08:00
|
|
|
|
int usedIndex = 0;
|
|
|
|
|
int freeIndex = _usedCount;
|
2024-02-14 17:05:41 +08:00
|
|
|
|
for (int i = 0; i < _size; i++)
|
2023-06-29 00:56:26 +08:00
|
|
|
|
{
|
2024-02-14 15:00:07 +08:00
|
|
|
|
if (_sparse[i] < _usedCount)
|
2024-02-13 21:00:01 +08:00
|
|
|
|
{
|
|
|
|
|
_sparse[i] = usedIndex;
|
|
|
|
|
_dense[usedIndex++] = i;
|
|
|
|
|
}
|
|
|
|
|
else
|
2023-06-29 00:56:26 +08:00
|
|
|
|
{
|
2024-02-14 15:00:07 +08:00
|
|
|
|
_sparse[i] = freeIndex;
|
2024-02-13 21:00:01 +08:00
|
|
|
|
_dense[freeIndex++] = i;
|
2023-06-29 00:56:26 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
2024-02-15 20:28:38 +08:00
|
|
|
|
#region Upsize
|
2024-02-13 21:00:01 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
2024-02-15 20:28:38 +08:00
|
|
|
|
public void Upsize(int minSize)
|
2024-02-13 21:00:01 +08:00
|
|
|
|
{
|
|
|
|
|
if (minSize > _size)
|
|
|
|
|
{
|
2024-02-15 20:28:38 +08:00
|
|
|
|
Upsize_Internal(minSize);
|
2024-02-13 21:00:01 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Internal
|
2023-06-29 00:56:26 +08:00
|
|
|
|
private void SetNullID(int nullID)
|
|
|
|
|
{
|
|
|
|
|
_nullID = nullID;
|
|
|
|
|
if (nullID >= 0)
|
|
|
|
|
{
|
2024-02-15 20:28:38 +08:00
|
|
|
|
CheckIDOrUpsize(nullID);
|
2024-02-13 21:00:01 +08:00
|
|
|
|
Swap(nullID, _usedCount++);
|
2023-06-29 00:56:26 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-02-14 17:05:41 +08:00
|
|
|
|
internal bool IsValid()
|
2023-06-29 00:56:26 +08:00
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < _usedCount; i++)
|
|
|
|
|
{
|
|
|
|
|
if (_sparse[_dense[i]] != i || _dense[_sparse[i]] != i)
|
2024-02-13 21:00:01 +08:00
|
|
|
|
{
|
2023-06-29 00:56:26 +08:00
|
|
|
|
return false;
|
2024-02-13 21:00:01 +08:00
|
|
|
|
}
|
2023-06-29 00:56:26 +08:00
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2024-02-13 21:00:01 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-02-15 20:28:38 +08:00
|
|
|
|
private void CheckIDOrUpsize(int id)
|
2023-06-29 00:56:26 +08:00
|
|
|
|
{
|
2024-02-13 21:00:01 +08:00
|
|
|
|
if (id >= _size)
|
2023-06-29 00:56:26 +08:00
|
|
|
|
{
|
2024-02-15 20:28:38 +08:00
|
|
|
|
Upsize_Internal(id + 1);
|
2023-06-29 00:56:26 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-02-13 21:00:01 +08:00
|
|
|
|
private void Move_FromFree_ToUsed(int id)
|
2023-06-29 00:56:26 +08:00
|
|
|
|
{
|
2024-02-13 21:00:01 +08:00
|
|
|
|
Swap(id, _usedCount++);
|
2023-06-29 00:56:26 +08:00
|
|
|
|
}
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-02-13 21:00:01 +08:00
|
|
|
|
private void Move_FromUsed_ToFree(int id)
|
2023-06-29 00:56:26 +08:00
|
|
|
|
{
|
2024-02-13 21:00:01 +08:00
|
|
|
|
Swap(id, --_usedCount);
|
2023-06-29 00:56:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
private void Swap(int sparseIndex, int denseIndex)
|
|
|
|
|
{
|
|
|
|
|
int _dense_denseIndex_ = _dense[denseIndex];
|
2024-02-14 15:00:07 +08:00
|
|
|
|
int _sparse_sparseIndex_ = _sparse[sparseIndex];
|
2023-06-29 00:56:26 +08:00
|
|
|
|
_dense[denseIndex] = _dense[_sparse_sparseIndex_];
|
|
|
|
|
_dense[_sparse_sparseIndex_] = _dense_denseIndex_;
|
|
|
|
|
_sparse[_dense_denseIndex_] = _sparse_sparseIndex_;
|
|
|
|
|
_sparse[sparseIndex] = denseIndex;
|
|
|
|
|
}
|
2024-02-13 21:00:01 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
2024-02-15 20:28:38 +08:00
|
|
|
|
private void Upsize_Internal(int minSize)
|
2024-02-13 21:00:01 +08:00
|
|
|
|
{
|
2025-03-19 11:18:25 +08:00
|
|
|
|
Resize(ArrayUtility.NextPow2_ClampOverflow(minSize));
|
2024-02-13 21:00:01 +08:00
|
|
|
|
}
|
2023-06-29 00:56:26 +08:00
|
|
|
|
private void Resize(int newSize)
|
|
|
|
|
{
|
|
|
|
|
Array.Resize(ref _dense, newSize);
|
|
|
|
|
Array.Resize(ref _sparse, newSize);
|
|
|
|
|
for (int i = _size; i < newSize;)
|
|
|
|
|
{
|
2024-02-14 15:00:07 +08:00
|
|
|
|
_sparse[i] = i;
|
2023-06-29 00:56:26 +08:00
|
|
|
|
_dense[i] = i++;
|
|
|
|
|
}
|
|
|
|
|
_size = newSize;
|
|
|
|
|
Resized(newSize);
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
2024-02-13 21:00:01 +08:00
|
|
|
|
#region Enumerable
|
2024-09-07 17:18:35 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
public Enumerator GetEnumerator() { return new Enumerator(_dense, 0, _usedCount); }
|
2024-02-13 21:00:01 +08:00
|
|
|
|
IEnumerator<int> IEnumerable<int>.GetEnumerator() { return GetEnumerator(); }
|
|
|
|
|
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
|
2023-06-29 00:56:26 +08:00
|
|
|
|
public struct Enumerator : IEnumerator<int>
|
|
|
|
|
{
|
|
|
|
|
private readonly int[] _dense;
|
|
|
|
|
private readonly int _count;
|
|
|
|
|
private int _index;
|
2024-09-07 17:18:35 +08:00
|
|
|
|
public int Current
|
|
|
|
|
{
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
get { return _dense[_index]; }
|
|
|
|
|
}
|
|
|
|
|
object IEnumerator.Current { get { return Current; } }
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2023-06-29 00:56:26 +08:00
|
|
|
|
public Enumerator(int[] dense, int startIndex, int count)
|
|
|
|
|
{
|
|
|
|
|
_dense = dense;
|
|
|
|
|
_count = startIndex + count;
|
|
|
|
|
_index = startIndex - 1;
|
|
|
|
|
}
|
2024-09-07 17:18:35 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
public bool MoveNext() { return ++_index < _count; }
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
void IDisposable.Dispose() { }
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
public void Reset() { _index = -1; }
|
2023-06-29 00:56:26 +08:00
|
|
|
|
}
|
2024-02-13 21:00:01 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region UsedToEcsSpan
|
2024-04-16 12:46:09 +08:00
|
|
|
|
public EcsSpan UsedToEcsSpan(short worldID)
|
2024-02-13 21:00:01 +08:00
|
|
|
|
{
|
|
|
|
|
return new EcsSpan(worldID, _dense, 1, _usedCount - 1);
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
2023-06-29 00:56:26 +08:00
|
|
|
|
#region Utils
|
2024-02-13 21:00:01 +08:00
|
|
|
|
private enum IDState : byte
|
|
|
|
|
{
|
|
|
|
|
Free = 0,
|
|
|
|
|
Reserved = 1,
|
|
|
|
|
Used = 2,
|
|
|
|
|
}
|
2023-06-29 00:56:26 +08:00
|
|
|
|
private static class ThrowHalper
|
|
|
|
|
{
|
|
|
|
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
2024-09-07 17:18:35 +08:00
|
|
|
|
public static void ThrowIsAlreadyInUse(int id) { throw new ArgumentException($"Id {id} is already in use."); }
|
2023-06-29 00:56:26 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
2024-09-07 17:18:35 +08:00
|
|
|
|
public static void ThrowIsHasBeenReserved(int id) { throw new ArgumentException($"Id {id} has been reserved."); }
|
2023-06-29 00:56:26 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
2024-09-07 17:18:35 +08:00
|
|
|
|
public static void ThrowIsNotUsed(int id) { throw new ArgumentException($"Id {id} is not used."); }
|
2023-06-29 00:56:26 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
2024-09-07 17:18:35 +08:00
|
|
|
|
public static void ThrowIsNotAvailable(int id) { throw new ArgumentException($"Id {id} is not available."); }
|
2023-06-29 00:56:26 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
2024-09-07 17:18:35 +08:00
|
|
|
|
public static void ThrowIsNullID(int id) { throw new ArgumentException($"Id {id} cannot be released because it is used as a null id."); }
|
2024-02-13 21:00:01 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
|
|
|
|
public static void UndefinedException() { throw new Exception(); }
|
2023-06-29 00:56:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-02-14 01:04:22 +08:00
|
|
|
|
private class DebuggerProxy
|
2023-06-29 00:56:26 +08:00
|
|
|
|
{
|
2024-02-13 21:00:01 +08:00
|
|
|
|
private IdDispenser _target;
|
|
|
|
|
public DebuggerProxy(IdDispenser dispenser)
|
|
|
|
|
{
|
|
|
|
|
_target = dispenser;
|
|
|
|
|
}
|
2023-06-29 00:56:26 +08:00
|
|
|
|
#if DEBUG
|
2024-02-13 21:00:01 +08:00
|
|
|
|
public ReadOnlySpan<int> Used => new ReadOnlySpan<int>(_target._dense, 0, _target._usedCount);
|
2024-02-14 01:04:22 +08:00
|
|
|
|
public ReadOnlySpan<int> Free => new ReadOnlySpan<int>(_target._dense, _target._usedCount, _target._size - _target._usedCount);
|
2023-06-29 00:56:26 +08:00
|
|
|
|
public Pair[] Pairs
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2025-03-24 19:29:58 +08:00
|
|
|
|
Pair[] result = new Pair[_target.Capacity];
|
2023-06-29 00:56:26 +08:00
|
|
|
|
for (int i = 0; i < result.Length; i++)
|
2024-02-14 17:05:41 +08:00
|
|
|
|
{
|
|
|
|
|
result[i] = new Pair(
|
|
|
|
|
_target._dense[i],
|
|
|
|
|
_target._sparse[i],
|
|
|
|
|
i < _target.Count);
|
|
|
|
|
}
|
2023-06-29 00:56:26 +08:00
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
public ID[] All
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2025-03-24 19:29:58 +08:00
|
|
|
|
ID[] result = new ID[_target.Capacity];
|
2023-06-29 00:56:26 +08:00
|
|
|
|
for (int i = 0; i < result.Length; i++)
|
|
|
|
|
{
|
2024-02-13 21:00:01 +08:00
|
|
|
|
int id = _target._dense[i];
|
|
|
|
|
result[i] = new ID(id, _target.IsUsed(id) ? "Used" : "Free");
|
2023-06-29 00:56:26 +08:00
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-02-13 21:00:01 +08:00
|
|
|
|
public bool IsValid => _target.IsValid();
|
|
|
|
|
public int Count => _target.Count;
|
2025-03-24 19:29:58 +08:00
|
|
|
|
public int Capacity => _target.Capacity;
|
2024-02-13 21:00:01 +08:00
|
|
|
|
public int NullID => _target._nullID;
|
2023-06-29 00:56:26 +08:00
|
|
|
|
internal readonly struct ID
|
|
|
|
|
{
|
|
|
|
|
public readonly int id;
|
|
|
|
|
public readonly string state;
|
|
|
|
|
public ID(int id, string state) { this.id = id; this.state = state; }
|
|
|
|
|
public override string ToString() => $"{id} - {state}";
|
|
|
|
|
}
|
2024-02-14 17:05:41 +08:00
|
|
|
|
[DebuggerDisplay("{Separator} -> {sparse} - {dense}")]
|
2023-06-29 00:56:26 +08:00
|
|
|
|
internal readonly struct Pair
|
|
|
|
|
{
|
|
|
|
|
public readonly int sparse;
|
2024-02-14 17:05:41 +08:00
|
|
|
|
public readonly int dense;
|
|
|
|
|
public readonly bool isSeparator;
|
|
|
|
|
public int Separator => isSeparator ? 1 : 0;
|
|
|
|
|
public Pair(int dense, int sparse, bool isSeparator)
|
|
|
|
|
{
|
|
|
|
|
this.dense = dense;
|
|
|
|
|
this.sparse = sparse;
|
|
|
|
|
this.isSeparator = isSeparator;
|
|
|
|
|
}
|
|
|
|
|
//public override string ToString() => $"{sparse} - {dense} { (isSeparator ? '>' : ' ') } ";
|
2023-06-29 00:56:26 +08:00
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
2024-02-13 21:00:01 +08:00
|
|
|
|
|
|
|
|
|
#region Events
|
|
|
|
|
public delegate void ResizedHandler(int newSize);
|
|
|
|
|
public event ResizedHandler Resized = delegate { };
|
|
|
|
|
#endregion
|
2023-06-29 00:56:26 +08:00
|
|
|
|
}
|
|
|
|
|
}
|