1- // TODO: needs massive improvements obvs
2-
31const BigSparseArray = require ( 'big-sparse-array' )
42const b4a = require ( 'b4a' )
3+ const bits = require ( 'bits-to-bytes' )
54
65class FixedBitfield {
76 constructor ( index , bitfield ) {
@@ -11,26 +10,17 @@ class FixedBitfield {
1110 }
1211
1312 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 )
1814 }
1915
2016 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+ }
3219
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 )
3424 return true
3525 }
3626}
@@ -44,7 +34,11 @@ module.exports = class Bitfield {
4434 this . resumed = ! ! ( buf && buf . byteLength >= 4 )
4535
4636 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+ )
4842 : new Uint32Array ( 1024 )
4943
5044 for ( let i = 0 ; i < all . length ; i += 1024 ) {
@@ -55,33 +49,52 @@ module.exports = class Bitfield {
5549 }
5650
5751 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+
6055 const p = this . pages . get ( i )
6156
6257 return p ? p . get ( j ) : false
6358 }
6459
6560 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
6863
6964 let p = this . pages . get ( i )
7065
71- if ( ! p ) {
72- if ( ! val ) return
66+ if ( ! p && val ) {
7367 p = this . pages . set ( i , new FixedBitfield ( i , new Uint32Array ( 1024 ) ) )
7468 }
7569
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+ }
8074 }
8175
8276 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
8598 }
8699 }
87100
@@ -120,7 +133,12 @@ module.exports = class Bitfield {
120133 let error = null
121134
122135 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+
124142 page . dirty = false
125143 this . storage . write ( page . index * 4096 , buf , done )
126144 }
@@ -151,7 +169,7 @@ module.exports = class Bitfield {
151169}
152170
153171function ensureSize ( uint32 , size ) {
154- if ( uint32 . length === size ) return uint32
172+ if ( uint32 . byteLength === size ) return uint32
155173 const a = new Uint32Array ( 1024 )
156174 a . set ( uint32 , 0 )
157175 return a
0 commit comments