-
Notifications
You must be signed in to change notification settings - Fork 0
/
bitmap.js
80 lines (64 loc) · 1.85 KB
/
bitmap.js
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
// u8 -> number of 1s LUT
const bitCountLUT = [...Array(256)].map((r = 0, a) => {
for (; a; a >>= 1) r += 1 & a
return r
})
function countOnes(array) {
let count = 0
for (let i = 0; i < array.length; i++) {
count += bitCountLUT[array[i]]
}
return count
}
exports.Bitmap = class Bitmap {
checkedCount = 0
subscribers = new Set()
constructor(bitCount) {
this.bitCount = bitCount
const byteCount = Math.ceil(bitCount / 8)
this.bytes = new Uint8Array(byteCount)
}
get(index) {
const byteIndex = index >> 3
const bitIndex = index & 7
return (this.bytes[byteIndex] & (1 << bitIndex)) !== 0
}
set(index, value) {
const byteIndex = index >> 3
const bitIndex = index & 7
let b = this.bytes[byteIndex]
this.checkedCount -= bitCountLUT[b]
b &= ~(1 << bitIndex)
if (value) {
b |= 1 << bitIndex
}
this.bytes[byteIndex] = b
this.checkedCount += bitCountLUT[b]
}
fullStateUpdate(bitmap) {
this.bytes.set(bitmap)
this.checkedCount = countOnes(bitmap)
this.fireChange()
}
partialStateUpdate(offset, chunk) {
for (let i = 0; i < chunk.length; i++) {
const byteIndex = offset + i
const b = this.bytes[byteIndex]
this.checkedCount -= bitCountLUT[b]
this.bytes[byteIndex] = chunk[i]
this.checkedCount += bitCountLUT[chunk[i]]
}
this.fireChange(offset * 8, (offset + chunk.length) * 8)
}
fireChange(rangeMin = 0, rangeMax = this.bitCount) {
for (const subscriber of this.subscribers) {
subscriber(rangeMin, rangeMax)
}
}
subscribeToChanges(callback) {
this.subscribers.add(callback)
}
unsubscribeFromChanges(callback) {
this.subscribers.delete(callback)
}
}