支持分层 BitMask 自动扩容,避免用户超过组件后报错问题

This commit is contained in:
YHH
2025-09-30 15:38:50 +08:00
parent 0969d09da1
commit db73b077c5
4 changed files with 158 additions and 38 deletions

View File

@@ -1,15 +1,16 @@
/** /**
* 64位掩码兼容层 * 位掩码数据结构
*/ * 基础模式64位使用 lo + hi 存储 64 位segments 为空
* 扩展模式128+位lo + hi 作为第一段segments 存储额外的 64 位段
/** * segments[0] 对应 bit 64-127segments[1] 对应 bit 128-191以此类推
* 64位掩码数据结构使用两个32位整数表示
*/ */
export interface BitMask64Data { export interface BitMask64Data {
/** 低32位 */ /** 低32位bit 0-31 */
lo: number; lo: number;
/** 高32位 */ /** 高32位bit 32-63 */
hi: number; hi: number;
/** 扩展段数组,每个元素是一个 64 位段,用于超过 64 位的场景 */
segments?: BitMask64Data[];
} }
export class BitMask64Utils { export class BitMask64Utils {
@@ -55,12 +56,44 @@ export class BitMask64Utils {
/** /**
* 检查掩码是否包含所有指定的位 * 检查掩码是否包含所有指定的位
* 支持扩展模式,自动处理超过 64 位的掩码
* @param mask 要检查的掩码 * @param mask 要检查的掩码
* @param bits 指定的位模式 * @param bits 指定的位模式
* @returns 如果掩码包含bits中的所有位则返回true * @returns 如果掩码包含bits中的所有位则返回true
*/ */
public static hasAll(mask: BitMask64Data, bits: BitMask64Data): boolean { public static hasAll(mask: BitMask64Data, bits: BitMask64Data): boolean {
return (mask.lo & bits.lo) === bits.lo && (mask.hi & bits.hi) === bits.hi; // 检查第一个 64 位段
if ((mask.lo & bits.lo) !== bits.lo || (mask.hi & bits.hi) !== bits.hi) {
return false;
}
// 如果 bits 没有扩展段,检查完成
if (!bits.segments || bits.segments.length === 0) {
return true;
}
// 如果 bits 有扩展段但 mask 没有,返回 false
if (!mask.segments || mask.segments.length === 0) {
// 检查 bits 的扩展段是否全为 0
return bits.segments.every(seg => BitMask64Utils.isZero(seg));
}
// 递归检查每个扩展段
const minSegments = Math.min(mask.segments.length, bits.segments.length);
for (let i = 0; i < minSegments; i++) {
if (!BitMask64Utils.hasAll(mask.segments[i], bits.segments[i])) {
return false;
}
}
// 如果 bits 有更多段,检查这些段是否为空
for (let i = minSegments; i < bits.segments.length; i++) {
if (!BitMask64Utils.isZero(bits.segments[i])) {
return false;
}
}
return true;
} }
/** /**
@@ -237,4 +270,95 @@ export class BitMask64Utils {
return count; return count;
} }
/**
* 设置扩展位(支持超过 64 位的索引)
* @param mask 要修改的掩码(原地修改)
* @param bitIndex 位索引(可以超过 63
*/
public static setBitExtended(mask: BitMask64Data, bitIndex: number): void {
if (bitIndex < 0) {
throw new Error('Bit index cannot be negative');
}
if (bitIndex < 64) {
BitMask64Utils.setBit(mask, bitIndex);
return;
}
// 计算段索引和段内位索引
const segmentIndex = Math.floor(bitIndex / 64) - 1;
const localBitIndex = bitIndex % 64;
// 确保 segments 数组存在
if (!mask.segments) {
mask.segments = [];
}
// 扩展 segments 数组
while (mask.segments.length <= segmentIndex) {
mask.segments.push(BitMask64Utils.clone(BitMask64Utils.ZERO));
}
// 设置对应段的位
BitMask64Utils.setBit(mask.segments[segmentIndex], localBitIndex);
}
/**
* 获取扩展位(支持超过 64 位的索引)
* @param mask 要检查的掩码
* @param bitIndex 位索引(可以超过 63
* @returns 如果位被设置则返回 true
*/
public static getBitExtended(mask: BitMask64Data, bitIndex: number): boolean {
if (bitIndex < 0) {
return false;
}
if (bitIndex < 64) {
const testMask = BitMask64Utils.create(bitIndex);
return BitMask64Utils.hasAny(mask, testMask);
}
if (!mask.segments) {
return false;
}
const segmentIndex = Math.floor(bitIndex / 64) - 1;
if (segmentIndex >= mask.segments.length) {
return false;
}
const localBitIndex = bitIndex % 64;
const testMask = BitMask64Utils.create(localBitIndex);
return BitMask64Utils.hasAny(mask.segments[segmentIndex], testMask);
}
/**
* 清除扩展位(支持超过 64 位的索引)
* @param mask 要修改的掩码(原地修改)
* @param bitIndex 位索引(可以超过 63
*/
public static clearBitExtended(mask: BitMask64Data, bitIndex: number): void {
if (bitIndex < 0) {
return;
}
if (bitIndex < 64) {
BitMask64Utils.clearBit(mask, bitIndex);
return;
}
if (!mask.segments) {
return;
}
const segmentIndex = Math.floor(bitIndex / 64) - 1;
if (segmentIndex >= mask.segments.length) {
return;
}
const localBitIndex = bitIndex % 64;
BitMask64Utils.clearBit(mask.segments[segmentIndex], localBitIndex);
}
} }

View File

@@ -1,11 +1,12 @@
import { BitMask64Data, BitMask64Utils } from './BigIntCompatibility'; import { BitMask64Data, BitMask64Utils } from './BigIntCompatibility';
/** /**
* 64位位集合类,用于高效的位操作 * 位集合类,用于高效的位操作
* 支持最多64个位的设置、清除、查询和逻辑运算 * 自动扩展支持:默认 64 位,超过时自动扩展到 128/256 位
* 扩展模式性能略有下降,但仍然比数组遍历快得多
*/ */
export class Bits { export class Bits {
/** 存储位数据的64位掩码 */ /** 存储位数据的掩码,支持扩展 */
private _value: BitMask64Data; private _value: BitMask64Data;
/** /**
@@ -27,24 +28,21 @@ export class Bits {
/** /**
* 设置指定位为1 * 设置指定位为1
* @param index 位索引,范围 [0, 63] * 自动扩展:当索引超过 64 时,自动扩展到 128/256 位
* @throws 当位索引为负数或超过64位限制时抛出错误 * @param index 位索引0-based
* @throws 当位索引为负数时抛出错误
*/ */
public set(index: number): void { public set(index: number): void {
if (index < 0) { if (index < 0) {
throw new Error('Bit index cannot be negative'); throw new Error('Bit index cannot be negative');
} }
if (index >= 64) { BitMask64Utils.setBitExtended(this._value, index);
throw new Error('Bit index exceeds 64-bit limit. ECS framework supports max 64 component types.');
}
BitMask64Utils.setBit(this._value, index);
} }
/** /**
* 清除指定位为0 * 清除指定位为0
* @param index 位索引,范围 [0, 63] * @param index 位索引
* @throws 当位索引为负数时抛出错误 * @throws 当位索引为负数时抛出错误
*/ */
public clear(index: number): void { public clear(index: number): void {
@@ -52,11 +50,7 @@ export class Bits {
throw new Error('Bit index cannot be negative'); throw new Error('Bit index cannot be negative');
} }
if (index >= 64) { BitMask64Utils.clearBitExtended(this._value, index);
return;
}
BitMask64Utils.clearBit(this._value, index);
} }
/** /**
@@ -65,12 +59,7 @@ export class Bits {
* @returns 如果位被设置为1则返回true否则返回false * @returns 如果位被设置为1则返回true否则返回false
*/ */
public get(index: number): boolean { public get(index: number): boolean {
if (index < 0 || index >= 64) { return BitMask64Utils.getBitExtended(this._value, index);
return false;
}
const mask = BitMask64Utils.create(index);
return BitMask64Utils.hasAny(this._value, mask);
} }
/** /**

View File

@@ -5,6 +5,7 @@ import { ComponentType } from "../../Types";
/** /**
* 组件类型管理器 * 组件类型管理器
* 负责管理组件类型的注册和ID分配 * 负责管理组件类型的注册和ID分配
* 支持无限数量的组件类型(通过自动扩展 BitMask
*/ */
export class ComponentTypeManager { export class ComponentTypeManager {
private static _instance: ComponentTypeManager; private static _instance: ComponentTypeManager;

View File

@@ -438,9 +438,15 @@ describe('Bits - 高性能位操作类测试', () => {
expect(bits.cardinality()).toBe(1); expect(bits.cardinality()).toBe(1);
}); });
it('超过64位索引应该抛出错误', () => { it('超过64位索引应该自动扩展', () => {
expect(() => bits.set(64)).toThrow('Bit index exceeds 64-bit limit'); // 现在支持自动扩展到 128/256 位
expect(() => bits.set(100)).toThrow('Bit index exceeds 64-bit limit'); expect(() => bits.set(64)).not.toThrow();
expect(() => bits.set(100)).not.toThrow();
// 验证扩展后的位可以正确读取
expect(bits.get(64)).toBe(true);
expect(bits.get(100)).toBe(true);
expect(bits.get(65)).toBe(false);
}); });
it('64位范围内的位运算应该正确', () => { it('64位范围内的位运算应该正确', () => {