public unsafe void ValidateMatchesCache(int foundCacheIndex, ref EntityQueryBuilder builder, int *delegateTypeIndices, int delegateTypeCount) { if (!builder.ShallowEquals(ref m_CacheCheckQueryBuilders[foundCacheIndex])) { goto bad; } var cached = m_CacheCheckDelegateTypeIndices[foundCacheIndex]; if (cached.Length != delegateTypeCount) { goto bad; } for (var i = 0; i < delegateTypeCount; ++i) { if (cached[i] != delegateTypeIndices[i]) { goto bad; } } return; bad: throw new InvalidOperationException("Type signature does not match cached"); }
// this is a specialized function intended only for validation that builders are hashing and getting cached // correctly without unexpected collisions. "Equals" is hard to truly validate because the type may not // fully be constructed yet due to ForEach not getting called yet. internal bool ShallowEquals(ref EntityQueryBuilder other) { #if ENABLE_UNITY_COLLECTIONS_CHECKS if (!ReferenceEquals(m_System, other.m_System)) { throw new InvalidOperationException($"Suspicious comparison of {nameof(EntityQueryBuilder)}s with different {nameof(ComponentSystem)}s"); } #endif return (m_Any.Equals(ref other.m_Any) && m_None.Equals(ref other.m_None) && m_All.Equals(ref other.m_All) && ReferenceEquals(m_Query, other.m_Query)); }
public unsafe int CreateCachedQuery(uint hash, EntityQuery query #if ENABLE_UNITY_COLLECTIONS_CHECKS , ref EntityQueryBuilder builder, int *delegateTypeIndices, int delegateTypeCount #endif ) { #if ENABLE_UNITY_COLLECTIONS_CHECKS if (query == null) { throw new ArgumentNullException(nameof(query)); } #endif var index = 0; // find open slot or create one for (;;) { if (index == m_CacheHashes.Length) { var newSize = m_CacheHashes.Length + Math.Max(m_CacheHashes.Length / 2, 1); UnityEngine.Debug.LogError( $"{nameof(EntityQueryCache)} is too small to hold the current number of queries this {nameof(ComponentSystem)} is running. The cache automatically expanded to {newSize}, " + $"but this may cause a GC. Set cache size at init time via {nameof(ComponentSystem.InitEntityQueryCache)}() to a large enough number to ensure no allocations are required at run time."); Array.Resize(ref m_CacheHashes, newSize); Array.Resize(ref m_CachedEntityQueries, newSize); #if ENABLE_UNITY_COLLECTIONS_CHECKS Array.Resize(ref m_CacheCheckQueryBuilders, newSize); Array.Resize(ref m_CacheCheckDelegateTypeIndices, newSize); #endif break; } if (m_CachedEntityQueries[index] == null) { break; } #if ENABLE_UNITY_COLLECTIONS_CHECKS if (m_CacheHashes[index] == hash) { throw new InvalidOperationException($"Unexpected {nameof(CreateCachedQuery)} with hash {hash} that already exists in cache at slot {index}"); } #endif ++index; } // store in cache m_CacheHashes[index] = hash; m_CachedEntityQueries[index] = query; #if ENABLE_UNITY_COLLECTIONS_CHECKS m_CacheCheckQueryBuilders[index] = builder; var checkDelegateTypeIndices = new int[delegateTypeCount]; for (var i = 0; i < delegateTypeCount; ++i) { checkDelegateTypeIndices[i] = delegateTypeIndices[i]; } m_CacheCheckDelegateTypeIndices[index] = checkDelegateTypeIndices; #endif return(index); }