using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Threading; using Svelto.DataStructures; using Svelto.ECS.Internal; namespace Svelto.ECS.Experimental { struct GroupsList { public static GroupsList Init() { var group = new GroupsList(); group._groups = new FasterList(); group._sets = new HashSet(); return group; } public void Reset() { _sets.Clear(); } public void AddRange(ExclusiveGroupStruct[] groupsToAdd, int length) { for (var i = 0; i < length; i++) _sets.Add(groupsToAdd[i]); } public void Add(ExclusiveGroupStruct group) { _sets.Add(group); } public void Exclude(ExclusiveGroupStruct[] groupsToIgnore, int length) { for (var i = 0; i < length; i++) _sets.Remove(groupsToIgnore[i]); } public void Exclude(ExclusiveGroupStruct groupsToIgnore) { _sets.Remove(groupsToIgnore); } public void Resize(uint preparecount) { _groups.Resize(preparecount); } public FasterList Evaluate() { _groups.Clear(); foreach (var item in _sets) _groups.Add(item); return _groups; } FasterList _groups; HashSet _sets; } //I am not 100% sure why I made this thread-safe since it cannot be used inside jobs. public ref struct QueryGroups { static readonly ThreadLocal groups; static QueryGroups() { groups = new ThreadLocal(GroupsList.Init); } public QueryGroups(LocalFasterReadOnlyList groups) { var groupsValue = QueryGroups.groups.Value; groupsValue.Reset(); groupsValue.AddRange(groups.ToArrayFast(out var count), count); } public QueryGroups(ExclusiveGroupStruct group) { var groupsValue = groups.Value; groupsValue.Reset(); groupsValue.Add(group); } public QueryGroups(uint preparecount) { var groupsValue = groups.Value; groupsValue.Reset(); groupsValue.Resize(preparecount); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public QueryGroups Union(ExclusiveGroupStruct group) { var groupsValue = groups.Value; groupsValue.Add(group); return this; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public QueryGroups Union(LocalFasterReadOnlyList groups) { var groupsValue = QueryGroups.groups.Value; groupsValue.AddRange(groups.ToArrayFast(out var count), count); return this; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public QueryGroups Except(ExclusiveGroupStruct group) { var groupsValue = groups.Value; groupsValue.Exclude(group); return this; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public QueryGroups Except(ExclusiveGroupStruct[] groupsToIgnore) { var groupsValue = groups.Value; groupsValue.Exclude(groupsToIgnore, groupsToIgnore.Length); return this; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public QueryGroups Except(LocalFasterReadOnlyList groupsToIgnore) { var groupsValue = groups.Value; groupsValue.Exclude(groupsToIgnore.ToArrayFast(out var count), count); return this; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public QueryGroups Except(FasterList groupsToIgnore) { var groupsValue = groups.Value; groupsValue.Exclude(groupsToIgnore.ToArrayFast(out var count), count); return this; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public QueryGroups Except(FasterReadOnlyList groupsToIgnore) { var groupsValue = groups.Value; groupsValue.Exclude(groupsToIgnore.ToArrayFast(out var count), count); return this; } // public QueryGroups WithAny(EntitiesDB entitiesDB) // where T : struct, IEntityComponent // { // var group = groups.Value.reference; // var groupsCount = group.count; // // for (uint i = 0; i < groupsCount; i++) // { // if (entitiesDB.Count(group[i]) == 0) // { // group.UnorderedRemoveAt(i); // i--; // groupsCount--; // } // } // // return this; // } public QueryResult Evaluate() { var groupsValue = groups.Value; return new QueryResult(groupsValue.Evaluate()); } public void Evaluate(FasterList group) { var groupsValue = groups.Value; groupsValue.Evaluate().CopyTo(group.ToArrayFast(out var count), count); } } public readonly ref struct QueryResult { public QueryResult(FasterList group) { _group = group; } public LocalFasterReadOnlyList result => _group; readonly FasterReadOnlyList _group; [MethodImpl(MethodImplOptions.AggressiveInlining)] public int Count(EntitiesDB entitiesDB) where T : struct, _IInternalEntityComponent { var count = 0; var groupsCount = result.count; for (var i = 0; i < groupsCount; ++i) count += entitiesDB.Count(result[i]); return count; } public int Max(EntitiesDB entitiesDB) where T : struct, _IInternalEntityComponent { var max = 0; var groupsCount = result.count; for (var i = 0; i < groupsCount; ++i) { var count = entitiesDB.Count(result[i]); if (count > max) max = count; } return max; } } }