@@ -73,6 +73,8 @@ function WritableState(options, stream, isDuplex) {
73
73
if ( typeof isDuplex !== 'boolean' )
74
74
isDuplex = stream instanceof Stream . Duplex ;
75
75
76
+ this . bitfield = 0 ;
77
+
76
78
// Object stream flag to indicate whether or not this stream
77
79
// contains buffers or objects.
78
80
this . objectMode = ! ! ( options && options . objectMode ) ;
@@ -184,6 +186,73 @@ function WritableState(options, stream, isDuplex) {
184
186
this . corkedRequestsFree = corkReq ;
185
187
}
186
188
189
+ const F = { } ;
190
+ for ( let [ key , options ] of Object . entries ( {
191
+ objectMode : { } ,
192
+ finalCalled : { } ,
193
+ drained : { } ,
194
+ ending : { } ,
195
+ ended : { } ,
196
+ finished : { } ,
197
+ destroyed : { } ,
198
+ decodeStrings : { } ,
199
+ writing : { } ,
200
+ sync : { } ,
201
+ bufferProcessing : { } ,
202
+ prefinished : { } ,
203
+ errorEmitted : { } ,
204
+ emitClose : { } ,
205
+ autoDestroy : { } ,
206
+ errored : { }
207
+ } ) ) {
208
+ options = options || { }
209
+ const mask = 1 << ( Object . keys ( F ) . length + 8 ) ;
210
+ F [ key ] = mask ;
211
+ ObjectDefineProperty ( WritableState . prototype , key , {
212
+ get ( ) {
213
+ return ! ! ( this . bitfield & mask ) ;
214
+ } ,
215
+ set ( val ) {
216
+ if ( val ) {
217
+ this . bitfield |= mask ;
218
+ } else {
219
+ this . bitfield &= ~ mask ;
220
+ }
221
+ }
222
+ } )
223
+ }
224
+
225
+ ObjectDefineProperty ( WritableState . prototype , 'needDrain' , {
226
+ get ( ) {
227
+ return ! this . drained ;
228
+ } ,
229
+ set ( val ) {
230
+ this . drained = ! val ;
231
+ }
232
+ } ) ;
233
+
234
+ F . corked = 0xF0 ;
235
+ ObjectDefineProperty ( WritableState . prototype , 'corked' , {
236
+ get ( ) {
237
+ return ( this . bitfield & F . corked ) >> 4 ;
238
+ } ,
239
+ set ( val ) {
240
+ this . bitfield &= ~ F . corked ;
241
+ this . bitfield |= ( val << 4 ) & F . corked ;
242
+ }
243
+ } ) ;
244
+
245
+ F . pendingcb = 0xF ;
246
+ ObjectDefineProperty ( WritableState . prototype , 'pendingcb' , {
247
+ get ( ) {
248
+ return ( this . bitfield & F . pendingcb ) ;
249
+ } ,
250
+ set ( val ) {
251
+ this . bitfield &= ~ F . pendingcb ;
252
+ this . bitfield |= ( val & F . pendingcb ) ;
253
+ }
254
+ } ) ;
255
+
187
256
WritableState . prototype . getBuffer = function getBuffer ( ) {
188
257
var current = this . bufferedRequest ;
189
258
const out = [ ] ;
@@ -294,8 +363,9 @@ function validChunk(stream, state, chunk, cb) {
294
363
295
364
Writable . prototype . write = function ( chunk , encoding , cb ) {
296
365
const state = this . _writableState ;
366
+ const objectMode = state . bitfield & F . objectMode ;
297
367
var ret = false ;
298
- const isBuf = ! state . objectMode && Stream . _isUint8Array ( chunk ) ;
368
+ const isBuf = ! objectMode && Stream . _isUint8Array ( chunk ) ;
299
369
300
370
// Do not use Object.getPrototypeOf as it is slower since V8 7.3.
301
371
if ( isBuf && ! ( chunk instanceof Buffer ) ) {
@@ -315,12 +385,14 @@ Writable.prototype.write = function(chunk, encoding, cb) {
315
385
if ( typeof cb !== 'function' )
316
386
cb = nop ;
317
387
318
- if ( state . ending ) {
319
- writeAfterEnd ( this , cb ) ;
320
- } else if ( state . destroyed ) {
321
- const err = new ERR_STREAM_DESTROYED ( 'write' ) ;
322
- process . nextTick ( cb , err ) ;
323
- errorOrDestroy ( this , err ) ;
388
+ if ( state . bitfield & ( F . ending | F . destroyed ) ) {
389
+ if ( state . ending ) {
390
+ writeAfterEnd ( this , cb ) ;
391
+ } else if ( state . destroyed ) {
392
+ const err = new ERR_STREAM_DESTROYED ( 'write' ) ;
393
+ process . nextTick ( cb , err ) ;
394
+ errorOrDestroy ( this , err ) ;
395
+ }
324
396
} else if ( isBuf || validChunk ( this , state , chunk , cb ) ) {
325
397
state . pendingcb ++ ;
326
398
ret = writeOrBuffer ( this , state , chunk , encoding , cb ) ;
@@ -401,8 +473,11 @@ ObjectDefineProperty(Writable.prototype, 'writableCorked', {
401
473
// in the queue, and wait our turn. Otherwise, call _write
402
474
// If we return false, then we need a drain event, so set that flag.
403
475
function writeOrBuffer ( stream , state , chunk , encoding , cb ) {
404
- if ( ! state . objectMode &&
405
- state . decodeStrings !== false &&
476
+ const objectMode = state . bitfield & F . objectMode ;
477
+ const decodeStrings = state . bitfield & F . decodeStrings ;
478
+
479
+ if ( ! objectMode &&
480
+ decodeStrings &&
406
481
encoding !== 'buffer' &&
407
482
typeof chunk === 'string' ) {
408
483
chunk = Buffer . from ( chunk , encoding ) ;
@@ -415,9 +490,9 @@ function writeOrBuffer(stream, state, chunk, encoding, cb) {
415
490
const ret = state . length < state . highWaterMark ;
416
491
// We must ensure that previous needDrain will not be reset to false.
417
492
if ( ! ret )
418
- state . needDrain = true ;
493
+ state . bitfield &= ~ F . drained ;
419
494
420
- if ( state . writing || state . corked || state . errored ) {
495
+ if ( state . bitfield & ( F . writing | F . corked | F . errored ) ) {
421
496
var last = state . lastBufferedRequest ;
422
497
state . lastBufferedRequest = {
423
498
chunk,
@@ -437,21 +512,18 @@ function writeOrBuffer(stream, state, chunk, encoding, cb) {
437
512
438
513
// Return false if errored or destroyed in order to break
439
514
// any synchronous while(stream.write(data)) loops.
440
- return ret && ! state . errored && ! state . destroyed ;
515
+ return ret && ! ( state . bitfield & ( F . errored | F . destroyed ) ) ;
441
516
}
442
517
443
518
function doWrite ( stream , state , writev , len , chunk , encoding , cb ) {
444
519
state . writelen = len ;
445
520
state . writecb = cb ;
446
- state . writing = true ;
447
- state . sync = true ;
448
- if ( state . destroyed )
449
- state . onwrite ( new ERR_STREAM_DESTROYED ( 'write' ) ) ;
450
- else if ( writev )
521
+ state . bitfield |= F . writing | F . sync ;
522
+ if ( writev )
451
523
stream . _writev ( chunk , state . onwrite ) ;
452
524
else
453
525
stream . _write ( chunk , encoding , state . onwrite ) ;
454
- state . sync = false ;
526
+ state . bitfield &= ~ F . sync ;
455
527
}
456
528
457
529
function onwriteError ( stream , state , er , cb ) {
@@ -464,15 +536,15 @@ function onwriteError(stream, state, er, cb) {
464
536
465
537
function onwrite ( stream , er ) {
466
538
const state = stream . _writableState ;
467
- const sync = state . sync ;
539
+ const sync = state . bitfield & F . sync ;
468
540
const cb = state . writecb ;
469
541
470
542
if ( typeof cb !== 'function' ) {
471
543
errorOrDestroy ( stream , new ERR_MULTIPLE_CALLBACK ( ) ) ;
472
544
return ;
473
545
}
474
546
475
- state . writing = false ;
547
+ state . bitfield &= ~ F . writing ;
476
548
state . writecb = null ;
477
549
state . length -= state . writelen ;
478
550
state . writelen = 0 ;
@@ -485,12 +557,7 @@ function onwrite(stream, er) {
485
557
onwriteError ( stream , state , er , cb ) ;
486
558
}
487
559
} else {
488
- // Check if we're actually ready to finish, but don't emit yet
489
- var finished = needFinish ( state ) || stream . destroyed ;
490
-
491
- if ( ! finished &&
492
- ! state . corked &&
493
- ! state . bufferProcessing &&
560
+ if ( ! ( state . bitfield & ( F . corked | F . bufferProcessing ) ) &&
494
561
state . bufferedRequest ) {
495
562
clearBuffer ( stream , state ) ;
496
563
}
@@ -519,10 +586,10 @@ function afterWriteTick({ stream, state, count, cb }) {
519
586
}
520
587
521
588
function afterWrite ( stream , state , count , cb ) {
522
- const needDrain = ! state . ending && ! stream . destroyed && state . length === 0 &&
523
- state . needDrain ;
589
+ const needDrain = ! ( state . bitfield & ( F . ending | F . destroyed | F . drained ) ) &&
590
+ state . length === 0 ;
524
591
if ( needDrain ) {
525
- state . needDrain = false ;
592
+ state . bitfield |= F . drained ;
526
593
stream . emit ( 'drain' ) ;
527
594
}
528
595
@@ -536,7 +603,7 @@ function afterWrite(stream, state, count, cb) {
536
603
537
604
// If there's something in the buffer waiting, then process it
538
605
function clearBuffer ( stream , state ) {
539
- state . bufferProcessing = true ;
606
+ state . bitfield |= F . bufferProcessing ;
540
607
var entry = state . bufferedRequest ;
541
608
542
609
if ( stream . _writev && entry && entry . next ) {
@@ -597,7 +664,7 @@ function clearBuffer(stream, state) {
597
664
}
598
665
599
666
state . bufferedRequest = entry ;
600
- state . bufferProcessing = false ;
667
+ state . bitfield &= ~ F . bufferProcessing ;
601
668
}
602
669
603
670
Writable . prototype . _write = function ( chunk , encoding , cb ) {
@@ -656,12 +723,10 @@ ObjectDefineProperty(Writable.prototype, 'writableLength', {
656
723
} ) ;
657
724
658
725
function needFinish ( state ) {
659
- return ( state . ending &&
726
+ return ( ( state . bitfield & F . ending ) &&
727
+ ! ( state . bitfield & ( F . errored | F . finished | F . writing ) ) &&
660
728
state . length === 0 &&
661
- ! state . errored &&
662
- state . bufferedRequest === null &&
663
- ! state . finished &&
664
- ! state . writing ) ;
729
+ state . bufferedRequest === null ) ;
665
730
}
666
731
667
732
function callFinal ( stream , state ) {
0 commit comments