mirror of
https://github.com/DCFApixels/DragonECS.git
synced 2025-09-18 01:44:35 +08:00
fix changes
This commit is contained in:
parent
c0b1d8ba5b
commit
e7835a39d3
30
src/Builtin/Components.cs
Normal file
30
src/Builtin/Components.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
/// <summary>
|
||||
/// Используется для реализации отношений. traget - это сущьность к которой крепится эта сущьность. other - это сущьность с которой traget образует связь
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Explicit, Pack = 8, Size = 16)]
|
||||
public readonly struct Attach
|
||||
{
|
||||
[FieldOffset(0), MarshalAs(UnmanagedType.U8)]
|
||||
public readonly EcsEntity target;
|
||||
[FieldOffset(1), MarshalAs(UnmanagedType.U8)]
|
||||
public readonly EcsEntity other;
|
||||
|
||||
/// <summary>alias for "target"</summary>
|
||||
public EcsEntity left
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => target;
|
||||
}
|
||||
/// <summary>alias for "other"</summary>
|
||||
public EcsEntity right
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => other;
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Unity.Profiling;
|
||||
using UnityEngine;
|
||||
using delayedOp = System.Int32;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
@ -10,7 +11,6 @@ namespace DCFApixels.DragonECS
|
||||
public readonly ref struct EcsReadonlyGroup
|
||||
{
|
||||
private readonly EcsGroup _source;
|
||||
|
||||
#region Constructors
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public EcsReadonlyGroup(EcsGroup source) => _source = source;
|
||||
@ -49,11 +49,8 @@ namespace DCFApixels.DragonECS
|
||||
public bool Contains(int entityID) => _source.Contains(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public EcsGroup.Enumerator GetEnumerator() => _source.GetEnumerator();
|
||||
|
||||
/// <summary>Equivalent of the EcsGroup.Clone() method</summary>
|
||||
/// <returns>An editable clone of this EcsReadnolyGroup</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public EcsGroup Extract() => _source.Clone();
|
||||
public EcsGroup Clone() => _source.Clone();
|
||||
#endregion
|
||||
|
||||
#region Object
|
||||
@ -80,23 +77,10 @@ namespace DCFApixels.DragonECS
|
||||
public static bool operator !=(EcsReadonlyGroup a, EcsReadonlyGroup b) => !a.Equals(b);
|
||||
public static bool operator !=(EcsReadonlyGroup a, EcsGroup b) => !a.Equals(b);
|
||||
#endregion
|
||||
|
||||
#region Dispose/Release
|
||||
public void Dispose()
|
||||
{
|
||||
_source.Dispose();
|
||||
}
|
||||
public void Release()
|
||||
{
|
||||
_source.World.ReleaseGroup(_source);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
// не может содержать значение 0
|
||||
// индексация начинается с 1
|
||||
// _delayedOps это int[] для отложенных операций, хранятся отложенные операции в виде int значения, если старший бит = 0 то это опреация добавленияб если = 1 то это операция вычитания
|
||||
|
||||
// this collection can only store numbers greater than 0
|
||||
public unsafe class EcsGroup : IDisposable, IEquatable<EcsGroup>
|
||||
{
|
||||
private const int DEALAYED_ADD = 0;
|
||||
@ -145,7 +129,8 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Constrcutors
|
||||
#region Constrcutors/Finalizer
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static EcsGroup New(IEcsWorld world)
|
||||
{
|
||||
return world.GetGroupFromPool();
|
||||
@ -164,6 +149,14 @@ namespace DCFApixels.DragonECS
|
||||
_delayedOpsCount = 0;
|
||||
_count = 0;
|
||||
}
|
||||
|
||||
//защита от криворукости
|
||||
//перед сборкой мусора снова создает сильную ссылку и возвращает в пул
|
||||
//TODO переделат ьиил удалить, так как сборщик мусора просыпается только после 12к и более экземпляров, только тогда и вызывается финализатор, слишком жирно
|
||||
~EcsGroup()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Contains
|
||||
@ -256,12 +249,10 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_count = 0;
|
||||
for (int i = 0; i < _dense.Length; i++)
|
||||
_dense[i] = 0;
|
||||
//массив _dense нет смысла очищать, испольщуется только область от 1 до _count
|
||||
for (int i = 0; i < _sparse.Length; i++)
|
||||
_sparse[i] = 0;
|
||||
}
|
||||
@ -275,6 +266,7 @@ namespace DCFApixels.DragonECS
|
||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
||||
if (group.World != _source) throw new ArgumentException("groupFilter.World != World");
|
||||
#endif
|
||||
if(_count > 0)
|
||||
Clear();
|
||||
foreach (var item in group)
|
||||
AggressiveAdd(item.id);
|
||||
@ -428,14 +420,14 @@ namespace DCFApixels.DragonECS
|
||||
#region Enumerator
|
||||
public ref struct Enumerator// : IDisposable
|
||||
{
|
||||
// private readonly EcsGroup _source;
|
||||
// private readonly EcsGroup source;
|
||||
private readonly int[] _dense;
|
||||
private readonly int _count;
|
||||
private int _index;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Enumerator(EcsGroup group)
|
||||
{
|
||||
// _source = group;
|
||||
// source = group;
|
||||
_dense = group._dense;
|
||||
_count = group.Count;
|
||||
_index = 0;
|
||||
@ -448,7 +440,7 @@ namespace DCFApixels.DragonECS
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool MoveNext() => ++_index <= _count && _count<_dense.Length; // <= потму что отсчет начинается с индекса 1 //_count < _dense.Length дает среде понять что проверки на выход за границы не нужны
|
||||
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
//public void Dispose() => _source.Unlock();
|
||||
//public void Dispose() => source.Unlock();
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
@ -357,27 +357,27 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
static Activator()
|
||||
{
|
||||
// var inc = new TInc().GetComponentsIDs<TWorldArchetype>();
|
||||
// var exc = new TExc().GetComponentsIDs<TWorldArchetype>();
|
||||
// Array.Sort(inc);
|
||||
// Array.Sort(exc);
|
||||
// var inc_ = new TInc().GetComponentsIDs<TWorldArchetype>();
|
||||
// var exc_ = new TExc().GetComponentsIDs<TWorldArchetype>();
|
||||
// Array.Sort(inc_);
|
||||
// Array.Sort(exc_);
|
||||
//
|
||||
// Type thisType = typeof(Activator<TInc, TExc>);
|
||||
//
|
||||
// Type sortedIncType = typeof(TInc);
|
||||
// if (sortedIncType.IsGenericType)
|
||||
// {
|
||||
// Type[] sortedInc = new Type[inc.Length];
|
||||
// Type[] sortedInc = new Type[inc_.Length];
|
||||
// for (int i = 0; i < sortedInc.Length; i++)
|
||||
// sortedInc[i] = EcsWorld<TWorldArchetype>.ComponentType.types[inc[i]];
|
||||
// sortedInc[i] = EcsWorld<TWorldArchetype>.ComponentType.types[inc_[i]];
|
||||
// sortedIncType = sortedIncType.GetGenericTypeDefinition().MakeGenericType(sortedInc);
|
||||
// }
|
||||
// Type sortedExcType = typeof(TExc);
|
||||
// if (sortedExcType.IsGenericType)
|
||||
// {
|
||||
// Type[] sortedExc = new Type[exc.Length];
|
||||
// Type[] sortedExc = new Type[exc_.Length];
|
||||
// for (int i = 0; i < sortedExc.Length; i++)
|
||||
// sortedExc[i] = EcsWorld<TWorldArchetype>.ComponentType.types[exc[i]];
|
||||
// sortedExc[i] = EcsWorld<TWorldArchetype>.ComponentType.types[exc_[i]];
|
||||
// sortedExcType = sortedExcType.GetGenericTypeDefinition().MakeGenericType(sortedExc);
|
||||
// }
|
||||
//
|
||||
@ -393,7 +393,7 @@ namespace DCFApixels.DragonECS
|
||||
// if (_count >= _capacity)
|
||||
// _capacity <<= 1;
|
||||
//
|
||||
// instance = new EcsMask(typeof(TWorldArchetype), id, inc, exc);
|
||||
// instance = new EcsMask(typeof(TWorldArchetype), id, inc_, exc_);
|
||||
}
|
||||
|
||||
public readonly static EcsMask instance;
|
||||
|
@ -1,21 +1,25 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Unity.Profiling;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public interface IEcsPool
|
||||
{
|
||||
#region Properties
|
||||
public Type ComponentType { get; }
|
||||
public int ComponentID { get; }
|
||||
public IEcsWorld World { get; }
|
||||
public int Count { get; }
|
||||
public int Capacity { get; }
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
public bool Has(int entityID);
|
||||
public void Write(int entityID);
|
||||
public void Del(int entityID);
|
||||
internal void OnWorldResize(int newSize);
|
||||
#endregion
|
||||
}
|
||||
public interface IEcsPool<T> : IEcsPool where T : struct
|
||||
{
|
||||
@ -28,13 +32,18 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
public static EcsNullPool instance => new EcsNullPool(null);
|
||||
private IEcsWorld _source;
|
||||
private EcsNullPool(IEcsWorld source) => _source = source;
|
||||
private NullComponent fakeComponent;
|
||||
private EcsNullPool(IEcsWorld source) => _source = source;
|
||||
|
||||
#region Properties
|
||||
public Type ComponentType => typeof(NullComponent);
|
||||
public int ComponentID => -1;
|
||||
public IEcsWorld World => _source;
|
||||
public int Count => 0;
|
||||
public int Capacity => 1;
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
public void Del(int index) { }
|
||||
public override bool Has(int index) => false;
|
||||
void IEcsPool.Write(int entityID) { }
|
||||
@ -42,6 +51,7 @@ namespace DCFApixels.DragonECS
|
||||
public ref NullComponent Write(int entity) => ref fakeComponent;
|
||||
void IEcsPool.OnWorldResize(int newSize) { }
|
||||
internal override void OnWorldResize(int newSize) { }
|
||||
#endregion
|
||||
}
|
||||
public abstract class EcsPool
|
||||
{
|
||||
@ -62,6 +72,7 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
private IEcsComponentReset<T> _componentResetHandler;
|
||||
private PoolRunnres _poolRunnres;
|
||||
|
||||
#region Properites
|
||||
public int Count => _itemsCount;
|
||||
public int Capacity => _items.Length;
|
||||
@ -120,6 +131,7 @@ namespace DCFApixels.DragonECS
|
||||
return ref _items[itemIndex];
|
||||
// }
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref T Write(int entityID)
|
||||
{
|
||||
// using (_writeMark.Auto())
|
||||
|
172
src/EcsQuery.cs
172
src/EcsQuery.cs
@ -1,106 +1,68 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Unity.Profiling;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public abstract class EcsQuery
|
||||
public abstract class EcsQueryBase
|
||||
{
|
||||
internal IEcsWorld source;
|
||||
internal EcsGroup groupFilter;
|
||||
internal EcsQueryMask mask;
|
||||
public IEcsWorld World => groupFilter.World;
|
||||
|
||||
private ProfilerMarker _getEnumerator = new ProfilerMarker("EcsQuery.GetEnumerator");
|
||||
|
||||
|
||||
public EcsGroup.Enumerator GetEnumerator()
|
||||
{
|
||||
using (_getEnumerator.Auto())
|
||||
{
|
||||
var pools = World.GetAllPools();
|
||||
|
||||
EcsReadonlyGroup all = World.Entities;
|
||||
groupFilter.Clear();
|
||||
foreach (var e in all)
|
||||
{
|
||||
int entityID = e.id;
|
||||
|
||||
for (int i = 0, iMax = mask.Inc.Length; i < iMax; i++)
|
||||
{
|
||||
if (!pools[mask.Inc[i]].Has(entityID))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
for (int i = 0, iMax = mask.Exc.Length; i < iMax; i++)
|
||||
{
|
||||
if (pools[mask.Exc[i]].Has(entityID))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
groupFilter.AggressiveAdd(entityID);
|
||||
}
|
||||
groupFilter.Sort();
|
||||
return groupFilter.GetEnumerator();
|
||||
}
|
||||
}
|
||||
protected virtual void Init(Builder b) { }
|
||||
public IEcsWorld World => source;
|
||||
|
||||
#region Builder
|
||||
public sealed class Builder : EcsQueryBuilder
|
||||
protected virtual void Init(Builder b) { }
|
||||
protected abstract void OnBuilt();
|
||||
public abstract void Execute();
|
||||
public sealed class Builder : EcsQueryBuilderBase
|
||||
{
|
||||
private IEcsWorld _world;
|
||||
private List<int> _inc;
|
||||
private List<int> _exc;
|
||||
|
||||
internal static TQuery Build<TQuery>(IEcsWorld world) where TQuery : EcsQuery
|
||||
{
|
||||
Builder builder = new Builder(world);
|
||||
|
||||
Type queryType = typeof(TQuery);
|
||||
ConstructorInfo constructorInfo = queryType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(Builder) }, null);
|
||||
EcsQuery newQuery;
|
||||
if (constructorInfo != null)
|
||||
{
|
||||
newQuery = (EcsQuery)constructorInfo.Invoke(new object[] { builder });
|
||||
}
|
||||
else
|
||||
{
|
||||
newQuery = (EcsQuery)Activator.CreateInstance(typeof(TQuery));
|
||||
newQuery.Init(builder);
|
||||
}
|
||||
|
||||
builder.End(out newQuery.mask);
|
||||
// newQuery.groupFilter = new EcsGroup(world);
|
||||
newQuery.groupFilter = EcsGroup.New(world);
|
||||
return (TQuery)(object)newQuery;
|
||||
}
|
||||
|
||||
private Builder(IEcsWorld world)
|
||||
{
|
||||
_world = world;
|
||||
_inc = new List<int>(8);
|
||||
_exc = new List<int>(4);
|
||||
}
|
||||
internal static TQuery Build<TQuery>(IEcsWorld world) where TQuery : EcsQueryBase
|
||||
{
|
||||
Builder builder = new Builder(world);
|
||||
Type queryType = typeof(TQuery);
|
||||
ConstructorInfo constructorInfo = queryType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(Builder) }, null);
|
||||
EcsQueryBase newQuery;
|
||||
if (constructorInfo != null)
|
||||
{
|
||||
newQuery = (EcsQueryBase)constructorInfo.Invoke(new object[] { builder });
|
||||
}
|
||||
else
|
||||
{
|
||||
newQuery = (EcsQueryBase)Activator.CreateInstance(typeof(TQuery));
|
||||
newQuery.Init(builder);
|
||||
}
|
||||
newQuery.groupFilter = EcsGroup.New(world);
|
||||
newQuery.source = world;
|
||||
builder.End(out newQuery.mask);
|
||||
newQuery.OnBuilt();
|
||||
return (TQuery)(object)newQuery;
|
||||
}
|
||||
|
||||
public override inc<TComponent> Include<TComponent>() where TComponent : struct
|
||||
public override inc_<TComponent> Include<TComponent>() where TComponent : struct
|
||||
{
|
||||
_inc.Add(_world.GetComponentID<TComponent>());
|
||||
return new inc<TComponent>(_world.GetPool<TComponent>());
|
||||
return new inc_<TComponent>(_world.GetPool<TComponent>());
|
||||
}
|
||||
public override exc<TComponent> Exclude<TComponent>() where TComponent : struct
|
||||
public override exc_<TComponent> Exclude<TComponent>() where TComponent : struct
|
||||
{
|
||||
_exc.Add(_world.GetComponentID<TComponent>());
|
||||
return new exc<TComponent>(_world.GetPool<TComponent>());
|
||||
return new exc_<TComponent>(_world.GetPool<TComponent>());
|
||||
}
|
||||
public override opt<TComponent> Optional<TComponent>() where TComponent : struct
|
||||
public override opt_<TComponent> Optional<TComponent>() where TComponent : struct
|
||||
{
|
||||
return new opt<TComponent>(_world.GetPool<TComponent>());
|
||||
return new opt_<TComponent>(_world.GetPool<TComponent>());
|
||||
}
|
||||
|
||||
private void End(out EcsQueryMask mask)
|
||||
@ -116,6 +78,64 @@ namespace DCFApixels.DragonECS
|
||||
#endregion
|
||||
}
|
||||
|
||||
public abstract class EcsJoinQuery : EcsQueryBase
|
||||
{
|
||||
private EcsPool<Attach> attachPool;
|
||||
|
||||
private ProfilerMarker _getEnumerator = new ProfilerMarker("EcsQuery.Execute");
|
||||
protected sealed override void OnBuilt()
|
||||
{
|
||||
attachPool = World.GetPool<Attach>();
|
||||
}
|
||||
public sealed override void Execute()
|
||||
{
|
||||
using (_getEnumerator.Auto())
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
public EcsGroup.Enumerator GetEnumerator()
|
||||
{
|
||||
return groupFilter.GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class EcsQuery : EcsQueryBase
|
||||
{
|
||||
private ProfilerMarker _getEnumerator = new ProfilerMarker("EcsQuery.Execute");
|
||||
protected sealed override void OnBuilt() { }
|
||||
public sealed override void Execute()
|
||||
{
|
||||
using (_getEnumerator.Auto())
|
||||
{
|
||||
var pools = World.GetAllPools();
|
||||
|
||||
EcsReadonlyGroup all = World.Entities;
|
||||
groupFilter.Clear();
|
||||
foreach (var e in all)
|
||||
{
|
||||
int entityID = e.id;
|
||||
for (int i = 0, iMax = mask.Inc.Length; i < iMax; i++)
|
||||
{
|
||||
if (!pools[mask.Inc[i]].Has(entityID))
|
||||
continue;
|
||||
}
|
||||
for (int i = 0, iMax = mask.Exc.Length; i < iMax; i++)
|
||||
{
|
||||
if (pools[mask.Exc[i]].Has(entityID))
|
||||
continue;
|
||||
}
|
||||
groupFilter.AggressiveAdd(entityID);
|
||||
}
|
||||
groupFilter.Sort();
|
||||
}
|
||||
}
|
||||
public EcsGroup.Enumerator GetEnumerator()
|
||||
{
|
||||
return groupFilter.GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
||||
public class EcsQueryMask : EcsComponentMask
|
||||
{
|
||||
public EcsQueryMask(Type worldArchetypeType, int[] inc, int[] exc)
|
||||
@ -125,10 +145,10 @@ namespace DCFApixels.DragonECS
|
||||
Exc = exc;
|
||||
}
|
||||
}
|
||||
public abstract class EcsQueryBuilder
|
||||
public abstract class EcsQueryBuilderBase
|
||||
{
|
||||
public abstract inc<TComponent> Include<TComponent>() where TComponent : struct;
|
||||
public abstract exc<TComponent> Exclude<TComponent>() where TComponent : struct;
|
||||
public abstract opt<TComponent> Optional<TComponent>() where TComponent : struct;
|
||||
public abstract inc_<TComponent> Include<TComponent>() where TComponent : struct;
|
||||
public abstract exc_<TComponent> Exclude<TComponent>() where TComponent : struct;
|
||||
public abstract opt_<TComponent> Optional<TComponent>() where TComponent : struct;
|
||||
}
|
||||
}
|
||||
|
@ -1,89 +1,160 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public interface IEcsQueryMember<TComponent>
|
||||
public interface IEcsQueryMember { }
|
||||
public interface IEcsQueryReadonlyField<TComponent> : IEcsQueryMember
|
||||
{
|
||||
public ref TComponent Read(ent entityID);
|
||||
public bool Has(ent entityID);
|
||||
}
|
||||
public interface IEcsQueryField<TComponent> : IEcsQueryReadonlyField<TComponent>
|
||||
where TComponent : struct
|
||||
{
|
||||
public ref TComponent Add(ent entityID);
|
||||
public ref TComponent Write(ent entityID);
|
||||
public ref TComponent Read(ent entityID);
|
||||
public bool Has(ent entityID);
|
||||
public void Del(ent entityID);
|
||||
}
|
||||
|
||||
#region select
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
|
||||
public readonly struct inc<TComponent> : IEcsQueryMember<TComponent>
|
||||
public readonly struct inc_<TComponent> : IEcsQueryField<TComponent>
|
||||
where TComponent : struct
|
||||
{
|
||||
private readonly EcsPool<TComponent> _pool;
|
||||
internal readonly EcsPool<TComponent> pool;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal inc(EcsPool<TComponent> pool) => _pool = pool;
|
||||
internal inc_(EcsPool<TComponent> pool) => this.pool = pool;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref TComponent Add(ent entityID) => ref _pool.Add(entityID.id);
|
||||
public ref TComponent Add(ent entityID) => ref pool.Add(entityID.id);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref TComponent Write(ent entityID) => ref _pool.Write(entityID.id);
|
||||
public ref TComponent Write(ent entityID) => ref pool.Write(entityID.id);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref TComponent Read(ent entityID) => ref _pool.Read(entityID.id);
|
||||
public ref TComponent Read(ent entityID) => ref pool.Read(entityID.id);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Has(ent entityID) => _pool.Has(entityID.id);
|
||||
public bool Has(ent entityID) => pool.Has(entityID.id);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Del(ent entityID) => _pool.Del(entityID.id);
|
||||
public void Del(ent entityID) => pool.Del(entityID.id);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override string ToString() => $"{(_pool == null ? "NULL" : _pool.World.ArchetypeType.Name)}inc<{typeof(TComponent).Name}>";
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static implicit operator inc<TComponent>(EcsQueryBuilder buider) => buider.Include<TComponent>();
|
||||
public static implicit operator inc_<TComponent>(EcsQueryBuilderBase buider) => buider.Include<TComponent>();
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
|
||||
public readonly struct exc<TComponent> : IEcsQueryMember<TComponent>
|
||||
public readonly struct exc_<TComponent> : IEcsQueryField<TComponent>
|
||||
where TComponent : struct
|
||||
{
|
||||
private readonly EcsPool<TComponent> _pool;
|
||||
internal readonly EcsPool<TComponent> pool;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal exc(EcsPool<TComponent> pool) => _pool = pool;
|
||||
internal exc_(EcsPool<TComponent> pool) => this.pool = pool;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref TComponent Add(ent entityID) => ref _pool.Add(entityID.id);
|
||||
public ref TComponent Add(ent entityID) => ref pool.Add(entityID.id);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref TComponent Write(ent entityID) => ref _pool.Write(entityID.id);
|
||||
public ref TComponent Write(ent entityID) => ref pool.Write(entityID.id);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref TComponent Read(ent entityID) => ref _pool.Read(entityID.id);
|
||||
public ref TComponent Read(ent entityID) => ref pool.Read(entityID.id);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Has(ent entityID) => _pool.Has(entityID.id);
|
||||
public bool Has(ent entityID) => pool.Has(entityID.id);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Del(ent entityID) => _pool.Del(entityID.id);
|
||||
public void Del(ent entityID) => pool.Del(entityID.id);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override string ToString() => $"{(_pool == null ? "NULL" : _pool.World.ArchetypeType.Name)}exc<{typeof(TComponent).Name}>";
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static implicit operator exc<TComponent>(EcsQueryBuilder buider) => buider.Exclude<TComponent>();
|
||||
public static implicit operator exc_<TComponent>(EcsQueryBuilderBase buider) => buider.Exclude<TComponent>();
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
|
||||
public readonly struct opt<TComponent> : IEcsQueryMember<TComponent>
|
||||
public readonly struct opt_<TComponent> : IEcsQueryField<TComponent>
|
||||
where TComponent : struct
|
||||
{
|
||||
private readonly EcsPool<TComponent> _pool;
|
||||
internal readonly EcsPool<TComponent> pool;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal opt(EcsPool<TComponent> pool) => _pool = pool;
|
||||
internal opt_(EcsPool<TComponent> pool) => this.pool = pool;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref TComponent Add(ent entityID) => ref _pool.Add(entityID.id);
|
||||
public ref TComponent Add(ent entityID) => ref pool.Add(entityID.id);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref TComponent Write(ent entityID) => ref _pool.Write(entityID.id);
|
||||
public ref TComponent Write(ent entityID) => ref pool.Write(entityID.id);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref TComponent Read(ent entityID) => ref _pool.Read(entityID.id);
|
||||
public ref TComponent Read(ent entityID) => ref pool.Read(entityID.id);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Has(ent entityID) => _pool.Has(entityID.id);
|
||||
public bool Has(ent entityID) => pool.Has(entityID.id);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Del(ent entityID) => _pool.Del(entityID.id);
|
||||
public void Del(ent entityID) => pool.Del(entityID.id);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override string ToString() => $"{(_pool == null ? "NULL" : _pool.World.ArchetypeType.Name)}opt<{typeof(TComponent).Name}>";
|
||||
public static implicit operator opt_<TComponent>(EcsQueryBuilderBase buider) => buider.Optional<TComponent>();
|
||||
}
|
||||
#endregion
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static implicit operator opt<TComponent>(EcsQueryBuilder buider) => buider.Optional<TComponent>();
|
||||
}
|
||||
// #region select_readonly
|
||||
// [StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
|
||||
// public readonly struct inc_readonly_<TComponent> : IEcsQueryReadonlyField<TComponent>
|
||||
// where TComponent : struct
|
||||
// {
|
||||
// internal readonly EcsPool<TComponent> pool;
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// internal inc_readonly_(EcsPool<TComponent> pool) => this.pool = pool;
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// public ref TComponent Read(ent entityID) => ref pool.Read(entityID.id);
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// public bool Has(ent entityID) => pool.Has(entityID.id);
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
//
|
||||
// public static implicit operator inc_readonly_<TComponent>(EcsQueryBuilderBase buider) => buider.Include<TComponent>();
|
||||
// public static implicit operator inc_readonly_<TComponent>(inc_<TComponent> o) => new inc_readonly_<TComponent>(o.pool);
|
||||
// }
|
||||
//
|
||||
// [StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
|
||||
// public readonly struct exc_readonly_<TComponent> : IEcsQueryReadonlyField<TComponent>
|
||||
// where TComponent : struct
|
||||
// {
|
||||
// internal readonly EcsPool<TComponent> pool;
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// internal exc_readonly_(EcsPool<TComponent> pool) => this.pool = pool;
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// public ref TComponent Read(ent entityID) => ref pool.Read(entityID.id);
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// public bool Has(ent entityID) => pool.Has(entityID.id);
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
//
|
||||
// public static implicit operator exc_readonly_<TComponent>(EcsQueryBuilderBase buider) => buider.Exclude<TComponent>();
|
||||
// public static implicit operator exc_readonly_<TComponent>(exc_<TComponent> o) => new exc_readonly_<TComponent>(o.pool);
|
||||
// }
|
||||
//
|
||||
// [StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
|
||||
// public readonly struct opt_readonly_<TComponent> : IEcsQueryReadonlyField<TComponent>
|
||||
// where TComponent : struct
|
||||
// {
|
||||
// internal readonly EcsPool<TComponent> pool;
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// internal opt_readonly_(EcsPool<TComponent> pool) => this.pool = pool;
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// public ref TComponent Read(ent entityID) => ref pool.Read(entityID.id);
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// public bool Has(ent entityID) => pool.Has(entityID.id);
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
//
|
||||
// public static implicit operator opt_readonly_<TComponent>(EcsQueryBuilderBase buider) => buider.Optional<TComponent>();
|
||||
// public static implicit operator opt_readonly_<TComponent>(opt_<TComponent> o) => new opt_readonly_<TComponent>(o.pool);
|
||||
// }
|
||||
// #endregion
|
||||
//
|
||||
// #region join
|
||||
// [StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
|
||||
// public readonly struct attach : IEcsQueryField<Attach>
|
||||
// {
|
||||
// internal readonly EcsPool<Attach> pool;
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// internal attach(EcsPool<Attach> pool) => this.pool = pool;
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// public ref Attach Add(ent entityID) => ref pool.Add(entityID.id);
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// public ref Attach Write(ent entityID) => ref pool.Write(entityID.id);
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// public ref Attach Read(ent entityID) => ref pool.Read(entityID.id);
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// public bool Has(ent entityID) => pool.Has(entityID.id);
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// public void Del(ent entityID) => pool.Del(entityID.id);
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// public static implicit operator attach(EcsQueryBuilderBase buider) => buider.Include<Attach>();
|
||||
// public static implicit operator attach(inc_<Attach> o) => new attach(o.pool);
|
||||
// }
|
||||
// #endregion
|
||||
}
|
||||
|
@ -38,9 +38,9 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
public readonly short id;
|
||||
|
||||
protected EcsWorld(bool isIndexed)
|
||||
protected EcsWorld(bool isIndexable)
|
||||
{
|
||||
if(isIndexed == true)
|
||||
if(isIndexable == true)
|
||||
{
|
||||
id = (short)_worldIdDispenser.GetFree();
|
||||
if (id >= Worlds.Length)
|
||||
@ -74,11 +74,11 @@ namespace DCFApixels.DragonECS
|
||||
private EcsPool[] _pools;
|
||||
private EcsNullPool _nullPool;
|
||||
|
||||
private EcsQuery[] _queries;
|
||||
private EcsQueryBase[] _queries;
|
||||
|
||||
private EcsPipeline _pipeline;
|
||||
|
||||
private List<EcsGroup> _groups;
|
||||
private List<WeakReference<EcsGroup>> _groups;
|
||||
|
||||
public IEcsRealationTable[] _relationTables;
|
||||
|
||||
@ -132,7 +132,8 @@ namespace DCFApixels.DragonECS
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
public EcsWorld(EcsPipeline pipline = null) : base(true)
|
||||
public EcsWorld(EcsPipeline pipline = null) : this(pipline, true) { }
|
||||
internal EcsWorld(EcsPipeline pipline, bool isIndexable) : base(isIndexable)
|
||||
{
|
||||
_pipeline = pipline ?? EcsPipeline.Empty;
|
||||
if (!_pipeline.IsInit) pipline.Init();
|
||||
@ -143,7 +144,7 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
_gens = new short[512];
|
||||
_queries = new EcsQuery[QueryType.capacity];
|
||||
_groups = new List<EcsGroup>(128);
|
||||
_groups = new List<WeakReference<EcsGroup>>();
|
||||
|
||||
_denseEntities = new int[512];
|
||||
|
||||
@ -154,7 +155,7 @@ namespace DCFApixels.DragonECS
|
||||
_pipeline.GetRunner<IEcsInject<IEcsWorld>>().Inject(this);
|
||||
_pipeline.GetRunner<IEcsWorldCreate>().OnWorldCreate(this);
|
||||
|
||||
_allEntites = new EcsGroup(this);
|
||||
_allEntites = GetGroupFromPool();
|
||||
}
|
||||
#endregion
|
||||
|
||||
@ -181,17 +182,15 @@ namespace DCFApixels.DragonECS
|
||||
#endregion
|
||||
|
||||
#region Query
|
||||
public TQuery Query<TQuery>(out TQuery query) where TQuery : EcsQuery
|
||||
public TQuery Query<TQuery>(out TQuery query) where TQuery : EcsQueryBase
|
||||
{
|
||||
int uniqueID = QueryType<TQuery>.uniqueID;
|
||||
if (_queries.Length < QueryType.capacity)
|
||||
Array.Resize(ref _queries, QueryType.capacity);
|
||||
|
||||
if (_queries[uniqueID] == null)
|
||||
{
|
||||
_queries[uniqueID] = EcsQuery.Builder.Build<TQuery>(this);
|
||||
}
|
||||
_queries[uniqueID] = EcsQueryBase.Builder.Build<TQuery>(this);
|
||||
query = (TQuery)_queries[uniqueID];
|
||||
query.Execute();
|
||||
return query;
|
||||
}
|
||||
#endregion
|
||||
@ -233,8 +232,19 @@ namespace DCFApixels.DragonECS
|
||||
if (_gens.Length <= entityID)
|
||||
{
|
||||
Array.Resize(ref _gens, _gens.Length << 1);
|
||||
foreach (var item in _groups)
|
||||
item.OnWorldResize(_gens.Length);
|
||||
for (int i = 0; i < _groups.Count; i++)
|
||||
{
|
||||
if (_groups[i].TryGetTarget(out EcsGroup group))
|
||||
{
|
||||
group.OnWorldResize(_gens.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
int last = _groups.Count - 1;
|
||||
_groups[i--] = _groups[last];
|
||||
_groups.RemoveAt(last);
|
||||
}
|
||||
}
|
||||
foreach (var item in _pools)
|
||||
item.OnWorldResize(_gens.Length);
|
||||
}
|
||||
@ -286,7 +296,7 @@ namespace DCFApixels.DragonECS
|
||||
#region Other
|
||||
void IEcsReadonlyTable.RegisterGroup(EcsGroup group)
|
||||
{
|
||||
_groups.Add(group);
|
||||
_groups.Add(new WeakReference<EcsGroup>(group));
|
||||
}
|
||||
#endregion
|
||||
|
||||
@ -339,7 +349,8 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
#region GroupsPool
|
||||
private Stack<EcsGroup> _pool = new Stack<EcsGroup>(64);
|
||||
EcsGroup IEcsWorld.GetGroupFromPool()
|
||||
EcsGroup IEcsWorld.GetGroupFromPool() => GetGroupFromPool();
|
||||
internal EcsGroup GetGroupFromPool()
|
||||
{
|
||||
if (_pool.Count <= 0)
|
||||
return new EcsGroup(this);
|
||||
|
@ -4,8 +4,7 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
|
||||
/// <summary>Permanent relation entity identifier</summary>
|
||||
/// <summary>Strong identifier/Permanent entity identifier</summary>
|
||||
[StructLayout(LayoutKind.Explicit, Pack = 2, Size = 8)]
|
||||
public readonly partial struct EcsEntity : IEquatable<long>, IEquatable<EcsEntity>
|
||||
{
|
||||
|
@ -1,74 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
/// <summary>Permanent relation entity identifier</summary>
|
||||
[StructLayout(LayoutKind.Explicit, Pack = 2, Size = 8)]
|
||||
public readonly partial struct EcsRelation : IEquatable<long>, IEquatable<EcsRelation>
|
||||
{
|
||||
public static readonly EcsEntity NULL = default;
|
||||
// uniqueID - 32 bits
|
||||
// gen - 16 bits
|
||||
// world - 16 bits
|
||||
[FieldOffset(0)]
|
||||
internal readonly long full; //Union
|
||||
[FieldOffset(3)]
|
||||
public readonly int id;
|
||||
[FieldOffset(1)]
|
||||
public readonly short rightWorld;
|
||||
[FieldOffset(0)]
|
||||
public readonly short leftWorld;
|
||||
|
||||
public ent Ent
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => new ent(id);
|
||||
}
|
||||
|
||||
#region Constructors
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public EcsRelation(int id, short leftWorld, short rightWorld) : this()
|
||||
{
|
||||
this.id = id;
|
||||
this.leftWorld = leftWorld;
|
||||
this.rightWorld = rightWorld;
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal EcsRelation(long full) : this()
|
||||
{
|
||||
this.full = full;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Equals
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(EcsRelation other) => full == other.full;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(long other) => full == other;
|
||||
#endregion
|
||||
|
||||
#region Object
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override int GetHashCode() => unchecked((int)full) ^ (int)(full >> 32);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override string ToString() => $"Relation(id:{id} leftWorld:{leftWorld} rightWorld:{rightWorld})";
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override bool Equals(object obj) => obj is EcsRelation other && full == other.full;
|
||||
#endregion
|
||||
|
||||
#region operators
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator ==(in EcsRelation a, in EcsRelation b) => a.full == b.full;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator !=(in EcsRelation a, in EcsRelation b) => a.full != b.full;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static explicit operator long(in EcsRelation a) => a.full;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static explicit operator ent(in EcsRelation a) => a.Ent;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static explicit operator EcsRelation(in long a) => new EcsRelation(a);
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -4,8 +4,8 @@ using UnityEngine.Rendering;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
#pragma warning disable CS0660, CS0661
|
||||
/// <summary>Single frame entity identifier</summary>
|
||||
#pragma warning disable CS0660, CS0661, IDE1006
|
||||
/// <summary>Weak identifier/Single frame entity identifier</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4, Size = 4)]
|
||||
public readonly ref struct ent
|
||||
{
|
||||
@ -25,5 +25,8 @@ namespace DCFApixels.DragonECS
|
||||
public static bool operator !=(Null? _, ent b) => b.id != 0;
|
||||
|
||||
public struct Null { }
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public EcsEntity ToStrong(IEcsWorld world) => world.GetEntity(id);
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ namespace DCFApixels.DragonECS
|
||||
#region Methods
|
||||
public EcsPool<T> GetPool<T>() where T : struct;
|
||||
public ReadOnlySpan<EcsPool> GetAllPools();
|
||||
public TQuery Query<TQuery>(out TQuery query) where TQuery : EcsQuery;
|
||||
public TQuery Query<TQuery>(out TQuery query) where TQuery : EcsQueryBase;
|
||||
|
||||
public int GetComponentID<T>();
|
||||
public bool IsMaskCompatible<TInc, TExc>(int entityID) where TInc : struct, IInc where TExc : struct, IExc;
|
||||
|
203
src/Utils/SparseArray.cs
Normal file
203
src/Utils/SparseArray.cs
Normal file
@ -0,0 +1,203 @@
|
||||
using System;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace DCFApixels
|
||||
{
|
||||
public class SparseArray<TValue>
|
||||
{
|
||||
public const int MIN_CAPACITY = 16;
|
||||
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;
|
||||
|
||||
#region Properties
|
||||
public TValue this[int key]
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => _entries[FindEntry(key)].value;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
set => Insert(key, value);
|
||||
}
|
||||
|
||||
public int Count => _count;
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
public SparseArray(int capacity = MIN_CAPACITY)
|
||||
{
|
||||
_buckets = new int[capacity];
|
||||
for (int i = 0; i < capacity; i++)
|
||||
_buckets[i] = EMPTY;
|
||||
_entries = new Entry[capacity];
|
||||
}
|
||||
#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
|
||||
private int FindEntry(int key)
|
||||
{
|
||||
key &= 0x7FFFFFFF;
|
||||
for (int i = _buckets[key % _buckets.Length]; i >= 0; i = _entries[i].next)
|
||||
{
|
||||
if (_entries[i].hashKey == key) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
private void Insert(int key, TValue value)
|
||||
{
|
||||
key &= 0x7FFFFFFF;
|
||||
int targetBucket = key % _buckets.Length;
|
||||
|
||||
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 % _buckets.Length;
|
||||
}
|
||||
index = _count;
|
||||
_count++;
|
||||
}
|
||||
|
||||
_entries[index].next = _buckets[targetBucket];
|
||||
_entries[index].hashKey = key;
|
||||
_entries[index].value = value;
|
||||
_buckets[targetBucket] = index;
|
||||
}
|
||||
public bool Remove(int key)
|
||||
{
|
||||
key &= 0x7FFFFFFF;
|
||||
int bucket = key % _buckets.Length;
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
#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
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user