Files
esengine/packages/core/src/ECS/Utils/Bits.ts

361 lines
11 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { BitMask64Data, BitMask64Utils } from './BigIntCompatibility';
/**
* 位集合类,用于高效的位操作
* 自动扩展支持:默认 64 位,超过时自动扩展到 128/256 位
* 扩展模式性能略有下降,但仍然比数组遍历快得多
*/
export class Bits {
/** 存储位数据的掩码,支持扩展 */
private _value: BitMask64Data;
/**
* 构造函数,创建位集合
* @param initialValue 初始值可以是BitMask64Data对象、数字或字符串
*/
constructor(initialValue?: BitMask64Data | number | string) {
if (initialValue && typeof initialValue === 'object') {
this._value = BitMask64Utils.clone(initialValue);
} else if (typeof initialValue === 'number') {
this._value = BitMask64Utils.fromNumber(initialValue);
} else if (typeof initialValue === 'string') {
const num = parseInt(initialValue, 10);
this._value = BitMask64Utils.fromNumber(num);
} else {
this._value = BitMask64Utils.clone(BitMask64Utils.ZERO);
}
}
/**
* 设置指定位为1
* 自动扩展:当索引超过 64 时,自动扩展到 128/256 位
* @param index 位索引0-based
* @throws 当位索引为负数时抛出错误
*/
public set(index: number): void {
if (index < 0) {
throw new Error('Bit index cannot be negative');
}
BitMask64Utils.setBitExtended(this._value, index);
}
/**
* 清除指定位为0
* @param index 位索引
* @throws 当位索引为负数时抛出错误
*/
public clear(index: number): void {
if (index < 0) {
throw new Error('Bit index cannot be negative');
}
BitMask64Utils.clearBitExtended(this._value, index);
}
/**
* 获取指定位的值
* @param index 位索引
* @returns 如果位被设置为1则返回true否则返回false
*/
public get(index: number): boolean {
return BitMask64Utils.getBitExtended(this._value, index);
}
/**
* 检查是否包含另一个位集合的所有位
* @param other 另一个位集合
* @returns 如果包含other的所有设置位则返回true
*/
public containsAll(other: Bits): boolean {
return BitMask64Utils.hasAll(this._value, other._value);
}
/**
* 检查是否与另一个位集合有交集
* @param other 另一个位集合
* @returns 如果有共同的设置位则返回true
*/
public intersects(other: Bits): boolean {
return BitMask64Utils.hasAny(this._value, other._value);
}
/**
* 检查是否与另一个位集合没有交集
* @param other 另一个位集合
* @returns 如果没有共同的设置位则返回true
*/
public excludes(other: Bits): boolean {
return BitMask64Utils.hasNone(this._value, other._value);
}
/**
* 清除所有位为0
*/
public clearAll(): void {
BitMask64Utils.clear(this._value);
}
/**
* 检查位集合是否为空
* @returns 如果所有位都为0则返回true
*/
public isEmpty(): boolean {
return BitMask64Utils.isZero(this._value);
}
/**
* 计算设置为1的位数
* @returns 设置位的总数
*/
public cardinality(): number {
return BitMask64Utils.popCount(this._value);
}
/**
* 与另一个位集合执行按位与操作
* @param other 另一个位集合
* @returns 新的位集合,包含按位与的结果
*/
public and(other: Bits): Bits {
const result = new Bits();
BitMask64Utils.copy(this._value, result._value);
BitMask64Utils.andInPlace(result._value, other._value);
return result;
}
/**
* 与另一个位集合执行按位或操作
* @param other 另一个位集合
* @returns 新的位集合,包含按位或的结果
*/
public or(other: Bits): Bits {
const result = new Bits();
BitMask64Utils.copy(this._value, result._value);
BitMask64Utils.orInPlace(result._value, other._value);
return result;
}
/**
* 与另一个位集合执行按位异或操作
* @param other 另一个位集合
* @returns 新的位集合,包含按位异或的结果
*/
public xor(other: Bits): Bits {
const result = new Bits();
BitMask64Utils.copy(this._value, result._value);
BitMask64Utils.xorInPlace(result._value, other._value);
return result;
}
/**
* 执行按位取反操作
* @param maxBits 最大位数默认为64
* @returns 新的位集合,包含按位取反的结果
*/
public not(maxBits: number = 64): Bits {
if (maxBits > 64) {
maxBits = 64;
}
const result = new Bits();
BitMask64Utils.copy(this._value, result._value);
if (maxBits <= 32) {
const mask = (1 << maxBits) - 1;
result._value.lo = (~result._value.lo) & mask;
result._value.hi = 0;
} else {
result._value.lo = ~result._value.lo;
if (maxBits < 64) {
const remainingBits = maxBits - 32;
const mask = (1 << remainingBits) - 1;
result._value.hi = (~result._value.hi) & mask;
} else {
result._value.hi = ~result._value.hi;
}
}
return result;
}
/**
* 从另一个位集合复制值
* @param other 源位集合
*/
public copyFrom(other: Bits): void {
BitMask64Utils.copy(other._value, this._value);
}
/**
* 创建当前位集合的深拷贝
* @returns 新的位集合,内容与当前位集合相同
*/
public clone(): Bits {
return new Bits(this._value);
}
/**
* 获取内部的64位掩码数据
* @returns 内部存储的BitMask64Data对象
*/
public getValue(): BitMask64Data {
return this._value;
}
/**
* 设置位集合的值
* @param value 新值可以是BitMask64Data对象、数字或字符串
*/
public setValue(value: BitMask64Data | number | string): void {
if (typeof value === 'object') {
BitMask64Utils.copy(value, this._value);
} else if (typeof value === 'number') {
this._value = BitMask64Utils.fromNumber(value);
} else {
const num = parseInt(value, 10);
this._value = BitMask64Utils.fromNumber(num);
}
}
/**
* 将位集合转换为可读字符串
* @returns 格式为"Bits[index1, index2, ...]"的字符串
*/
public toString(): string {
const bits: string[] = [];
for (let i = 0; i < 64; i++) {
if (this.get(i)) {
bits.push(i.toString());
}
}
return `Bits[${bits.join(', ')}]`;
}
/**
* 将位集合转换为二进制字符串
* @param maxBits 最大位数默认为64
* @returns 二进制字符串表示每8位用空格分隔
*/
public toBinaryString(maxBits: number = 64): string {
if (maxBits > 64) maxBits = 64;
let result = '';
for (let i = maxBits - 1; i >= 0; i--) {
result += this.get(i) ? '1' : '0';
if (i % 8 === 0 && i > 0) {
result += ' ';
}
}
return result;
}
/**
* 将位集合转换为十六进制字符串
* @returns 十六进制字符串表示带0x前缀
*/
public toHexString(): string {
return BitMask64Utils.toString(this._value, 16);
}
/**
* 从二进制字符串创建位集合
* @param binaryString 二进制字符串,可以包含空格
* @returns 新的位集合对象
*/
public static fromBinaryString(binaryString: string): Bits {
const cleanString = binaryString.replace(/\s/g, '');
let data: BitMask64Data;
if (cleanString.length <= 32) {
const num = parseInt(cleanString, 2);
data = { lo: num >>> 0, hi: 0 };
} else {
const loBits = cleanString.substring(cleanString.length - 32);
const hiBits = cleanString.substring(0, cleanString.length - 32);
const lo = parseInt(loBits, 2);
const hi = parseInt(hiBits, 2);
data = { lo: lo >>> 0, hi: hi >>> 0 };
}
return new Bits(data);
}
/**
* 从十六进制字符串创建位集合
* @param hexString 十六进制字符串可以带或不带0x前缀
* @returns 新的位集合对象
*/
public static fromHexString(hexString: string): Bits {
const cleanString = hexString.replace(/^0x/i, '');
let data: BitMask64Data;
if (cleanString.length <= 8) {
const num = parseInt(cleanString, 16);
data = { lo: num >>> 0, hi: 0 };
} else {
const loBits = cleanString.substring(cleanString.length - 8);
const hiBits = cleanString.substring(0, cleanString.length - 8);
const lo = parseInt(loBits, 16);
const hi = parseInt(hiBits, 16);
data = { lo: lo >>> 0, hi: hi >>> 0 };
}
return new Bits(data);
}
/**
* 检查是否与另一个位集合相等
* @param other 另一个位集合
* @returns 如果两个位集合完全相同则返回true
*/
public equals(other: Bits): boolean {
return BitMask64Utils.equals(this._value, other._value);
}
/**
* 获取最高位设置位的索引
* @returns 最高位设置位的索引,如果位集合为空则返回-1
*/
public getHighestBitIndex(): number {
if (BitMask64Utils.isZero(this._value)) {
return -1;
}
if (this._value.hi !== 0) {
for (let i = 31; i >= 0; i--) {
if ((this._value.hi & (1 << i)) !== 0) {
return i + 32;
}
}
}
for (let i = 31; i >= 0; i--) {
if ((this._value.lo & (1 << i)) !== 0) {
return i;
}
}
return -1;
}
/**
* 获取最低位设置位的索引
* @returns 最低位设置位的索引,如果位集合为空则返回-1
*/
public getLowestBitIndex(): number {
if (BitMask64Utils.isZero(this._value)) {
return -1;
}
for (let i = 0; i < 32; i++) {
if ((this._value.lo & (1 << i)) !== 0) {
return i;
}
}
for (let i = 0; i < 32; i++) {
if ((this._value.hi & (1 << i)) !== 0) {
return i + 32;
}
}
return -1;
}
}