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

372 lines
11 KiB
TypeScript
Raw Normal View History

2025-09-03 10:29:43 +08:00
import { BitMask64Data, BitMask64Utils } from './BigIntCompatibility';
/**
2025-09-03 10:29:43 +08:00
* 64
* 64
*/
export class Bits {
2025-09-03 10:29:43 +08:00
/** 存储位数据的64位掩码 */
private _value: BitMask64Data;
/**
2025-09-03 10:29:43 +08:00
*
* @param initialValue BitMask64Data对象
*/
2025-09-03 10:29:43 +08:00
constructor(initialValue?: BitMask64Data | number | string) {
if (initialValue && typeof initialValue === 'object') {
2025-09-03 10:29:43 +08:00
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 {
2025-09-03 10:29:43 +08:00
this._value = BitMask64Utils.clone(BitMask64Utils.ZERO);
}
}
/**
2025-09-03 10:29:43 +08:00
* 1
* @param index [0, 63]
* @throws 64
*/
public set(index: number): void {
2025-06-16 09:36:36 +08:00
if (index < 0) {
throw new Error('Bit index cannot be negative');
}
2025-09-03 10:29:43 +08:00
if (index >= 64) {
throw new Error('Bit index exceeds 64-bit limit. ECS framework supports max 64 component types.');
}
BitMask64Utils.setBit(this._value, index);
}
2021-05-07 16:23:15 +08:00
/**
2025-09-03 10:29:43 +08:00
* 0
* @param index [0, 63]
* @throws
*/
public clear(index: number): void {
2025-06-16 09:36:36 +08:00
if (index < 0) {
throw new Error('Bit index cannot be negative');
2021-05-07 16:23:15 +08:00
}
2025-09-03 10:29:43 +08:00
if (index >= 64) {
return;
}
BitMask64Utils.clearBit(this._value, index);
}
2021-05-07 16:23:15 +08:00
/**
2025-09-03 10:29:43 +08:00
*
* @param index
* @returns 1truefalse
*/
public get(index: number): boolean {
2025-09-03 10:29:43 +08:00
if (index < 0 || index >= 64) {
return false;
2021-05-07 16:23:15 +08:00
}
2025-09-03 10:29:43 +08:00
const mask = BitMask64Utils.create(index);
return BitMask64Utils.hasAny(this._value, mask);
2021-05-07 16:23:15 +08:00
}
/**
2025-09-03 10:29:43 +08:00
*
* @param other
* @returns other的所有设置位则返回true
*/
public containsAll(other: Bits): boolean {
2025-09-03 10:29:43 +08:00
return BitMask64Utils.hasAll(this._value, other._value);
}
/**
2025-09-03 10:29:43 +08:00
*
* @param other
* @returns true
*/
public intersects(other: Bits): boolean {
2025-09-03 10:29:43 +08:00
return BitMask64Utils.hasAny(this._value, other._value);
}
/**
2025-09-03 10:29:43 +08:00
*
* @param other
* @returns true
*/
public excludes(other: Bits): boolean {
2025-09-03 10:29:43 +08:00
return BitMask64Utils.hasNone(this._value, other._value);
}
/**
2025-09-03 10:29:43 +08:00
* 0
*/
public clearAll(): void {
2025-09-03 10:29:43 +08:00
BitMask64Utils.clear(this._value);
}
/**
2025-09-03 10:29:43 +08:00
*
* @returns 0true
*/
public isEmpty(): boolean {
2025-09-03 10:29:43 +08:00
return BitMask64Utils.isZero(this._value);
}
/**
2025-09-03 10:29:43 +08:00
* 1
* @returns
*/
public cardinality(): number {
2025-09-03 10:29:43 +08:00
return BitMask64Utils.popCount(this._value);
}
/**
2025-09-03 10:29:43 +08:00
*
* @param other
* @returns
2025-06-16 09:36:36 +08:00
*/
public and(other: Bits): Bits {
2025-09-03 10:29:43 +08:00
const result = new Bits();
BitMask64Utils.copy(this._value, result._value);
BitMask64Utils.andInPlace(result._value, other._value);
return result;
2025-06-16 09:36:36 +08:00
}
/**
2025-09-03 10:29:43 +08:00
*
* @param other
* @returns
*/
2025-06-16 09:36:36 +08:00
public or(other: Bits): Bits {
2025-09-03 10:29:43 +08:00
const result = new Bits();
BitMask64Utils.copy(this._value, result._value);
BitMask64Utils.orInPlace(result._value, other._value);
return result;
2025-06-16 09:36:36 +08:00
}
/**
2025-09-03 10:29:43 +08:00
*
* @param other
* @returns
2025-06-16 09:36:36 +08:00
*/
public xor(other: Bits): Bits {
2025-09-03 10:29:43 +08:00
const result = new Bits();
BitMask64Utils.copy(this._value, result._value);
BitMask64Utils.xorInPlace(result._value, other._value);
return result;
2025-06-16 09:36:36 +08:00
}
/**
2025-09-03 10:29:43 +08:00
*
* @param maxBits 64
* @returns
2025-06-16 09:36:36 +08:00
*/
public not(maxBits: number = 64): Bits {
2025-09-03 10:29:43 +08:00
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;
}
/**
2025-09-03 10:29:43 +08:00
*
* @param other
*/
public copyFrom(other: Bits): void {
2025-09-03 10:29:43 +08:00
BitMask64Utils.copy(other._value, this._value);
}
/**
2025-09-03 10:29:43 +08:00
*
* @returns
*/
public clone(): Bits {
2025-09-03 10:29:43 +08:00
return new Bits(this._value);
2025-06-16 09:36:36 +08:00
}
/**
2025-09-03 10:29:43 +08:00
* 64
* @returns BitMask64Data对象
2025-06-16 09:36:36 +08:00
*/
2025-09-03 10:29:43 +08:00
public getValue(): BitMask64Data {
2025-06-16 09:36:36 +08:00
return this._value;
}
/**
2025-09-03 10:29:43 +08:00
*
* @param value BitMask64Data对象
2025-06-16 09:36:36 +08:00
*/
2025-09-03 10:29:43 +08:00
public setValue(value: BitMask64Data | number | string): void {
if (typeof value === 'object') {
2025-09-03 10:29:43 +08:00
BitMask64Utils.copy(value, this._value);
} else if (typeof value === 'number') {
this._value = BitMask64Utils.fromNumber(value);
} else {
2025-09-03 10:29:43 +08:00
const num = parseInt(value, 10);
this._value = BitMask64Utils.fromNumber(num);
}
2025-06-16 09:36:36 +08:00
}
/**
2025-09-03 10:29:43 +08:00
*
* @returns "Bits[index1, index2, ...]"
2025-06-16 09:36:36 +08:00
*/
public toString(): string {
const bits: string[] = [];
2025-09-03 10:29:43 +08:00
for (let i = 0; i < 64; i++) {
if (this.get(i)) {
bits.push(i.toString());
2025-06-16 09:36:36 +08:00
}
}
return `Bits[${bits.join(', ')}]`;
}
/**
2025-09-03 10:29:43 +08:00
*
* @param maxBits 64
* @returns 8
2025-06-16 09:36:36 +08:00
*/
public toBinaryString(maxBits: number = 64): string {
2025-09-03 10:29:43 +08:00
if (maxBits > 64) maxBits = 64;
2025-06-16 09:36:36 +08:00
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;
}
/**
2025-09-03 10:29:43 +08:00
*
* @returns 0x前缀
2025-06-16 09:36:36 +08:00
*/
public toHexString(): string {
2025-09-03 10:29:43 +08:00
return BitMask64Utils.toString(this._value, 16);
2025-06-16 09:36:36 +08:00
}
/**
2025-09-03 10:29:43 +08:00
*
* @param binaryString
* @returns
2025-06-16 09:36:36 +08:00
*/
public static fromBinaryString(binaryString: string): Bits {
const cleanString = binaryString.replace(/\s/g, '');
2025-09-03 10:29:43 +08:00
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);
2025-06-16 09:36:36 +08:00
}
/**
2025-09-03 10:29:43 +08:00
*
* @param hexString 0x前缀
* @returns
2025-06-16 09:36:36 +08:00
*/
public static fromHexString(hexString: string): Bits {
2025-09-03 10:29:43 +08:00
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);
2025-06-16 09:36:36 +08:00
}
/**
2025-09-03 10:29:43 +08:00
*
* @param other
* @returns true
2025-06-16 09:36:36 +08:00
*/
public equals(other: Bits): boolean {
2025-09-03 10:29:43 +08:00
return BitMask64Utils.equals(this._value, other._value);
2025-06-16 09:36:36 +08:00
}
/**
2025-09-03 10:29:43 +08:00
*
* @returns -1
2025-06-16 09:36:36 +08:00
*/
public getHighestBitIndex(): number {
2025-09-03 10:29:43 +08:00
if (BitMask64Utils.isZero(this._value)) {
2025-06-16 09:36:36 +08:00
return -1;
}
2025-09-03 10:29:43 +08:00
if (this._value.hi !== 0) {
for (let i = 31; i >= 0; i--) {
if ((this._value.hi & (1 << i)) !== 0) {
return i + 32;
}
}
}
2025-06-16 09:36:36 +08:00
2025-09-03 10:29:43 +08:00
for (let i = 31; i >= 0; i--) {
if ((this._value.lo & (1 << i)) !== 0) {
return i;
}
2025-06-16 09:36:36 +08:00
}
2025-09-03 10:29:43 +08:00
return -1;
2025-06-16 09:36:36 +08:00
}
/**
2025-09-03 10:29:43 +08:00
*
* @returns -1
2025-06-16 09:36:36 +08:00
*/
public getLowestBitIndex(): number {
2025-09-03 10:29:43 +08:00
if (BitMask64Utils.isZero(this._value)) {
2025-06-16 09:36:36 +08:00
return -1;
}
2025-09-03 10:29:43 +08:00
for (let i = 0; i < 32; i++) {
if ((this._value.lo & (1 << i)) !== 0) {
return i;
}
}
2025-06-16 09:36:36 +08:00
2025-09-03 10:29:43 +08:00
for (let i = 0; i < 32; i++) {
if ((this._value.hi & (1 << i)) !== 0) {
return i + 32;
}
2025-06-16 09:36:36 +08:00
}
2025-09-03 10:29:43 +08:00
return -1;
}
2021-05-07 16:23:15 +08:00
}