-
Notifications
You must be signed in to change notification settings - Fork 6
/
BitSet.ts
152 lines (142 loc) · 4.23 KB
/
BitSet.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/**
* A set of numbers, stored as bits in a typed array. The amount of numbers /
* the maximum number that can be stored is limited by the length, which is
* fixed at construction time.
*/
abstract class BitSet {
protected readonly bs: Uint8Array | Uint16Array | Uint32Array;
protected readonly W: 8 | 16 | 32;
protected constructor(W: typeof BitSet.prototype.W, bs: typeof BitSet.prototype.bs){
this.W = W;
this.bs = bs;
}
/**
* Add a number to the set.
*
* @param idx The number to add. Must be 0 <= idx < len.
* @return this.
*/
add(idx: number){
const W = this.W,
byte = (idx / W) | 0,
bit = idx % W;
this.bs[byte] |= 1 << bit;
return this;
}
/**
* Delete a number from the set.
*
* @param idx The number to delete. Must be 0 <= idx < len.
* @return this.
*/
delete(idx: number){
const W = this.W,
byte = (idx / W) | 0,
bit = idx % W;
this.bs[byte] &= ~(1 << bit);
return this;
}
/**
* Add or delete a number in the set, depending on the second argument.
*
* @param idx The number to add or delete. Must be 0 <= idx < len.
* @param val If true, add the number, otherwise delete.
* @return val.
*/
set(idx: number, val: boolean){
const W = this.W,
byte = (idx / W) | 0,
bit = idx % W,
m = 1 << bit;
//this.bs[byte] = set ? this.bs[byte] | m : this.bs[byte] & ~m;
this.bs[byte] ^= (-val ^ this.bs[byte]) & m; // -set == set * 255
return val;
}
/**
* Whether the number is in the set.
*
* @param idx The number to test. Must be 0 <= idx < len.
* @return True if the number is in the set.
*/
has(idx: number){
const W = this.W,
byte = (idx / W) | 0,
bit = idx % W;
return !!(this.bs[byte] & (1 << bit));
}
/**
* Iterate over the numbers that are in the set. The callback is invoked
* with each number that is set. It is allowed to change the BitSet during
* iteration. If it deletes a number that has not been iterated over, that
* number will not show up in a later call. If it adds a number during
* iteration, that number may or may not show up in a later call.
*
* @param fn The function to call for each number.
* @return this.
*/
forEach(fn: (idx: number) => void){
const W = this.W,
bs = this.bs,
len = bs.length;
for(let byte = 0; byte < len; byte++){
let bit = 0;
// bs[byte] may change during iteration
while(bs[byte] && bit < W){
if(bs[byte] & (1 << bit)){
fn(byte * W + bit);
}
bit++;
}
}
return this;
}
}
export type { BitSet };
/**
* A bit set using 8 bits per cell.
*/
export class BitSet8 extends BitSet {
/**
* Create a bit set.
*
* @param len The length of the bit set, limiting the maximum value that
* can be stored in it to len - 1.
*/
constructor(len: number){
const W = 8,
bs = new Uint8Array(Math.ceil(len / W)).fill(0);
super(W, bs);
}
}
/**
* A bit set using 16 bits per cell.
*/
export class BitSet16 extends BitSet {
/**
* Create a bit set.
*
* @param len The length of the bit set, limiting the maximum value that
* can be stored in it to len - 1.
*/
constructor(len: number){
const W = 16,
bs = new Uint16Array(Math.ceil(len / W)).fill(0);
super(W, bs);
}
}
/**
* A bit set using 32 bits per cell.
*/
export class BitSet32 extends BitSet {
/**
* Create a bit set.
*
* @param len The length of the bit set, limiting the maximum value that
* can be stored in it to len - 1.
*/
constructor(len: number){
const W = 32,
bs = new Uint32Array(Math.ceil(len / W)).fill(0);
super(W, bs);
}
}