@@ -73,6 +73,7 @@ const {
73
73
const { validateObject } = require ( 'internal/validators' ) ;
74
74
75
75
const kState = Symbol ( 'kState' ) ;
76
+ const FastBuffer = Buffer [ Symbol . species ] ;
76
77
77
78
const { StringDecoder } = require ( 'string_decoder' ) ;
78
79
const from = require ( 'internal/streams/from' ) ;
@@ -278,7 +279,8 @@ function ReadableState(options, stream, isDuplex) {
278
279
// A linked list is used to store data chunks instead of an array because the
279
280
// linked list can remove elements from the beginning faster than
280
281
// array.shift().
281
- this . buffer = new BufferList ( ) ;
282
+ this . buffer = [ ] ;
283
+ this . bufferIndex = 0 ;
282
284
this . length = 0 ;
283
285
this . pipes = [ ] ;
284
286
@@ -546,10 +548,15 @@ function addChunk(stream, state, chunk, addToFront) {
546
548
} else {
547
549
// Update the buffer info.
548
550
state . length += ( state [ kState ] & kObjectMode ) !== 0 ? 1 : chunk . length ;
549
- if ( addToFront )
550
- state . buffer . unshift ( chunk ) ;
551
- else
551
+ if ( addToFront ) {
552
+ if ( state . bufferIndex > 0 ) {
553
+ state . buffer [ -- state . bufferIndex ] = chunk ;
554
+ } else {
555
+ state . buffer . unshift ( chunk ) ; // Slow path
556
+ }
557
+ } else {
552
558
state . buffer . push ( chunk ) ;
559
+ }
553
560
554
561
if ( ( state [ kState ] & kNeedReadable ) !== 0 )
555
562
emitReadable ( stream ) ;
@@ -564,21 +571,24 @@ Readable.prototype.isPaused = function() {
564
571
565
572
// Backwards compatibility.
566
573
Readable . prototype . setEncoding = function ( enc ) {
574
+ const state = this . _readableState ;
575
+
567
576
const decoder = new StringDecoder ( enc ) ;
568
- this . _readableState . decoder = decoder ;
577
+ state . decoder = decoder ;
569
578
// If setEncoding(null), decoder.encoding equals utf8.
570
- this . _readableState . encoding = this . _readableState . decoder . encoding ;
579
+ state . encoding = state . decoder . encoding ;
571
580
572
- const buffer = this . _readableState . buffer ;
573
581
// Iterate over current buffer to convert already stored Buffers:
574
582
let content = '' ;
575
- for ( const data of buffer ) {
583
+ for ( const data of state . buffer . slice ( state . bufferIndex ) ) {
576
584
content += decoder . write ( data ) ;
577
585
}
578
- buffer . clear ( ) ;
586
+ state . buffer . length = 0 ;
587
+ state . bufferIndex = 0 ;
588
+
579
589
if ( content !== '' )
580
590
buffer . push ( content ) ;
581
- this . _readableState . length = content . length ;
591
+ state . length = content . length ;
582
592
return this ;
583
593
} ;
584
594
@@ -611,7 +621,7 @@ function howMuchToRead(n, state) {
611
621
if ( NumberIsNaN ( n ) ) {
612
622
// Only flow one buffer at a time.
613
623
if ( ( state [ kState ] & kFlowing ) !== 0 && state . length )
614
- return state . buffer . first ( ) . length ;
624
+ return state . buffer [ state . bufferIndex ] . length ;
615
625
return state . length ;
616
626
}
617
627
if ( n <= state . length )
@@ -1550,20 +1560,96 @@ function fromList(n, state) {
1550
1560
return null ;
1551
1561
1552
1562
let ret ;
1553
- if ( state . objectMode )
1554
- ret = state . buffer . shift ( ) ;
1555
- else if ( ! n || n >= state . length ) {
1563
+ if ( ( state [ kState ] & kObjectMode ) !== 0 ) {
1564
+ ret = state . buffer [ state . bufferIndex ++ ] ;
1565
+ } else if ( ! n || n >= state . length ) {
1556
1566
// Read it all, truncate the list.
1557
- if ( state . decoder )
1558
- ret = state . buffer . join ( '' ) ;
1559
- else if ( state . buffer . length === 1 )
1560
- ret = state . buffer . first ( ) ;
1561
- else
1562
- ret = state . buffer . concat ( state . length ) ;
1563
- state . buffer . clear ( ) ;
1567
+ if ( ( state [ kState ] & kDecoder ) !== 0 ) {
1568
+ ret = ''
1569
+ for ( let n = state . bufferIndex ; n < state . buffer . length ; n ++ ) {
1570
+ ret += state . buffer [ n ] ;
1571
+ }
1572
+ } else if ( state . buffer . length - state . bufferIndex === 0 ) {
1573
+ ret = Buffer . alloc ( 0 )
1574
+ } else if ( state . buffer . length - state . bufferIndex === 1 ) {
1575
+ ret = state . buffer [ state . bufferIndex ] ;
1576
+ } else {
1577
+ ret = Buffer . allocUnsafe ( n >>> 0 ) ;
1578
+ let i = 0 ;
1579
+ for ( let n = state . bufferIndex ; n < state . buffer . length ; n ++ ) {
1580
+ const data = state . buffer [ n ] ;
1581
+ ret . set ( data , i ) ;
1582
+ i += data . length ;
1583
+ }
1584
+ }
1585
+ state . buffer . length = 0 ;
1586
+ state . bufferIndex = 0 ;
1564
1587
} else {
1565
1588
// read part of list.
1566
- ret = state . buffer . consume ( n , state . decoder ) ;
1589
+
1590
+ const buf = state . buffer ;
1591
+ const len = buf . length ;
1592
+
1593
+ let idx = state . bufferIndex ;
1594
+
1595
+ if ( n < buf [ idx ] . length ) {
1596
+ // `slice` is the same for buffers and strings.
1597
+ ret = buf [ idx ] . slice ( 0 , n ) ;
1598
+ buf [ idx ] = buf [ idx ] . slice ( n ) ;
1599
+ } else if ( n === data . length ) {
1600
+ // First chunk is a perfect match.
1601
+ ret = buf [ idx ++ ] ;
1602
+ } else if ( ( state [ kState ] & kDecoder ) !== 0 ) {
1603
+ ret = '' ;
1604
+ while ( idx < state . buffer . length ) {
1605
+ const str = buf [ idx ] ;
1606
+ if ( n > str . length ) {
1607
+ ret += str ;
1608
+ n -= str . length ;
1609
+ idx ++ ;
1610
+ } else {
1611
+ if ( n === buf . length ) {
1612
+ ret += str ;
1613
+ idx ++ ;
1614
+ } else {
1615
+ ret += str . slice ( 0 , n ) ;
1616
+ buf [ idx ] = str . slice ( n ) ;
1617
+ }
1618
+ break ;
1619
+ }
1620
+ }
1621
+ } else {
1622
+ ret = Buffer . allocUnsafe ( n ) ;
1623
+
1624
+ const retLen = n ;
1625
+ while ( idx < len ) {
1626
+ const data = buf [ idx ] ;
1627
+ if ( n > data . length ) {
1628
+ ret . set ( data , retLen - n ) ;
1629
+ n -= data . length ;
1630
+ idx ++ ;
1631
+ } else {
1632
+ if ( n === data . length ) {
1633
+ ret . set ( data , retLen - n ) ;
1634
+ idx ++ ;
1635
+ } else {
1636
+ ret . set ( new FastBuffer ( data . buffer , data . byteOffset , n ) , retLen - n ) ;
1637
+ buf [ idx ] = new FastBuffer ( data . buffer , data . byteOffset + n ) ;
1638
+ }
1639
+ break ;
1640
+ }
1641
+ }
1642
+ }
1643
+
1644
+ if ( idx === buf . length ) {
1645
+ state . buffer . length = 0 ;
1646
+ state . bufferIndex = 0
1647
+ } else if ( idx > 1024 ) {
1648
+ state . buffer . splice ( 0 , idx ) ;
1649
+ state . bufferIndex = 0 ;
1650
+ } else {
1651
+ state . bufferIndex = idx ;
1652
+ }
1567
1653
}
1568
1654
1569
1655
return ret ;
0 commit comments