优化内部组件索引机制(更改为SparseSet索引)减少用户切换索引成本
修复内部系统初始化逻辑 - 不应该再onInitialize中初始内部entities,移动到initialize中 ci跳过cocos项目避免ci失败 soa开放更多安全类型接口
This commit is contained in:
419
packages/core/src/ECS/Utils/ComponentSparseSet.ts
Normal file
419
packages/core/src/ECS/Utils/ComponentSparseSet.ts
Normal file
@@ -0,0 +1,419 @@
|
||||
import { Entity } from '../Entity';
|
||||
import { ComponentType, ComponentRegistry } from '../Core/ComponentStorage';
|
||||
import { IBigIntLike, BigIntFactory } from './BigIntCompatibility';
|
||||
import { SparseSet } from './SparseSet';
|
||||
import { Pool } from '../../Utils/Pool/Pool';
|
||||
import { IPoolable } from '../../Utils/Pool/IPoolable';
|
||||
|
||||
/**
|
||||
* 可池化的实体集合
|
||||
*
|
||||
* 实现IPoolable接口,支持对象池复用以减少内存分配开销。
|
||||
*/
|
||||
class PoolableEntitySet extends Set<Entity> implements IPoolable {
|
||||
constructor(...args: unknown[]) {
|
||||
super();
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 组件稀疏集合实现
|
||||
*
|
||||
* 结合通用稀疏集合和组件位掩码
|
||||
*
|
||||
* 存储结构:
|
||||
* - 稀疏集合存储实体
|
||||
* - 位掩码数组存储组件信息
|
||||
* - 组件类型映射表
|
||||
*/
|
||||
export class ComponentSparseSet {
|
||||
/**
|
||||
* 实体稀疏集合
|
||||
*
|
||||
* 存储所有拥有组件的实体,提供O(1)的实体操作。
|
||||
*/
|
||||
private _entities: SparseSet<Entity>;
|
||||
|
||||
/**
|
||||
* 组件位掩码数组
|
||||
*
|
||||
* 与实体稀疏集合的密集数组对应,存储每个实体的组件位掩码。
|
||||
* 数组索引与稀疏集合的密集数组索引一一对应。
|
||||
*/
|
||||
private _componentMasks: IBigIntLike[] = [];
|
||||
|
||||
/**
|
||||
* 组件类型到实体集合的映射
|
||||
*
|
||||
* 维护每个组件类型对应的实体集合,用于快速的单组件查询。
|
||||
*/
|
||||
private _componentToEntities = new Map<ComponentType, PoolableEntitySet>();
|
||||
|
||||
/**
|
||||
* 实体集合对象池
|
||||
*
|
||||
* 使用core库的Pool系统来管理PoolableEntitySet对象的复用。
|
||||
*/
|
||||
private static _entitySetPool = Pool.getPool(PoolableEntitySet, 50, 512);
|
||||
|
||||
constructor() {
|
||||
this._entities = new SparseSet<Entity>();
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加实体到组件索引
|
||||
*
|
||||
* 分析实体的组件组成,生成位掩码,并更新所有相关索引。
|
||||
*
|
||||
* @param entity 要添加的实体
|
||||
*/
|
||||
public addEntity(entity: Entity): void {
|
||||
// 如果实体已存在,先移除旧数据
|
||||
if (this._entities.has(entity)) {
|
||||
this.removeEntity(entity);
|
||||
}
|
||||
|
||||
let componentMask = BigIntFactory.zero();
|
||||
const entityComponents = new Set<ComponentType>();
|
||||
|
||||
// 分析实体组件并构建位掩码
|
||||
for (const component of entity.components) {
|
||||
const componentType = component.constructor as ComponentType;
|
||||
entityComponents.add(componentType);
|
||||
|
||||
// 确保组件类型已注册
|
||||
if (!ComponentRegistry.isRegistered(componentType)) {
|
||||
ComponentRegistry.register(componentType);
|
||||
}
|
||||
|
||||
// 获取组件位掩码并合并
|
||||
const bitMask = ComponentRegistry.getBitMask(componentType);
|
||||
componentMask = componentMask.or(bitMask);
|
||||
}
|
||||
|
||||
// 添加实体到稀疏集合
|
||||
this._entities.add(entity);
|
||||
const entityIndex = this._entities.getIndex(entity)!;
|
||||
|
||||
// 确保位掩码数组有足够空间
|
||||
while (this._componentMasks.length <= entityIndex) {
|
||||
this._componentMasks.push(BigIntFactory.zero());
|
||||
}
|
||||
this._componentMasks[entityIndex] = componentMask;
|
||||
|
||||
// 更新组件类型到实体的映射
|
||||
this.updateComponentMappings(entity, entityComponents, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从组件索引中移除实体
|
||||
*
|
||||
* 清理实体相关的所有索引数据,保持数据结构的紧凑性。
|
||||
*
|
||||
* @param entity 要移除的实体
|
||||
*/
|
||||
public removeEntity(entity: Entity): void {
|
||||
const entityIndex = this._entities.getIndex(entity);
|
||||
if (entityIndex === undefined) {
|
||||
return; // 实体不存在
|
||||
}
|
||||
|
||||
// 获取实体的组件类型集合
|
||||
const entityComponents = this.getEntityComponentTypes(entity);
|
||||
|
||||
// 更新组件类型到实体的映射
|
||||
this.updateComponentMappings(entity, entityComponents, false);
|
||||
|
||||
// 从稀疏集合中移除实体
|
||||
this._entities.remove(entity);
|
||||
|
||||
// 维护位掩码数组的紧凑性
|
||||
const lastIndex = this._componentMasks.length - 1;
|
||||
if (entityIndex !== lastIndex) {
|
||||
// 将最后一个位掩码移动到当前位置
|
||||
this._componentMasks[entityIndex] = this._componentMasks[lastIndex];
|
||||
}
|
||||
this._componentMasks.pop();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询包含指定组件的所有实体
|
||||
*
|
||||
* @param componentType 组件类型
|
||||
* @returns 包含该组件的实体集合
|
||||
*/
|
||||
public queryByComponent(componentType: ComponentType): Set<Entity> {
|
||||
const entities = this._componentToEntities.get(componentType);
|
||||
return entities ? new Set(entities) : new Set<Entity>();
|
||||
}
|
||||
|
||||
/**
|
||||
* 多组件查询(AND操作)
|
||||
*
|
||||
* 查找同时包含所有指定组件的实体。
|
||||
*
|
||||
* @param componentTypes 组件类型数组
|
||||
* @returns 满足条件的实体集合
|
||||
*/
|
||||
public queryMultipleAnd(componentTypes: ComponentType[]): Set<Entity> {
|
||||
if (componentTypes.length === 0) {
|
||||
return new Set<Entity>();
|
||||
}
|
||||
|
||||
if (componentTypes.length === 1) {
|
||||
return this.queryByComponent(componentTypes[0]);
|
||||
}
|
||||
|
||||
// 构建目标位掩码
|
||||
let targetMask = BigIntFactory.zero();
|
||||
for (const componentType of componentTypes) {
|
||||
if (!ComponentRegistry.isRegistered(componentType)) {
|
||||
return new Set<Entity>(); // 未注册的组件类型,结果为空
|
||||
}
|
||||
const bitMask = ComponentRegistry.getBitMask(componentType);
|
||||
targetMask = targetMask.or(bitMask);
|
||||
}
|
||||
|
||||
const result = ComponentSparseSet._entitySetPool.obtain();
|
||||
|
||||
// 遍历所有实体,检查位掩码匹配
|
||||
this._entities.forEach((entity, index) => {
|
||||
const entityMask = this._componentMasks[index];
|
||||
if ((entityMask.and(targetMask)).equals(targetMask)) {
|
||||
result.add(entity);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 多组件查询(OR操作)
|
||||
*
|
||||
* 查找包含任意一个指定组件的实体。
|
||||
*
|
||||
* @param componentTypes 组件类型数组
|
||||
* @returns 满足条件的实体集合
|
||||
*/
|
||||
public queryMultipleOr(componentTypes: ComponentType[]): Set<Entity> {
|
||||
if (componentTypes.length === 0) {
|
||||
return new Set<Entity>();
|
||||
}
|
||||
|
||||
if (componentTypes.length === 1) {
|
||||
return this.queryByComponent(componentTypes[0]);
|
||||
}
|
||||
|
||||
// 构建目标位掩码
|
||||
let targetMask = BigIntFactory.zero();
|
||||
for (const componentType of componentTypes) {
|
||||
if (ComponentRegistry.isRegistered(componentType)) {
|
||||
const bitMask = ComponentRegistry.getBitMask(componentType);
|
||||
targetMask = targetMask.or(bitMask);
|
||||
}
|
||||
}
|
||||
|
||||
if (targetMask.equals(BigIntFactory.zero())) {
|
||||
return new Set<Entity>(); // 没有有效的组件类型
|
||||
}
|
||||
|
||||
const result = ComponentSparseSet._entitySetPool.obtain();
|
||||
|
||||
// 遍历所有实体,检查位掩码匹配
|
||||
this._entities.forEach((entity, index) => {
|
||||
const entityMask = this._componentMasks[index];
|
||||
if (!(entityMask.and(targetMask)).equals(BigIntFactory.zero())) {
|
||||
result.add(entity);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查实体是否包含指定组件
|
||||
*
|
||||
* @param entity 实体
|
||||
* @param componentType 组件类型
|
||||
* @returns 是否包含该组件
|
||||
*/
|
||||
public hasComponent(entity: Entity, componentType: ComponentType): boolean {
|
||||
const entityIndex = this._entities.getIndex(entity);
|
||||
if (entityIndex === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ComponentRegistry.isRegistered(componentType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const entityMask = this._componentMasks[entityIndex];
|
||||
const componentMask = ComponentRegistry.getBitMask(componentType);
|
||||
|
||||
return !(entityMask.and(componentMask)).equals(BigIntFactory.zero());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体的组件位掩码
|
||||
*
|
||||
* @param entity 实体
|
||||
* @returns 组件位掩码,如果实体不存在则返回undefined
|
||||
*/
|
||||
public getEntityMask(entity: Entity): IBigIntLike | undefined {
|
||||
const entityIndex = this._entities.getIndex(entity);
|
||||
if (entityIndex === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
return this._componentMasks[entityIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有实体
|
||||
*
|
||||
* @returns 所有实体的数组
|
||||
*/
|
||||
public getAllEntities(): Entity[] {
|
||||
return this._entities.toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体数量
|
||||
*/
|
||||
public get size(): number {
|
||||
return this._entities.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否为空
|
||||
*/
|
||||
public get isEmpty(): boolean {
|
||||
return this._entities.isEmpty;
|
||||
}
|
||||
|
||||
/**
|
||||
* 遍历所有实体
|
||||
*
|
||||
* @param callback 遍历回调函数
|
||||
*/
|
||||
public forEach(callback: (entity: Entity, mask: IBigIntLike, index: number) => void): void {
|
||||
this._entities.forEach((entity, index) => {
|
||||
callback(entity, this._componentMasks[index], index);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有数据
|
||||
*/
|
||||
public clear(): void {
|
||||
this._entities.clear();
|
||||
this._componentMasks.length = 0;
|
||||
|
||||
// 清理时将所有持有的实体集合返回到池中
|
||||
for (const entitySet of this._componentToEntities.values()) {
|
||||
ComponentSparseSet._entitySetPool.release(entitySet);
|
||||
}
|
||||
this._componentToEntities.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取内存使用统计
|
||||
*/
|
||||
public getMemoryStats(): {
|
||||
entitiesMemory: number;
|
||||
masksMemory: number;
|
||||
mappingsMemory: number;
|
||||
totalMemory: number;
|
||||
} {
|
||||
const entitiesStats = this._entities.getMemoryStats();
|
||||
const masksMemory = this._componentMasks.length * 16; // 估计每个BigInt 16字节
|
||||
|
||||
let mappingsMemory = this._componentToEntities.size * 16; // Map条目开销
|
||||
for (const entitySet of this._componentToEntities.values()) {
|
||||
mappingsMemory += entitySet.size * 8; // 每个实体引用8字节
|
||||
}
|
||||
|
||||
return {
|
||||
entitiesMemory: entitiesStats.totalMemory,
|
||||
masksMemory,
|
||||
mappingsMemory,
|
||||
totalMemory: entitiesStats.totalMemory + masksMemory + mappingsMemory
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证数据结构完整性
|
||||
*/
|
||||
public validate(): boolean {
|
||||
// 检查稀疏集合的有效性
|
||||
if (!this._entities.validate()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查位掩码数组长度一致性
|
||||
if (this._componentMasks.length !== this._entities.size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查组件映射的一致性
|
||||
const allMappedEntities = new Set<Entity>();
|
||||
for (const entitySet of this._componentToEntities.values()) {
|
||||
for (const entity of entitySet) {
|
||||
allMappedEntities.add(entity);
|
||||
}
|
||||
}
|
||||
|
||||
// 验证映射中的实体都在稀疏集合中
|
||||
for (const entity of allMappedEntities) {
|
||||
if (!this._entities.has(entity)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体的组件类型集合
|
||||
*/
|
||||
private getEntityComponentTypes(entity: Entity): Set<ComponentType> {
|
||||
const componentTypes = new Set<ComponentType>();
|
||||
for (const component of entity.components) {
|
||||
componentTypes.add(component.constructor as ComponentType);
|
||||
}
|
||||
return componentTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新组件类型到实体的映射
|
||||
*/
|
||||
private updateComponentMappings(
|
||||
entity: Entity,
|
||||
componentTypes: Set<ComponentType>,
|
||||
add: boolean
|
||||
): void {
|
||||
for (const componentType of componentTypes) {
|
||||
let entities = this._componentToEntities.get(componentType);
|
||||
|
||||
if (add) {
|
||||
if (!entities) {
|
||||
entities = ComponentSparseSet._entitySetPool.obtain();
|
||||
this._componentToEntities.set(componentType, entities);
|
||||
}
|
||||
entities.add(entity);
|
||||
} else {
|
||||
if (entities) {
|
||||
entities.delete(entity);
|
||||
if (entities.size === 0) {
|
||||
this._componentToEntities.delete(componentType);
|
||||
ComponentSparseSet._entitySetPool.release(entities);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
310
packages/core/src/ECS/Utils/SparseSet.ts
Normal file
310
packages/core/src/ECS/Utils/SparseSet.ts
Normal file
@@ -0,0 +1,310 @@
|
||||
/**
|
||||
* 稀疏集合实现
|
||||
*
|
||||
* 提供O(1)的插入、删除、查找操作,同时保持数据的紧凑存储。
|
||||
* 使用密集数组存储实际数据,稀疏映射提供快速访问
|
||||
*
|
||||
* @template T 存储的数据类型
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const sparseSet = new SparseSet<Entity>();
|
||||
*
|
||||
* sparseSet.add(entity1);
|
||||
* sparseSet.add(entity2);
|
||||
*
|
||||
* if (sparseSet.has(entity1)) {
|
||||
* sparseSet.remove(entity1);
|
||||
* }
|
||||
*
|
||||
* sparseSet.forEach((entity, index) => {
|
||||
* console.log(`Entity at index ${index}: ${entity.name}`);
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
export class SparseSet<T> {
|
||||
/**
|
||||
* 密集存储数组
|
||||
*
|
||||
* 连续存储所有有效数据,确保遍历时的缓存友好性。
|
||||
*/
|
||||
private _dense: T[] = [];
|
||||
|
||||
/**
|
||||
* 稀疏映射表
|
||||
*
|
||||
* 将数据项映射到密集数组中的索引,提供O(1)的查找性能。
|
||||
*/
|
||||
private _sparse = new Map<T, number>();
|
||||
|
||||
/**
|
||||
* 添加元素到集合
|
||||
*
|
||||
* @param item 要添加的元素
|
||||
* @returns 是否成功添加(false表示元素已存在)
|
||||
*/
|
||||
public add(item: T): boolean {
|
||||
if (this._sparse.has(item)) {
|
||||
return false; // 元素已存在
|
||||
}
|
||||
|
||||
const index = this._dense.length;
|
||||
this._dense.push(item);
|
||||
this._sparse.set(item, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从集合中移除元素
|
||||
*
|
||||
* 使用swap-and-pop技术保持数组紧凑性:
|
||||
* 1. 将要删除的元素与最后一个元素交换
|
||||
* 2. 删除最后一个元素
|
||||
* 3. 更新映射表
|
||||
*
|
||||
* @param item 要移除的元素
|
||||
* @returns 是否成功移除(false表示元素不存在)
|
||||
*/
|
||||
public remove(item: T): boolean {
|
||||
const index = this._sparse.get(item);
|
||||
if (index === undefined) {
|
||||
return false; // 元素不存在
|
||||
}
|
||||
|
||||
const lastIndex = this._dense.length - 1;
|
||||
|
||||
// 如果不是最后一个元素,则与最后一个元素交换
|
||||
if (index !== lastIndex) {
|
||||
const lastItem = this._dense[lastIndex];
|
||||
this._dense[index] = lastItem;
|
||||
this._sparse.set(lastItem, index);
|
||||
}
|
||||
|
||||
// 移除最后一个元素
|
||||
this._dense.pop();
|
||||
this._sparse.delete(item);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查元素是否存在于集合中
|
||||
*
|
||||
* @param item 要检查的元素
|
||||
* @returns 元素是否存在
|
||||
*/
|
||||
public has(item: T): boolean {
|
||||
return this._sparse.has(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取元素在密集数组中的索引
|
||||
*
|
||||
* @param item 要查询的元素
|
||||
* @returns 索引,如果元素不存在则返回undefined
|
||||
*/
|
||||
public getIndex(item: T): number | undefined {
|
||||
return this._sparse.get(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据索引获取元素
|
||||
*
|
||||
* @param index 索引
|
||||
* @returns 元素,如果索引无效则返回undefined
|
||||
*/
|
||||
public getByIndex(index: number): T | undefined {
|
||||
return this._dense[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取集合大小
|
||||
*/
|
||||
public get size(): number {
|
||||
return this._dense.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查集合是否为空
|
||||
*/
|
||||
public get isEmpty(): boolean {
|
||||
return this._dense.length === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 遍历集合中的所有元素
|
||||
*
|
||||
* 保证遍历顺序与添加顺序一致(除非中间有删除操作)。
|
||||
* 遍历性能优秀,因为数据在内存中连续存储。
|
||||
*
|
||||
* @param callback 遍历回调函数
|
||||
*/
|
||||
public forEach(callback: (item: T, index: number) => void): void {
|
||||
for (let i = 0; i < this._dense.length; i++) {
|
||||
callback(this._dense[i], i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 映射集合中的所有元素
|
||||
*
|
||||
* @param callback 映射回调函数
|
||||
* @returns 映射后的新数组
|
||||
*/
|
||||
public map<U>(callback: (item: T, index: number) => U): U[] {
|
||||
const result: U[] = [];
|
||||
for (let i = 0; i < this._dense.length; i++) {
|
||||
result.push(callback(this._dense[i], i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤集合中的元素
|
||||
*
|
||||
* @param predicate 过滤条件
|
||||
* @returns 满足条件的元素数组
|
||||
*/
|
||||
public filter(predicate: (item: T, index: number) => boolean): T[] {
|
||||
const result: T[] = [];
|
||||
for (let i = 0; i < this._dense.length; i++) {
|
||||
if (predicate(this._dense[i], i)) {
|
||||
result.push(this._dense[i]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找第一个满足条件的元素
|
||||
*
|
||||
* @param predicate 查找条件
|
||||
* @returns 找到的元素,如果没有则返回undefined
|
||||
*/
|
||||
public find(predicate: (item: T, index: number) => boolean): T | undefined {
|
||||
for (let i = 0; i < this._dense.length; i++) {
|
||||
if (predicate(this._dense[i], i)) {
|
||||
return this._dense[i];
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否存在满足条件的元素
|
||||
*
|
||||
* @param predicate 检查条件
|
||||
* @returns 是否存在满足条件的元素
|
||||
*/
|
||||
public some(predicate: (item: T, index: number) => boolean): boolean {
|
||||
for (let i = 0; i < this._dense.length; i++) {
|
||||
if (predicate(this._dense[i], i)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否所有元素都满足条件
|
||||
*
|
||||
* @param predicate 检查条件
|
||||
* @returns 是否所有元素都满足条件
|
||||
*/
|
||||
public every(predicate: (item: T, index: number) => boolean): boolean {
|
||||
for (let i = 0; i < this._dense.length; i++) {
|
||||
if (!predicate(this._dense[i], i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取密集数组的只读副本
|
||||
*
|
||||
* 返回数组的浅拷贝,确保外部无法直接修改内部数据。
|
||||
*/
|
||||
public getDenseArray(): readonly T[] {
|
||||
return [...this._dense];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取密集数组的直接引用(内部使用)
|
||||
*
|
||||
* 警告:直接修改返回的数组会破坏数据结构的完整性。
|
||||
* 仅在性能关键场景下使用,并确保不会修改数组内容。
|
||||
*/
|
||||
public getDenseArrayUnsafe(): readonly T[] {
|
||||
return this._dense;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空集合
|
||||
*/
|
||||
public clear(): void {
|
||||
this._dense.length = 0;
|
||||
this._sparse.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为数组
|
||||
*/
|
||||
public toArray(): T[] {
|
||||
return [...this._dense];
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为Set
|
||||
*/
|
||||
public toSet(): Set<T> {
|
||||
return new Set(this._dense);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取内存使用统计信息
|
||||
*/
|
||||
public getMemoryStats(): {
|
||||
denseArraySize: number;
|
||||
sparseMapSize: number;
|
||||
totalMemory: number;
|
||||
} {
|
||||
const denseArraySize = this._dense.length * 8; // 估计每个引用8字节
|
||||
const sparseMapSize = this._sparse.size * 16; // 估计每个Map条目16字节
|
||||
|
||||
return {
|
||||
denseArraySize,
|
||||
sparseMapSize,
|
||||
totalMemory: denseArraySize + sparseMapSize
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证数据结构的完整性
|
||||
*
|
||||
* 调试用方法,检查内部数据结构是否一致。
|
||||
*/
|
||||
public validate(): boolean {
|
||||
// 检查大小一致性
|
||||
if (this._dense.length !== this._sparse.size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查映射关系的正确性
|
||||
for (let i = 0; i < this._dense.length; i++) {
|
||||
const item = this._dense[i];
|
||||
const mappedIndex = this._sparse.get(item);
|
||||
if (mappedIndex !== i) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查稀疏映射中的所有项都在密集数组中
|
||||
for (const [item, index] of this._sparse) {
|
||||
if (index >= this._dense.length || this._dense[index] !== item) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -5,4 +5,6 @@ export { IdentifierPool } from './IdentifierPool';
|
||||
export { Matcher } from './Matcher';
|
||||
export { Bits } from './Bits';
|
||||
export { ComponentTypeManager } from './ComponentTypeManager';
|
||||
export { BigIntFactory } from './BigIntCompatibility';
|
||||
export { BigIntFactory } from './BigIntCompatibility';
|
||||
export { SparseSet } from './SparseSet';
|
||||
export { ComponentSparseSet } from './ComponentSparseSet';
|
||||
Reference in New Issue
Block a user