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

321 lines
8.2 KiB
TypeScript
Raw Normal View History

import { IBigIntLike, BigIntFactory } from './BigIntCompatibility';
/**
*
*
* BigInt实现
* BigInt的环境中使用兼容实现
*
* @example
* ```typescript
* const bits = new Bits();
* bits.set(0);
* bits.set(5);
* console.log(bits.get(0)); // true
* console.log(bits.get(1)); // false
* ```
*/
export class Bits {
private _value: IBigIntLike;
/**
*
* @param initialValue IBigIntLike或数值
*/
constructor(initialValue?: IBigIntLike | number | string) {
if (initialValue && typeof initialValue === 'object') {
this._value = initialValue;
} else {
this._value = BigIntFactory.create(initialValue || 0);
}
}
/**
* 1
* @param index 0
* @throws {Error}
*/
public set(index: number): void {
2025-06-16 09:36:36 +08:00
if (index < 0) {
throw new Error('Bit index cannot be negative');
}
const mask = BigIntFactory.one().shiftLeft(index);
this._value = this._value.or(mask);
}
2021-05-07 16:23:15 +08:00
/**
* 0
* @param index 0
* @throws {Error}
*/
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
}
const mask = BigIntFactory.one().shiftLeft(index).not();
this._value = this._value.and(mask);
}
2021-05-07 16:23:15 +08:00
/**
*
* @param index 0
* @returns true表示1false表示0
*/
public get(index: number): boolean {
2025-06-16 09:36:36 +08:00
if (index < 0) {
return false;
2021-05-07 16:23:15 +08:00
}
const mask = BigIntFactory.one().shiftLeft(index);
return !this._value.and(mask).isZero();
2021-05-07 16:23:15 +08:00
}
/**
*
* @param other Bits对象
* @returns
*/
public containsAll(other: Bits): boolean {
const intersection = this._value.and(other._value);
return intersection.equals(other._value);
}
/**
*
* @param other Bits对象
* @returns
*/
public intersects(other: Bits): boolean {
return !this._value.and(other._value).isZero();
}
/**
*
* @param other Bits对象
* @returns
*/
public excludes(other: Bits): boolean {
return !this.intersects(other);
}
/**
*
*/
public clearAll(): void {
this._value = BigIntFactory.zero();
}
/**
*
* @returns
*/
public isEmpty(): boolean {
return this._value.isZero();
}
/**
*
* @returns 1
*/
public cardinality(): number {
let count = 0;
let value = this._value.clone();
2025-06-16 09:36:36 +08:00
while (!value.isZero()) {
const one = BigIntFactory.one();
if (!value.and(one).isZero()) {
2025-06-16 09:36:36 +08:00
count++;
}
value = value.shiftRight(1);
}
2025-06-16 09:36:36 +08:00
return count;
}
/**
2025-06-16 09:36:36 +08:00
*
* @param other Bits对象
* @returns Bits对象
2025-06-16 09:36:36 +08:00
*/
public and(other: Bits): Bits {
return new Bits(this._value.and(other._value));
2025-06-16 09:36:36 +08:00
}
/**
*
* @param other Bits对象
* @returns Bits对象
*/
2025-06-16 09:36:36 +08:00
public or(other: Bits): Bits {
return new Bits(this._value.or(other._value));
2025-06-16 09:36:36 +08:00
}
/**
*
* @param other Bits对象
* @returns Bits对象
2025-06-16 09:36:36 +08:00
*/
public xor(other: Bits): Bits {
return new Bits(this._value.xor(other._value));
2025-06-16 09:36:36 +08:00
}
/**
*
* @param maxBits 64
* @returns Bits对象
2025-06-16 09:36:36 +08:00
*/
public not(maxBits: number = 64): Bits {
return new Bits(this._value.not(maxBits));
}
/**
* Bits对象
* @param other Bits对象
*/
public copyFrom(other: Bits): void {
this._value = other._value.clone();
}
/**
* Bits的副本
* @returns Bits对象副本
*/
public clone(): Bits {
return new Bits(this._value.clone());
2025-06-16 09:36:36 +08:00
}
/**
*
* @returns IBigIntLike值
2025-06-16 09:36:36 +08:00
*/
public getValue(): IBigIntLike {
2025-06-16 09:36:36 +08:00
return this._value;
}
/**
*
* @param value IBigIntLike或数值
2025-06-16 09:36:36 +08:00
*/
public setValue(value: IBigIntLike | number | string): void {
if (typeof value === 'object') {
this._value = value;
} else {
this._value = BigIntFactory.create(value);
}
2025-06-16 09:36:36 +08:00
}
/**
*
* @returns
2025-06-16 09:36:36 +08:00
*/
public toString(): string {
const bits: string[] = [];
let index = 0;
let value = this._value.clone();
2025-06-16 09:36:36 +08:00
while (!value.isZero()) {
const one = BigIntFactory.one();
if (!value.and(one).isZero()) {
2025-06-16 09:36:36 +08:00
bits.push(index.toString());
}
value = value.shiftRight(1);
2025-06-16 09:36:36 +08:00
index++;
}
return `Bits[${bits.join(', ')}]`;
}
/**
*
* @param maxBits 64
* @returns
2025-06-16 09:36:36 +08:00
*/
public toBinaryString(maxBits: number = 64): string {
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
2025-06-16 09:36:36 +08:00
*/
public toHexString(): string {
return '0x' + this._value.toString(16).toUpperCase();
}
/**
* Bits
* @param binaryString
* @returns Bits对象
2025-06-16 09:36:36 +08:00
*/
public static fromBinaryString(binaryString: string): Bits {
const cleanString = binaryString.replace(/\s/g, '');
const value = BigIntFactory.fromBinaryString(cleanString);
2025-06-16 09:36:36 +08:00
return new Bits(value);
}
/**
* Bits
* @param hexString
* @returns Bits对象
2025-06-16 09:36:36 +08:00
*/
public static fromHexString(hexString: string): Bits {
const value = BigIntFactory.fromHexString(hexString);
2025-06-16 09:36:36 +08:00
return new Bits(value);
}
/**
* Bits对象是否相等
* @param other Bits对象
* @returns
2025-06-16 09:36:36 +08:00
*/
public equals(other: Bits): boolean {
return this._value.equals(other._value);
2025-06-16 09:36:36 +08:00
}
/**
*
* @returns -1
2025-06-16 09:36:36 +08:00
*/
public getHighestBitIndex(): number {
if (this._value.isZero()) {
2025-06-16 09:36:36 +08:00
return -1;
}
let index = 0;
let value = this._value.clone();
2025-06-16 09:36:36 +08:00
while (!value.shiftRight(1).isZero()) {
value = value.shiftRight(1);
2025-06-16 09:36:36 +08:00
index++;
}
return index;
}
/**
*
* @returns -1
2025-06-16 09:36:36 +08:00
*/
public getLowestBitIndex(): number {
if (this._value.isZero()) {
2025-06-16 09:36:36 +08:00
return -1;
}
let index = 0;
let value = this._value.clone();
const one = BigIntFactory.one();
2025-06-16 09:36:36 +08:00
while (value.and(one).isZero()) {
value = value.shiftRight(1);
2025-06-16 09:36:36 +08:00
index++;
}
return index;
}
2021-05-07 16:23:15 +08:00
}