Skip to content

Commit

Permalink
Merge pull request #29 from andreakarasho/performance
Browse files Browse the repository at this point in the history
Performance
  • Loading branch information
andreakarasho authored Jul 19, 2024
2 parents deb2b7a + 6fb2888 commit 3ad6e29
Show file tree
Hide file tree
Showing 18 changed files with 1,259 additions and 715 deletions.
467 changes: 279 additions & 188 deletions src/Archetype.cs

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions src/DictionarySlim.cs
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,31 @@ public ref TValue GetOrAddValueRef(TKey key, out bool exists)
return ref AddKey(key, bucketIndex);
}

public ref TValue GetOrNullRef(TKey key, out bool exists)
{
if (key == null) ThrowHelper.ThrowKeyArgumentNullException();
exists = true;
Entry[] entries = _entries;
int collisionCount = 0;
int bucketIndex = key.GetHashCode() & (_buckets.Length - 1);
for (int i = _buckets[bucketIndex] - 1;
(uint)i < (uint)entries.Length; i = entries[i].next)
{
if (key.Equals(entries[i].key))
return ref entries[i].value;
if (collisionCount == entries.Length)
{
// The chain of entries forms a loop; which means a concurrent update has happened.
// Break out of the loop and throw, rather than looping forever.
ThrowHelper.ThrowInvalidOperationException_ConcurrentOperationsNotSupported();
}
collisionCount++;
}

exists = false;
return ref Unsafe.NullRef<TValue>();
}

[MethodImpl(MethodImplOptions.NoInlining)]
private ref TValue AddKey(TKey key, int bucketIndex)
{
Expand Down
17 changes: 17 additions & 0 deletions src/DotnetAddons.cs
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,23 @@ public static void Sort<T>(this Span<T> span, IComparer<T> comparer)
}
}

public static void Sort<T>(this Span<T> span, Comparison<T> comparison)
{
for (int i = 0; i < span.Length - 1; i++)
{
for (int j = 0; j < span.Length - i - 1; j++)
{
if (comparison(span[j], span[j + 1]) > 0)
{
// Swap the elements
T temp = span[j];
span[j] = span[j + 1];
span[j + 1] = temp;
}
}
}
}

// public static System.Collections.Immutable.ImmutableArray<TSource> ToImmutableArray<TSource>(this IEnumerable<TSource> items)
// {
// return System.Collections.Immutable.ImmutableArray.CreateRange(items);
Expand Down
14 changes: 7 additions & 7 deletions src/EcsID.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,25 @@ namespace TinyEcs;

public static class EcsIdEx
{
public static bool IsPair(this ref readonly EcsID id)
public static bool IsPair(this EcsID id)
=> IDOp.IsPair(id);

public static EcsID First(this ref readonly EcsID id)
public static EcsID First(this EcsID id)
=> id.IsPair() ? IDOp.GetPairFirst(id) : 0;

public static EcsID Second(this ref readonly EcsID id)
public static EcsID Second(this EcsID id)
=> id.IsPair() ? IDOp.GetPairSecond(id) : 0;

public static (EcsID, EcsID) Pair(this ref readonly EcsID id)
public static (EcsID, EcsID) Pair(this EcsID id)
=> (id.First(), id.Second());

public static bool IsValid(this ref readonly EcsID id)
public static bool IsValid(this EcsID id)
=> id != 0;

public static EcsID RealId(this ref readonly EcsID id)
public static EcsID RealId(this EcsID id)
=> IDOp.RealID(id);

public static int Generation(this ref readonly EcsID id)
public static int Generation(this EcsID id)
=> (int) IDOp.GetGeneration(id);
}

Expand Down
24 changes: 12 additions & 12 deletions src/EcsOp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,67 +2,67 @@ namespace TinyEcs;

public static class IDOp
{
public static void Toggle(ref ulong id)
public static void Toggle(ref EcsID id)
{
id ^= EcsConst.ECS_TOGGLE;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong GetGeneration(ulong id)
public static EcsID GetGeneration(EcsID id)
{
return ((id & EcsConst.ECS_GENERATION_MASK) >> 32);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong IncreaseGeneration(ulong id)
public static EcsID IncreaseGeneration(EcsID id)
{
return ((id & ~EcsConst.ECS_GENERATION_MASK) | ((0xFFFF & (GetGeneration(id) + 1)) << 32));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong RealID(ulong id)
public static EcsID RealID(EcsID id)
{
return id &= EcsConst.ECS_ENTITY_MASK;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool HasFlag(ulong id, byte flag)
public static bool HasFlag(EcsID id, byte flag)
{
return (id & flag) != 0;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsComponent(ulong id)
public static bool IsComponent(EcsID id)
{
return (id & ~EcsConst.ECS_COMPONENT_MASK) != 0;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong SetAsComponent(ulong id)
public static EcsID SetAsComponent(EcsID id)
{
return id |= EcsConst.ECS_ID_FLAGS_MASK;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong Pair(ulong first, ulong second)
public static EcsID Pair(EcsID first, EcsID second)
{
return EcsConst.ECS_PAIR | ((first << 32) + (uint)second);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsPair(ulong id)
public static bool IsPair(EcsID id)
{
return ((id) & EcsConst.ECS_ID_FLAGS_MASK) == EcsConst.ECS_PAIR;
return (id & EcsConst.ECS_ID_FLAGS_MASK) == EcsConst.ECS_PAIR;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong GetPairFirst(ulong id)
public static EcsID GetPairFirst(EcsID id)
{
return (uint)((id & EcsConst.ECS_COMPONENT_MASK) >> 32);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong GetPairSecond(ulong id)
public static EcsID GetPairSecond(EcsID id)
{
return (uint)id;
}
Expand Down
98 changes: 78 additions & 20 deletions src/Hashing.cs
Original file line number Diff line number Diff line change
@@ -1,31 +1,89 @@
namespace TinyEcs;

internal static class Hashing

public struct RollingHash
{
const ulong FIXED = 314159;
private const ulong Base = 31; // A prime base for hashing
private const ulong Modulus = 1_000_000_007; // A large prime modulus

public static ulong Calculate(ReadOnlySpan<ComponentInfo> components)
{
var hc = (ulong)components.Length;
foreach (ref readonly var val in components)
hc = unchecked(hc * FIXED + val.ID);
return hc;
}
private ulong _hash;
private ulong _product;

private static readonly ulong _inverseCache = ModInverse2(Base, Modulus);


public RollingHash()
{
_hash = 0;
_product = 1;
}

public readonly ulong Hash => _hash;


[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Add(ulong value)
{
_hash = (_hash + value * _product) % Modulus;
_product = (_product * Base) % Modulus;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Remove(ulong value)
{
var inverseBase = _inverseCache;
_product = (_product * inverseBase) % Modulus;
_hash = (_hash + Modulus - (value * _product % Modulus)) % Modulus;
}

public static ulong Calculate(ReadOnlySpan<IQueryTerm> terms)

// Compute modular inverse of a with respect to m using Extended Euclidean Algorithm
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong ModInverse2(ulong a, ulong m)
{
ulong m0 = m, x0 = 0, x1 = 1;

while (a > 1)
{
ulong q = a / m;
ulong t = m;

m = a % m;
a = t;
t = x0;

x0 = x1 - q * x0;
x1 = t;
}

return (x1 + m0) % m0;
}

public static ulong Calculate(params ReadOnlySpan<EcsID> values)
{
var hc = (ulong)terms.Length;
foreach (ref readonly var val in terms)
hc = unchecked(hc * FIXED + (ulong)val.Id + (byte)val.Op +
(val is ContainerQueryTerm container ? container.Terms.Aggregate(0Ul, static (a, b) => a + b.Id) : 0));
return hc;
var hash = 0ul;
var product = 1ul;

foreach (ref readonly var value in values)
{
hash = (hash + value * product) % Modulus;
product = (product * Base) % Modulus;
}

return hash;
}

public static ulong Calculate(IEnumerable<EcsID> terms)
public static ulong Calculate(params ReadOnlySpan<ComponentInfo> values)
{
var hc = (ulong)terms.Count();
foreach (var val in terms)
hc = unchecked(hc * FIXED + val);
return hc;
var hash = 0ul;
var product = 1ul;

foreach (ref readonly var value in values)
{
hash = (hash + value.ID * product) % Modulus;
product = (product * Base) % Modulus;
}

return hash;
}
}
Loading

0 comments on commit 3ad6e29

Please sign in to comment.