replace bitset

pull/5/head
Evan Hemsley 2019-12-28 21:39:35 -08:00
parent 05fa578652
commit d4115b231c
8 changed files with 39 additions and 318 deletions

View File

@ -1,33 +0,0 @@
using System.Collections;
using System.Collections.Generic;
namespace Encompass
{
internal class BitArrayPool
{
private Stack<BitArray> bitArrays;
public BitArrayPool(int capacity)
{
bitArrays = new Stack<BitArray>(capacity);
for (var i = 0; i < capacity; i++)
{
bitArrays.Push(new BitArray(128));
}
}
public BitArray Obtain(int size)
{
var bitArray = bitArrays.Pop();
bitArray.Length = size;
bitArray.SetAll(false);
return bitArray;
}
public void Free(BitArray bitArray)
{
bitArrays.Push(bitArray);
}
}
}

View File

@ -1,182 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
namespace Encompass.Collections
{
public static class BitSetBuilder
{
public static BitSet Zeroes()
{
return new BitSet(VectorBuilder.Zeroes(), VectorBuilder.Zeroes(), VectorBuilder.Zeroes(), VectorBuilder.Zeroes());
}
public static BitSet Ones()
{
return new BitSet(VectorBuilder.Ones(), VectorBuilder.Ones(), VectorBuilder.Ones(), VectorBuilder.Ones());
}
}
public static class VectorBuilder
{
static readonly uint[] zeroes = new uint[Vector<uint>.Count]; // max size of a Vector<T> is 8 uints
static readonly uint[] ones = Enumerable.Repeat(uint.MaxValue, Vector<uint>.Count).ToArray();
static uint[] builderInts = new uint[Vector<uint>.Count];
private static void ResetBuilder()
{
for (var i = 0; i < Vector<uint>.Count; i++)
{
builderInts[i] = 0;
}
}
public static Vector<uint> Zeroes()
{
return new Vector<uint>(zeroes);
}
public static Vector<uint> Ones()
{
return new Vector<uint>(ones);
}
public static Vector<uint> Build(int index)
{
if (index > Vector<uint>.Count * 32) { throw new System.ArgumentOutOfRangeException(nameof(index)); }
ResetBuilder();
builderInts[index / 32] |= (uint)(1 << (index % 32));
return new Vector<uint>(builderInts);
}
}
public struct BitSet
{
public static int VectorLength { get { return Vector<uint>.Count * 32; } }
public Vector<uint> A { get; }
public Vector<uint> B { get; }
public Vector<uint> C { get; }
public Vector<uint> D { get; }
internal BitSet(Vector<uint> a, Vector<uint> b, Vector<uint> c, Vector<uint> d)
{
A = a;
B = b;
C = c;
D = d;
}
public BitSet And(BitSet other)
{
return new BitSet(A & other.A, B & other.B, C & other.C, D & other.D);
}
public BitSet Or(BitSet other)
{
return new BitSet(A | other.A, B | other.B, C | other.C, D | other.D);
}
public BitSet Not()
{
return new BitSet(~A, ~B, ~C, ~D);
}
public BitSet Set(int index)
{
if (index < VectorLength)
{
return new BitSet(A | VectorBuilder.Build(index % VectorLength), B, C, D);
}
else if (index < VectorLength * 2)
{
return new BitSet(A, B | VectorBuilder.Build(index % VectorLength), C, D);
}
else if (index < VectorLength * 3)
{
return new BitSet(A, B, C | VectorBuilder.Build(index % VectorLength), D);
}
else if (index < VectorLength * 4)
{
return new BitSet(A, B, C, D | VectorBuilder.Build(index % VectorLength));
}
else
{
throw new System.ArgumentOutOfRangeException(nameof(index));
}
}
public BitSet UnSet(int index)
{
if (index < VectorLength)
{
return new BitSet(A & ~VectorBuilder.Build(index % VectorLength), B, C, D);
}
else if (index < VectorLength * 2)
{
return new BitSet(A, B & ~VectorBuilder.Build(index % VectorLength), C, D);
}
else if (index < VectorLength * 3)
{
return new BitSet(A, B, C & ~VectorBuilder.Build(index % VectorLength), D);
}
else if (index < VectorLength * 4)
{
return new BitSet(A, B, C, D & ~VectorBuilder.Build(index % VectorLength));
}
else
{
throw new System.ArgumentOutOfRangeException(nameof(index));
}
}
public bool Get(int index)
{
var vectorIndex = index % VectorLength;
if (index < VectorLength)
{
return (A[vectorIndex / 32] & (uint)(1 << vectorIndex % 32)) != 0;
}
else if (index < VectorLength * 2)
{
return (B[vectorIndex / 32] & (uint)(1 << vectorIndex % 32)) != 0;
}
else if (index < VectorLength * 3)
{
return (C[vectorIndex / 32] & (uint)(1 << vectorIndex % 32)) != 0;
}
else if (index < VectorLength * 4)
{
return (D[vectorIndex / 32] & (uint)(1 << vectorIndex % 32)) != 0;
}
else
{
throw new System.ArgumentOutOfRangeException(nameof(index));
}
}
public bool AllTrue()
{
for (var i = 0; i < Vector<uint>.Count; i++)
{
if (A[i] != uint.MaxValue) { return false; }
if (B[i] != uint.MaxValue) { return false; }
if (C[i] != uint.MaxValue) { return false; }
if (D[i] != uint.MaxValue) { return false; }
}
return true;
}
public bool AllFalse()
{
for (var i = 0; i < Vector<uint>.Count; i++)
{
if (A[i] != 0) { return false; }
if (B[i] != 0) { return false; }
if (C[i] != 0) { return false; }
if (D[i] != 0) { return false; }
}
return true;
}
}
}

View File

@ -1,13 +1,12 @@
using Encompass.Collections; using MoonTools.FastCollections;
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
namespace Encompass namespace Encompass
{ {
internal class ComponentBitSet internal class ComponentBitSet
{ {
Dictionary<int, BitSet> entities = new Dictionary<int, BitSet>(); Dictionary<int, BitSet512> entities = new Dictionary<int, BitSet512>();
Dictionary<Type, int> TypeToIndex { get; } Dictionary<Type, int> TypeToIndex { get; }
public ComponentBitSet(Dictionary<Type, int> typeToIndex) public ComponentBitSet(Dictionary<Type, int> typeToIndex)
@ -22,7 +21,7 @@ namespace Encompass
public void AddEntity(int entityID) public void AddEntity(int entityID)
{ {
entities.Add(entityID, BitSetBuilder.Zeroes()); entities.Add(entityID, BitSet512.Zero);
} }
public void Set<TComponent>(int entityID) where TComponent : struct, IComponent public void Set<TComponent>(int entityID) where TComponent : struct, IComponent
@ -47,9 +46,9 @@ namespace Encompass
} }
} }
public BitSet EntityBitArray(int entityID) public BitSet512 EntityBitArray(int entityID)
{ {
return entities.ContainsKey(entityID) ? entities[entityID] : BitSetBuilder.Zeroes(); return entities.ContainsKey(entityID) ? entities[entityID] : BitSet512.Zero;
} }
} }
} }

View File

@ -1,4 +1,4 @@
using Encompass.Collections; using MoonTools.FastCollections;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -47,7 +47,7 @@ namespace Encompass
return Stores.ContainsKey(type) && Stores[type].Has(entityID); return Stores.ContainsKey(type) && Stores[type].Has(entityID);
} }
public BitSet EntityBitArray(int entityID) public BitSet512 EntityBitArray(int entityID)
{ {
return ComponentBitSet.EntityBitArray(entityID); return ComponentBitSet.EntityBitArray(entityID);
} }

View File

@ -3,7 +3,7 @@ using System.Reflection;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Encompass.Exceptions; using Encompass.Exceptions;
using Encompass.Collections; using MoonTools.FastCollections;
namespace Encompass namespace Encompass
{ {
@ -686,36 +686,36 @@ namespace Encompass
/// </summary> /// </summary>
internal void BuildEntityQuery() internal void BuildEntityQuery()
{ {
var withMask = BitSetBuilder.Zeroes(); var withMask = BitSet512.Zero;
foreach (var type in queryWithTypes) foreach (var type in queryWithTypes)
{ {
withMask = withMask.Set(componentUpdateManager.TypeToIndex[type]); withMask = withMask.Set(componentUpdateManager.TypeToIndex[type]);
} }
var withoutMask = BitSetBuilder.Zeroes(); var withoutMask = BitSet512.Zero;
foreach (var type in queryWithoutTypes) foreach (var type in queryWithoutTypes)
{ {
withoutMask = withoutMask.Set(componentUpdateManager.TypeToIndex[type]); withoutMask = withoutMask.Set(componentUpdateManager.TypeToIndex[type]);
} }
var immediateMask = BitSetBuilder.Zeroes(); var immediateMask = BitSet512.Zero;
foreach (var type in readImmediateTypes) foreach (var type in readImmediateTypes)
{ {
immediateMask = immediateMask.Set(componentUpdateManager.TypeToIndex[type]); immediateMask = immediateMask.Set(componentUpdateManager.TypeToIndex[type]);
} }
var existingMask = BitSetBuilder.Zeroes(); var existingMask = BitSet512.Zero;
foreach (var type in readTypes) foreach (var type in readTypes)
{ {
existingMask = existingMask.Set(componentUpdateManager.TypeToIndex[type]); existingMask = existingMask.Set(componentUpdateManager.TypeToIndex[type]);
} }
entityQuery = new EntitySetQuery( entityQuery = new EntitySetQuery(
withMask.And(immediateMask), withMask & immediateMask,
withMask.And(existingMask), withMask & existingMask,
withoutMask.And(immediateMask), withoutMask & immediateMask,
withoutMask.And(existingMask), withoutMask & existingMask,
withMask.Not() ~withMask
); );
} }

View File

@ -1,18 +1,16 @@
using System.Collections; using MoonTools.FastCollections;
using System.Collections.Generic;
using Encompass.Collections;
namespace Encompass namespace Encompass
{ {
internal struct EntitySetQuery internal struct EntitySetQuery
{ {
private BitSet WithImmediateMask { get; } private BitSet512 WithImmediateMask { get; }
private BitSet WithExistingMask { get; } private BitSet512 WithExistingMask { get; }
private BitSet WithoutImmediateMask { get; } private BitSet512 WithoutImmediateMask { get; }
private BitSet WithoutExistingMask { get; } private BitSet512 WithoutExistingMask { get; }
private BitSet NotWithMask { get; } private BitSet512 NotWithMask { get; }
internal EntitySetQuery(BitSet withImmediateMask, BitSet withExistingMask, BitSet withoutImmediateMask, BitSet withoutExistingMask, BitSet notWithMask) internal EntitySetQuery(BitSet512 withImmediateMask, BitSet512 withExistingMask, BitSet512 withoutImmediateMask, BitSet512 withoutExistingMask, BitSet512 notWithMask)
{ {
WithImmediateMask = withImmediateMask; WithImmediateMask = withImmediateMask;
WithExistingMask = withExistingMask; WithExistingMask = withExistingMask;
@ -24,11 +22,11 @@ namespace Encompass
public bool CheckEntity(Entity entity, ComponentBitSet componentBitSet) public bool CheckEntity(Entity entity, ComponentBitSet componentBitSet)
{ {
var existingBits = componentBitSet.EntityBitArray(entity.ID); var existingBits = componentBitSet.EntityBitArray(entity.ID);
var existing = WithExistingMask.And(existingBits).Or(NotWithMask); var existing = (WithExistingMask & existingBits) | NotWithMask;
var existingForbidden = WithoutExistingMask.And(existingBits).Not(); var existingForbidden = ~(WithoutExistingMask & existingBits);
return existing.And(existingForbidden).AllTrue(); return (existing & existingForbidden).AllTrue();
} }
public bool ImmediateCheckEntity(Entity entity, ComponentBitSet immediateBitLookup, ComponentBitSet existingBitLookup) public bool ImmediateCheckEntity(Entity entity, ComponentBitSet immediateBitLookup, ComponentBitSet existingBitLookup)
@ -36,15 +34,15 @@ namespace Encompass
var immediateBits = immediateBitLookup.EntityBitArray(entity.ID); var immediateBits = immediateBitLookup.EntityBitArray(entity.ID);
var existingBits = existingBitLookup.EntityBitArray(entity.ID); var existingBits = existingBitLookup.EntityBitArray(entity.ID);
var immediate = WithImmediateMask.And(immediateBits); var immediate = WithImmediateMask & immediateBits;
var existing = WithExistingMask.And(existingBits); var existing = WithExistingMask & existingBits;
var withCheck = immediate.Or(existing).Or(NotWithMask); var withCheck = immediate | existing | NotWithMask;
var immediateForbidden = WithoutImmediateMask.And(immediateBits).Not(); var immediateForbidden = ~(WithoutImmediateMask & immediateBits);
var existingForbidden = WithoutExistingMask.And(existingBits).Not(); var existingForbidden = ~(WithoutExistingMask & existingBits);
var withoutCheck = immediateForbidden.And(existingForbidden); var withoutCheck = immediateForbidden & existingForbidden;
return withCheck.And(withoutCheck).AllTrue(); return (withCheck & withoutCheck).AllTrue();
} }
} }
} }

View File

@ -9,7 +9,7 @@
<Company>Moonside Games</Company> <Company>Moonside Games</Company>
<Product>Encompass ECS</Product> <Product>Encompass ECS</Product>
<PackageProjectUrl>https://github.com/encompass-ecs</PackageProjectUrl> <PackageProjectUrl>https://github.com/encompass-ecs</PackageProjectUrl>
<PackageLicenseUrl/> <PackageLicenseUrl />
<Copyright>Evan Hemsley 2019</Copyright> <Copyright>Evan Hemsley 2019</Copyright>
<Description>Encompass is an engine-agnostic Hyper ECS framework to help you code games, or other kinds of simulations.</Description> <Description>Encompass is an engine-agnostic Hyper ECS framework to help you code games, or other kinds of simulations.</Description>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
@ -19,11 +19,12 @@
<ItemGroup> <ItemGroup>
<None Include="..\LICENSE"> <None Include="..\LICENSE">
<Pack>True</Pack> <Pack>True</Pack>
<PackagePath/> <PackagePath />
</None> </None>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="MoonTools.Core.Graph" Version="1.0.0"/> <PackageReference Include="MoonTools.Core.Graph" Version="1.0.0" />
<PackageReference Include="System.Collections.Immutable" Version="1.7.0"/> <PackageReference Include="MoonTools.FastCollections" Version="1.0.0" />
<PackageReference Include="System.Collections.Immutable" Version="1.7.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,62 +0,0 @@
using Encompass.Collections;
using FluentAssertions;
using NUnit.Framework;
namespace Tests
{
public class BitSetTest
{
[Test]
public void Zeroes()
{
var bitSet = BitSetBuilder.Zeroes();
bitSet.AllFalse().Should().BeTrue();
}
[Test]
public void Ones()
{
var bitSet = BitSetBuilder.Ones();
bitSet.AllTrue().Should().BeTrue();
}
[Test]
public void Set()
{
var bitSet = BitSetBuilder.Zeroes().Set(5);
bitSet.AllFalse().Should().BeFalse();
bitSet = BitSetBuilder.Zeroes().Set(132);
bitSet.AllFalse().Should().BeFalse();
bitSet = BitSetBuilder.Zeroes().Set(268);
bitSet.AllFalse().Should().BeFalse();
bitSet = BitSetBuilder.Zeroes().Set(450);
bitSet.AllFalse().Should().BeFalse();
}
[Test]
public void UnSet()
{
var bitSet = BitSetBuilder.Ones().UnSet(285);
bitSet.Get(285).Should().BeFalse();
bitSet.Set(285).AllTrue().Should().BeTrue();
}
[Test]
public void Get()
{
var bitSet = BitSetBuilder.Zeroes().Set(359);
bitSet.Get(359).Should().BeTrue();
bitSet.UnSet(359).AllFalse().Should().BeTrue();
}
[Test]
public void Not()
{
var bitSet = BitSetBuilder.Ones().Not();
bitSet.AllFalse().Should().BeTrue();
}
}
}