Browse Source

add more safety checks

tinkering around the concept of QueryMappedEntities
tags/2.6a
sebas77 6 years ago
parent
commit
60525639d6
3 changed files with 163 additions and 45 deletions
  1. +4
    -2
      Svelto.ECS/EGIDMapper.cs
  2. +81
    -18
      Svelto.ECS/EntitiesDB.cs
  3. +78
    -25
      Svelto.ECS/IEntitiesDB.cs

+ 4
- 2
Svelto.ECS/EGIDMapper.cs View File

@@ -6,9 +6,11 @@ namespace Svelto.ECS
{
internal TypeSafeDictionary<T> map;

public uint this[EGID index]
public T[] entities(EGID id, out uint index)
{
get { return map.FindElementIndex(index.entityID); }
int count;
index = map.FindElementIndex(id.entityID);
return map.GetFasterValuesBuffer(out count);
}
}
}

+ 81
- 18
Svelto.ECS/EntitiesDB.cs View File

@@ -42,17 +42,25 @@ namespace Svelto.ECS.Internal
return typeSafeDictionary.GetFasterValuesBuffer(out count);
}
public T[] QueryEntities<T>(int groupID, ref EGIDMapper<T> mapper) where T : IEntityStruct
public EGIDMapper<T> QueryMappedEntities<T>() where T : IEntityStruct
{
return QueryMappedEntities<T>(ExclusiveGroup.StandardEntitiesGroup);
}
public EGIDMapper<T> QueryMappedEntities<T>(int groupID) where T : IEntityStruct
{
TypeSafeDictionary<T> typeSafeDictionary;
if (QueryEntitySafeDictionary(groupID, out typeSafeDictionary) == false)
throw new EntitiesDBException("Entity group not found type: ".FastConcat(typeof(T)).FastConcat(" groupID: ").FastConcat(groupID));

EGIDMapper<T> mapper;
mapper.map = typeSafeDictionary;

int count;
return typeSafeDictionary.GetFasterValuesBuffer(out count);
typeSafeDictionary.GetFasterValuesBuffer(out count);

return mapper;
}

public T[] QueryEntitiesAndIndex<T>(EGID entityGID, out uint index) where T : IEntityStruct
@@ -130,11 +138,22 @@ namespace Svelto.ECS.Internal

public void ExecuteOnEntities<T>(int groupID, ActionRef<T> action) where T : IEntityStruct
{
int count;
var entities = QueryEntities<T>(groupID, out count);

for (int i = 0; i < count; i++)
int count;
TypeSafeDictionary<T> typeSafeDictionary;
if (QueryEntitySafeDictionary(@groupID, out typeSafeDictionary) == false) return;
var entities = typeSafeDictionary.GetFasterValuesBuffer(out count);
for (var i = 0; i < count; i++)
action(ref entities[i]);
SafetyChecks(typeSafeDictionary, count);
}

static void SafetyChecks<T>(TypeSafeDictionary<T> typeSafeDictionary, int count) where T : IEntityStruct
{
if (typeSafeDictionary.Count != count)
throw new EntitiesDBException("Entities cannot be swapped or removed during an iteration");
}

public void ExecuteOnEntities<T>(ActionRef<T> action) where T : IEntityStruct
@@ -144,17 +163,27 @@ namespace Svelto.ECS.Internal

public void ExecuteOnEntities<T, W>(int groupID, ref W value, ActionRef<T, W> action) where T : IEntityStruct
{
int count;
var entities = QueryEntities<T>(groupID, out count);

for (int i = 0; i < count; i++)
int count;
TypeSafeDictionary<T> typeSafeDictionary;
if (QueryEntitySafeDictionary(@groupID, out typeSafeDictionary) == false) return;
var entities = typeSafeDictionary.GetFasterValuesBuffer(out count);
for (var i = 0; i < count; i++)
action(ref entities[i], ref value);
SafetyChecks(typeSafeDictionary, count);
}

public void ExecuteOnEntities<T, W>(ref W value, ActionRef<T, W> action) where T : IEntityStruct
{
ExecuteOnEntities(ExclusiveGroup.StandardEntitiesGroup, ref value, action);
}
public void ExecuteOnEntities<T, T1, W>(W value, ActionRef<T, T1, W> action) where T : IEntityStruct where T1 : IEntityStruct
{
ExecuteOnEntities(ExclusiveGroup.StandardEntitiesGroup, ref value, action);
}

public void ExecuteOnAllEntities<T>(ActionRef<T> action) where T : IEntityStruct
{
@@ -167,11 +196,15 @@ namespace Svelto.ECS.Internal
for (int j = 0; j < count; j++)
{
int innerCount;
var safedic = typeSafeDictionaries[j];
var casted = safedic as TypeSafeDictionary<T>;
var typeSafeDictionary = typeSafeDictionaries[j];
var casted = typeSafeDictionary as TypeSafeDictionary<T>;
var entities = casted.GetFasterValuesBuffer(out innerCount);

for (int i = 0; i < innerCount; i++)
action(ref entities[i]);
SafetyChecks(casted, count);
}
}
}
@@ -187,11 +220,15 @@ namespace Svelto.ECS.Internal
for (int j = 0; j < count; j++)
{
int innerCount;
var safedic = typeSafeDictionaries[j];
var casted = safedic as TypeSafeDictionary<T>;
var typeSafeDictionary = typeSafeDictionaries[j];
var casted = typeSafeDictionary as TypeSafeDictionary<T>;
var entities = casted.GetFasterValuesBuffer(out innerCount);

for (int i = 0; i < innerCount; i++)
action(ref entities[i], ref value);
SafetyChecks(casted, count);
}
}
}
@@ -203,20 +240,46 @@ namespace Svelto.ECS.Internal
if (QueryEntitySafeDictionary(@group, out typeSafeDictionary) == false) return;
var entities = typeSafeDictionary.GetFasterValuesBuffer(out count);

EGIDMapper<T1> map = QueryMappedEntities<T1>(group);
for (var i = 0; i < count; i++)
{
uint index;
action(ref entities[i], ref map.entities(entities[i].ID, out index)[index]);
}

SafetyChecks(typeSafeDictionary, count);
}
public void ExecuteOnEntities<T, T1, W>(int group, ref W value, ActionRef<T, T1, W> action) where T : IEntityStruct where T1 : IEntityStruct
{
int count;
TypeSafeDictionary<T> typeSafeDictionary;
if (QueryEntitySafeDictionary(@group, out typeSafeDictionary) == false) return;
var entities = typeSafeDictionary.GetFasterValuesBuffer(out count);

EGIDMapper<T1> map = QueryMappedEntities<T1>(group);
for (var i = 0; i < count; i++)
{
uint index;
action(ref entities[i], ref QueryEntitiesAndIndex<T1>(entities[i].ID, out index)[index]);
if (typeSafeDictionary.Count != count)
throw new EntitiesDBException("Entities cannot be swapped or removed during an iteration");
action(ref entities[i], ref map.entities(entities[i].ID, out index)[index], ref value);
}

SafetyChecks(typeSafeDictionary, count);
}

public void ExecuteOnEntities<T, T1>(ActionRef<T, T1> action) where T : IEntityStruct where T1 : IEntityStruct
{
ExecuteOnEntities(ExclusiveGroup.StandardEntitiesGroup, action);
}
public void ExecuteOnEntities<T, T1, W>(ref W value, ActionRef<T, T1, W> action) where T : IEntityStruct where T1 : IEntityStruct
{
ExecuteOnEntities(ExclusiveGroup.StandardEntitiesGroup, ref value, action);
}

public bool Exists<T>(EGID entityGID) where T : IEntityStruct
{


+ 78
- 25
Svelto.ECS/IEntitiesDB.cs View File

@@ -1,4 +1,3 @@
using System;
using Svelto.DataStructures;
using Svelto.Utilities;

@@ -30,41 +29,95 @@ namespace Svelto.ECS
/// over EntityView
/// </summary>
T QueryEntityView<T>(EGID egid) where T : class, IEntityStruct;

//to use with EntityViews, EntityStructs and EntityViewStructs
/// <summary>
/// Fast and raw (therefore not safe) return of entities buffer
/// Modifying a buffer would compromise the integrity of the whole DB
/// so they are meant to be used only in performance critical path
/// </summary>
/// <param name="count"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
T[] QueryEntities<T>(out int count) where T : IEntityStruct;
T[] QueryEntities<T>(int group, out int count) where T : IEntityStruct;
T[] QueryEntities<T>(int groupID, ref EGIDMapper<T> mapper) where T : IEntityStruct;
T[] QueryEntitiesAndIndex<T>(EGID entityGid, out uint index) where T : IEntityStruct;
bool TryQueryEntitiesAndIndex<T>(EGID entityGid, out uint index, out T[] array) where T : IEntityStruct;

//to use with EntityViews, EntityStructs and EntityViewStructs
void ExecuteOnEntity<T>(EGID egid, ActionRef<T> action) where T : IEntityStruct;
void ExecuteOnEntity<T>(int id, ActionRef<T> action) where T : IEntityStruct;
void ExecuteOnEntity<T>(int id, int groupid, ActionRef<T> action) where T : IEntityStruct;

T[] QueryEntities<T>(int group, out int count) where T : IEntityStruct;
/// <summary>
/// this version returns a mapped version of the entity array so that is possible to find the
/// index of the entity inside the returned buffer through it's EGID
/// However mapping can be slow so it must be used for not performance critical paths
/// </summary>
/// <param name="groupID"></param>
/// <param name="mapper"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
EGIDMapper<T> QueryMappedEntities<T>(int groupID) where T : IEntityStruct;
EGIDMapper<T> QueryMappedEntities<T>() where T : IEntityStruct;
/// <summary>
/// Execute an action on entities. Be sure that the action is not capturing variables
/// otherwise you will allocate memory which will have a great impact on the execution performance.
/// ExecuteOnEntities can be used to iterate safely over entities, several checks are in place
/// to be sure that everything will be done correctly.
/// Cache friendliness is guaranteed if only Entity Structs are used, but
/// </summary>
/// <param name="egid"></param>
/// <param name="action"></param>
/// <typeparam name="T"></typeparam>
void ExecuteOnEntities<T>(int groupID, ActionRef<T> action) where T : IEntityStruct;
void ExecuteOnEntities<T>(ActionRef<T> action) where T : IEntityStruct;

void ExecuteOnEntity<T, W>(EGID egid, ref W value, ActionRef<T, W> action) where T : IEntityStruct;
void ExecuteOnEntity<T, W>(int id, ref W value, ActionRef<T, W> action) where T : IEntityStruct;
void ExecuteOnEntity<T, W>(int id, int groupid, ref W value, ActionRef<T, W> action) where T : IEntityStruct;
void ExecuteOnEntities<T, W>(int groupID, ref W value, ActionRef<T, W> action) where T : IEntityStruct;
void ExecuteOnEntities<T, W>(ref W value, ActionRef<T, W> action) where T : IEntityStruct;

void ExecuteOnAllEntities<T>(ActionRef<T> action) where T : IEntityStruct;
void ExecuteOnAllEntities<T, W>(ref W value, ActionRef<T, W> action) where T : IEntityStruct;
/// <summary>
/// This specialized version allows to execute actions on multiple entity views or entity structs
/// Safety checks are in place. This function doesn't guarantee cache
/// friendliness even if just EntityStructs are used.
/// </summary>
/// <param name="groupID"></param>
/// <param name="action"></param>
/// <typeparam name="T"></typeparam>
/// <typeparam name="T1"></typeparam>
void ExecuteOnEntities<T, T1>(int groupID, ActionRef<T, T1> action) where T : IEntityStruct where T1 : IEntityStruct;
void ExecuteOnEntities<T, T1>(ActionRef<T, T1> action) where T : IEntityStruct where T1 : IEntityStruct;
void ExecuteOnEntities<T, T1, W>(int groupID, ref W value, ActionRef<T, T1, W> action) where T : IEntityStruct where T1 : IEntityStruct;
void ExecuteOnEntities<T, T1, W>(ref W value, ActionRef<T, T1, W> action) where T : IEntityStruct where T1 : IEntityStruct;
void ExecuteOnEntities<T, T1, W>(W value, ActionRef<T, T1, W> action) where T : IEntityStruct where T1 : IEntityStruct;
/// <summary>
/// Execute an action on ALL the entities regardless the group. This function doesn't guarantee cache
/// friendliness even if just EntityStructs are used.
/// Safety checks are in place
/// </summary>
/// <param name="action"></param>
/// <typeparam name="T"></typeparam>
void ExecuteOnAllEntities<T>(ActionRef<T> action) where T : IEntityStruct;
void ExecuteOnAllEntities<T, W>(ref W value, ActionRef<T, W> action) where T : IEntityStruct;
/// <summary>
/// ECS is meant to work on a set of Entities. Working on a single entity is sometime necessary, but using
/// the following functions inside a loop would be a mistake as performance can be significantly impacted
/// return the buffer and the index of the entity inside the buffer using the input EGID
/// </summary>
/// <param name="entityGid"></param>
/// <param name="index"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
T[] QueryEntitiesAndIndex<T>(EGID entityGid, out uint index) where T : IEntityStruct;
bool TryQueryEntitiesAndIndex<T>(EGID entityGid, out uint index, out T[] array) where T : IEntityStruct;
/// <summary>
/// ECS is meant to work on a set of Entities. Working on a single entity is sometime necessary, but using
/// the following functions inside a loop would be a mistake as performance can be significantly impacted
/// Execute an action on a specific Entity. Be sure that the action is not capturing variables
/// otherwise you will allocate memory which will have a great impact on the execution performance
/// </summary>
/// <param name="egid"></param>
/// <param name="action"></param>
/// <typeparam name="T"></typeparam>
void ExecuteOnEntity<T>(EGID egid, ActionRef<T> action) where T : IEntityStruct;
void ExecuteOnEntity<T>(int id, ActionRef<T> action) where T : IEntityStruct;
void ExecuteOnEntity<T>(int id, int groupid, ActionRef<T> action) where T : IEntityStruct;
void ExecuteOnEntity<T, W>(EGID egid, ref W value, ActionRef<T, W> action) where T : IEntityStruct;
void ExecuteOnEntity<T, W>(int id, ref W value, ActionRef<T, W> action) where T : IEntityStruct;
void ExecuteOnEntity<T, W>(int id, int groupid, ref W value, ActionRef<T, W> action) where T : IEntityStruct;

bool Exists<T>(EGID egid) where T : IEntityStruct;
bool HasAny<T>() where T:IEntityStruct;
bool HasAny<T>(int group) where T:IEntityStruct;
}
}

Loading…
Cancel
Save