using Svelto.DataStructures; using Svelto.ECS.Internal; namespace Svelto.ECS { public partial class EnginesRoot { internal class DoubleBufferedEntitiesToAdd { const int MaximumNumberOfItemsPerFrameBeforeToClear = 100; internal void Swap() { Swap(ref current, ref other); Swap(ref currentEntitiesCreatedPerGroup, ref otherEntitiesCreatedPerGroup); } void Swap(ref T item1, ref T item2) { var toSwap = item2; item2 = item1; item1 = toSwap; } public void ClearOther() { //do not clear the groups created so far, they will be reused, unless they are too many! var otherCount = other.count; if (otherCount > MaximumNumberOfItemsPerFrameBeforeToClear) { FasterDictionary[] otherValuesArray = other.unsafeValues; for (int i = 0; i < otherCount; ++i) { var safeDictionariesCount = otherValuesArray[i].count; ITypeSafeDictionary[] safeDictionaries = otherValuesArray[i].unsafeValues; { for (int j = 0; j < safeDictionariesCount; ++j) { //clear the dictionary of entities create do far (it won't allocate though) safeDictionaries[j].Dispose(); } } } //reset the number of entities created so far otherEntitiesCreatedPerGroup.FastClear(); other.FastClear(); return; } { FasterDictionary[] otherValuesArray = other.unsafeValues; for (int i = 0; i < otherCount; ++i) { var safeDictionariesCount = otherValuesArray[i].count; ITypeSafeDictionary[] safeDictionaries = otherValuesArray[i].unsafeValues; //do not remove the dictionaries of entities per type created so far, they will be reused if (safeDictionariesCount <= MaximumNumberOfItemsPerFrameBeforeToClear) { for (int j = 0; j < safeDictionariesCount; ++j) { //clear the dictionary of entities create do far (it won't allocate though) safeDictionaries[j].FastClear(); } } else { for (int j = 0; j < safeDictionariesCount; ++j) { //clear the dictionary of entities create do far (it won't allocate though) safeDictionaries[j].Dispose(); } otherValuesArray[i].FastClear(); } } //reset the number of entities created so far otherEntitiesCreatedPerGroup.FastClear(); } } //Before I tried for the third time to use a SparseSet instead of FasterDictionary, remember that //while group indices are sequential, they may not be used in a sequential order. Sparseset needs //entities to be created sequentially (the index cannot be managed externally) internal FasterDictionary> current; internal FasterDictionary> other; /// /// To avoid extra allocation, I don't clear the groups, so I need an extra data structure /// to keep count of the number of entities built this frame. At the moment the actual number /// of entities built is not used /// FasterDictionary currentEntitiesCreatedPerGroup; FasterDictionary otherEntitiesCreatedPerGroup; readonly FasterDictionary> _entityComponentsToAddBufferA = new FasterDictionary>(); readonly FasterDictionary> _entityComponentsToAddBufferB = new FasterDictionary>(); readonly FasterDictionary _entitiesCreatedPerGroupA = new FasterDictionary(); readonly FasterDictionary _entitiesCreatedPerGroupB = new FasterDictionary(); public DoubleBufferedEntitiesToAdd() { currentEntitiesCreatedPerGroup = _entitiesCreatedPerGroupA; otherEntitiesCreatedPerGroup = _entitiesCreatedPerGroupB; current = _entityComponentsToAddBufferA; other = _entityComponentsToAddBufferB; } public void Dispose() { { var otherValuesArray = other.unsafeValues; for (int i = 0; i < other.count; ++i) { var safeDictionariesCount = otherValuesArray[i].count; var safeDictionaries = otherValuesArray[i].unsafeValues; //do not remove the dictionaries of entities per type created so far, they will be reused for (int j = 0; j < safeDictionariesCount; ++j) { //clear the dictionary of entities create do far (it won't allocate though) safeDictionaries[j].Dispose(); } } } { var currentValuesArray = current.unsafeValues; for (int i = 0; i < current.count; ++i) { var safeDictionariesCount = currentValuesArray[i].count; var safeDictionaries = currentValuesArray[i].unsafeValues; //do not remove the dictionaries of entities per type created so far, they will be reused for (int j = 0; j < safeDictionariesCount; ++j) { //clear the dictionary of entities create do far (it won't allocate though) safeDictionaries[j].Dispose(); } } } } internal void IncrementEntityCount(ExclusiveGroupStruct groupID) { currentEntitiesCreatedPerGroup.GetOrCreate(groupID)++; } internal bool AnyEntityCreated() { return currentEntitiesCreatedPerGroup.count > 0; } internal bool AnyOtherEntityCreated() { return otherEntitiesCreatedPerGroup.count > 0; } internal void Preallocate (ExclusiveGroupStruct groupID, uint numberOfEntities, IComponentBuilder[] entityComponentsToBuild) { void PreallocateDictionaries(FasterDictionary> fasterDictionary1) { FasterDictionary group = fasterDictionary1.GetOrCreate((uint) groupID, () => new FasterDictionary()); foreach (var componentBuilder in entityComponentsToBuild) { var entityComponentType = componentBuilder.GetEntityComponentType(); var safeDictionary = @group.GetOrCreate(new RefWrapperType(entityComponentType) , () => componentBuilder.CreateDictionary(numberOfEntities)); componentBuilder.Preallocate(safeDictionary, numberOfEntities); } } PreallocateDictionaries(current); PreallocateDictionaries(other); currentEntitiesCreatedPerGroup.GetOrCreate(groupID); otherEntitiesCreatedPerGroup.GetOrCreate(groupID); } } } }