1
- // TODO: needs massive improvements obvs
2
-
3
1
const BigSparseArray = require ( 'big-sparse-array' )
4
2
const b4a = require ( 'b4a' )
3
+ const bits = require ( 'bits-to-bytes' )
5
4
6
5
class FixedBitfield {
7
6
constructor ( index , bitfield ) {
@@ -11,26 +10,17 @@ class FixedBitfield {
11
10
}
12
11
13
12
get ( index ) {
14
- const j = index & 31
15
- const i = ( index - j ) / 32
16
-
17
- return i < this . bitfield . length && ( this . bitfield [ i ] & ( 1 << j ) ) !== 0
13
+ return bits . get ( this . bitfield , index )
18
14
}
19
15
20
16
set ( index , val ) {
21
- const j = index & 31
22
- const i = ( index - j ) / 32
23
- const v = this . bitfield [ i ]
24
-
25
- if ( val === ( ( v & ( 1 << j ) ) !== 0 ) ) return false
26
-
27
- const u = val
28
- ? v | ( 1 << j )
29
- : v ^ ( 1 << j )
30
-
31
- if ( u === v ) return false
17
+ return bits . set ( this . bitfield , index , val )
18
+ }
32
19
33
- this . bitfield [ i ] = u
20
+ setRange ( start , length , val ) {
21
+ // Using fill instead of setRange is ~2 orders of magnitude faster, but does
22
+ // have the downside of not being able to tell if any bits actually changed.
23
+ bits . fill ( this . bitfield , val , start , start + length )
34
24
return true
35
25
}
36
26
}
@@ -44,7 +34,11 @@ module.exports = class Bitfield {
44
34
this . resumed = ! ! ( buf && buf . byteLength >= 4 )
45
35
46
36
const all = this . resumed
47
- ? new Uint32Array ( buf . buffer , buf . byteOffset , Math . floor ( buf . byteLength / 4 ) )
37
+ ? new Uint32Array (
38
+ buf . buffer ,
39
+ buf . byteOffset ,
40
+ Math . floor ( buf . byteLength / 4 )
41
+ )
48
42
: new Uint32Array ( 1024 )
49
43
50
44
for ( let i = 0 ; i < all . length ; i += 1024 ) {
@@ -55,33 +49,52 @@ module.exports = class Bitfield {
55
49
}
56
50
57
51
get ( index ) {
58
- const j = index & 32767
59
- const i = ( index - j ) / 32768
52
+ const j = index & ( this . pageSize - 1 )
53
+ const i = ( index - j ) / this . pageSize
54
+
60
55
const p = this . pages . get ( i )
61
56
62
57
return p ? p . get ( j ) : false
63
58
}
64
59
65
60
set ( index , val ) {
66
- const j = index & 32767
67
- const i = ( index - j ) / 32768
61
+ const j = index & ( this . pageSize - 1 )
62
+ const i = ( index - j ) / this . pageSize
68
63
69
64
let p = this . pages . get ( i )
70
65
71
- if ( ! p ) {
72
- if ( ! val ) return
66
+ if ( ! p && val ) {
73
67
p = this . pages . set ( i , new FixedBitfield ( i , new Uint32Array ( 1024 ) ) )
74
68
}
75
69
76
- if ( ! p . set ( j , val ) || p . dirty ) return
77
-
78
- p . dirty = true
79
- this . unflushed . push ( p )
70
+ if ( p && p . set ( j , val ) && ! p . dirty ) {
71
+ p . dirty = true
72
+ this . unflushed . push ( p )
73
+ }
80
74
}
81
75
82
76
setRange ( start , length , val ) {
83
- for ( let i = 0 ; i < length ; i ++ ) {
84
- this . set ( start + i , val )
77
+ let j = start & ( this . pageSize - 1 )
78
+ let i = ( start - j ) / this . pageSize
79
+
80
+ while ( length > 0 ) {
81
+ let p = this . pages . get ( i )
82
+
83
+ if ( ! p && val ) {
84
+ p = this . pages . set ( i , new FixedBitfield ( i , new Uint32Array ( 1024 ) ) )
85
+ }
86
+
87
+ const end = Math . min ( j + length , this . pageSize )
88
+ const range = end - j
89
+
90
+ if ( p && p . setRange ( j , range , val ) && ! p . dirty ) {
91
+ p . dirty = true
92
+ this . unflushed . push ( p )
93
+ }
94
+
95
+ j = 0
96
+ i ++
97
+ length -= range
85
98
}
86
99
}
87
100
@@ -120,7 +133,12 @@ module.exports = class Bitfield {
120
133
let error = null
121
134
122
135
for ( const page of this . unflushed ) {
123
- const buf = b4a . from ( page . bitfield . buffer , page . bitfield . byteOffset , page . bitfield . byteLength )
136
+ const buf = b4a . from (
137
+ page . bitfield . buffer ,
138
+ page . bitfield . byteOffset ,
139
+ page . bitfield . byteLength
140
+ )
141
+
124
142
page . dirty = false
125
143
this . storage . write ( page . index * 4096 , buf , done )
126
144
}
@@ -151,7 +169,7 @@ module.exports = class Bitfield {
151
169
}
152
170
153
171
function ensureSize ( uint32 , size ) {
154
- if ( uint32 . length === size ) return uint32
172
+ if ( uint32 . byteLength === size ) return uint32
155
173
const a = new Uint32Array ( 1024 )
156
174
a . set ( uint32 , 0 )
157
175
return a
0 commit comments