Files
esengine/source/src/ECS/Utils/BitSet.ts
2021-04-14 17:17:12 +08:00

119 lines
3.9 KiB
TypeScript

module es {
/**
* 这个类可以从两方面来考虑。你可以把它看成一个位向量或者一组非负整数。这个名字有点误导人。
*
* 它是由一个位向量实现的,但同样可以把它看成是一个非负整数的集合;集合中的每个整数由对应索引处的集合位表示。该结构的大小由集合中的最大整数决定。
*/
export class BitSet {
private static ADDRESS_BITS_PER_WORD = 5;
private static BITS_PER_WORD = 1 << BitSet.ADDRESS_BITS_PER_WORD; // 32
private static WORD_MASK : number = 0xffffffff;
private words_: number[];
constructor(nbits: number = 0) {
this.words_ = [];
}
public clear(bitIndex?: number) {
if (bitIndex === null) {
const words = this.words_;
let wordsInUse = words.length;
while (wordsInUse > 0) {
words[--wordsInUse] = 0;
}
return;
}
const wordIndex = bitIndex >> BitSet.ADDRESS_BITS_PER_WORD;
this.words_[wordIndex] &= ~(1 << bitIndex);
}
public get(bitIndex: number): boolean {
const wordIndex = bitIndex >> BitSet.ADDRESS_BITS_PER_WORD;
const words = this.words_;
const wordsInUse = words.length;
return wordIndex < wordsInUse && (words[wordIndex] & (1 << bitIndex)) != 0;
}
public intersects(set: BitSet) {
const words = this.words_;
const wordsInUse = words.length;
for (let i = Math.min(wordsInUse, set.words_.length) - 1; i >= 0; i--)
if ((words[i] & set.words_[i]) != 0) return true;
return false;
}
public isEmpty(): boolean {
return this.words_.length === 0;
}
public nextSetBit(fromIndex: number) {
let u = fromIndex >> BitSet.ADDRESS_BITS_PER_WORD;
const words = this.words_;
const wordsInUse = words.length;
let word = words[u] & (BitSet.WORD_MASK << fromIndex);
while (true) {
if (word !== 0) return u * BitSet.BITS_PER_WORD + this.numberOfTrailingZeros(word);
if (++u === wordsInUse) return -1;
word = words[u];
}
}
private numberOfTrailingZeros(i: number): number {
if (i == 0) return 64;
let x: number = i;
let y: number;
let n = 63;
y = x << 32;
if (y != 0) {
n -= 32;
x = y;
}
y = x << 16;
if (y != 0) {
n -= 16;
x = y;
}
y = x << 8;
if (y != 0) {
n -= 8;
x = y;
}
y = x << 4;
if (y != 0) {
n -= 4;
x = y;
}
y = x << 2;
if (y != 0) {
n -= 2;
x = y;
}
return n - ((x << 1) >>> 63);
}
public set(bitIndex: number, value: boolean = true) {
const wordIndex = bitIndex >> BitSet.ADDRESS_BITS_PER_WORD;
const words = this.words_;
const wordsInUse = words.length;
const wordsRequired = wordIndex + 1;
if (wordsInUse < wordsRequired) {
words.length = Math.max(2 * wordsInUse, wordsRequired);
for (let i = wordsInUse, l = words.length; i < l; i++) {
words[i] = 0;
}
}
if (value) {
return (words[wordIndex] |= 1 << bitIndex);
} else {
return (words[wordIndex] &= ~(1 << bitIndex));
}
}
}
}