@@ -278,7 +278,8 @@ function ReadableState(options, stream, isDuplex) {
278278 // A linked list is used to store data chunks instead of an array because the
279279 // linked list can remove elements from the beginning faster than
280280 // array.shift().
281- this . buffer = new BufferList ( ) ;
281+ this . buffer = [ ] ;
282+ this . bufferIndex = 0 ;
282283 this . length = 0 ;
283284 this . pipes = [ ] ;
284285
@@ -546,10 +547,15 @@ function addChunk(stream, state, chunk, addToFront) {
546547 } else {
547548 // Update the buffer info.
548549 state . length += ( state [ kState ] & kObjectMode ) !== 0 ? 1 : chunk . length ;
549- if ( addToFront )
550- state . buffer . unshift ( chunk ) ;
551- else
550+ if ( addToFront ) {
551+ if ( state . bufferIndex > 0 ) {
552+ state . buffer [ -- state . bufferIndex ] = chunk ;
553+ } else {
554+ state . buffer . unshift ( chunk ) ; // Slow path
555+ }
556+ } else {
552557 state . buffer . push ( chunk ) ;
558+ }
553559
554560 if ( ( state [ kState ] & kNeedReadable ) !== 0 )
555561 emitReadable ( stream ) ;
@@ -564,21 +570,24 @@ Readable.prototype.isPaused = function() {
564570
565571// Backwards compatibility.
566572Readable . prototype . setEncoding = function ( enc ) {
573+ const state = this . _readableState ;
574+
567575 const decoder = new StringDecoder ( enc ) ;
568- this . _readableState . decoder = decoder ;
576+ state . decoder = decoder ;
569577 // If setEncoding(null), decoder.encoding equals utf8.
570- this . _readableState . encoding = this . _readableState . decoder . encoding ;
578+ state . encoding = state . decoder . encoding ;
571579
572- const buffer = this . _readableState . buffer ;
573580 // Iterate over current buffer to convert already stored Buffers:
574581 let content = '' ;
575- for ( const data of buffer ) {
582+ for ( const data of state . buffer . slice ( state . bufferIndex ) ) {
576583 content += decoder . write ( data ) ;
577584 }
578- buffer . clear ( ) ;
585+ state . buffer . length = 0 ;
586+ state . bufferIndex = 0 ;
587+
579588 if ( content !== '' )
580589 buffer . push ( content ) ;
581- this . _readableState . length = content . length ;
590+ state . length = content . length ;
582591 return this ;
583592} ;
584593
@@ -611,7 +620,7 @@ function howMuchToRead(n, state) {
611620 if ( NumberIsNaN ( n ) ) {
612621 // Only flow one buffer at a time.
613622 if ( ( state [ kState ] & kFlowing ) !== 0 && state . length )
614- return state . buffer . first ( ) . length ;
623+ return state . buffer [ state . bufferIndex ] . length ;
615624 return state . length ;
616625 }
617626 if ( n <= state . length )
@@ -1550,20 +1559,96 @@ function fromList(n, state) {
15501559 return null ;
15511560
15521561 let ret ;
1553- if ( state . objectMode )
1554- ret = state . buffer . shift ( ) ;
1555- else if ( ! n || n >= state . length ) {
1562+ if ( ( state [ kState ] & kObjectMode ) !== 0 ) {
1563+ ret = state . buffer [ state . bufferIndex ++ ] ;
1564+ } else if ( ! n || n >= state . length ) {
15561565 // 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 ( ) ;
1566+ if ( ( state [ kState ] & kDecoder ) !== 0 ) {
1567+ ret = ''
1568+ for ( let n = state . bufferIndex ; n < state . buffer . length ; n ++ ) {
1569+ ret += state . buffer [ n ] ;
1570+ }
1571+ } else if ( state . buffer . length - state . bufferIndex === 0 ) {
1572+ ret = Buffer . alloc ( 0 )
1573+ } else if ( state . buffer . length - state . bufferIndex === 1 ) {
1574+ ret = state . buffer [ state . bufferIndex ] ;
1575+ } else {
1576+ ret = Buffer . allocUnsafe ( n >>> 0 ) ;
1577+ let i = 0 ;
1578+ for ( let n = state . bufferIndex ; n < state . buffer . length ; n ++ ) {
1579+ const data = state . buffer [ n ] ;
1580+ ret . set ( data , i ) ;
1581+ i += data . length ;
1582+ }
1583+ }
1584+ state . buffer . length = 0 ;
1585+ state . bufferIndex = 0 ;
15641586 } else {
15651587 // read part of list.
1566- ret = state . buffer . consume ( n , state . decoder ) ;
1588+
1589+ const data = state . buffer [ state . bufferIndex ] ;
1590+
1591+ if ( n < data . length ) {
1592+ // `slice` is the same for buffers and strings.
1593+ const slice = data . slice ( 0 , n ) ;
1594+ state . buffer [ state . bufferIndex ] = data . slice ( n ) ;
1595+ return slice ;
1596+ }
1597+
1598+ if ( n === data . length ) {
1599+ // First chunk is a perfect match.
1600+ return state . buffer [ state . bufferIndex ++ ] ;
1601+ }
1602+
1603+ if ( ( state [ kState ] & kDecoder ) !== 0 ) {
1604+ ret = '' ;
1605+ while ( state . bufferIndex < state . buffer . length ) {
1606+ const str = state . buffer [ state . bufferIndex ] ;
1607+ if ( n > str . length ) {
1608+ ret += str ;
1609+ n -= str . length ;
1610+ state . bufferIndex ++ ;
1611+ } else {
1612+ if ( n === buf . length ) {
1613+ ret += str ;
1614+ state . bufferIndex ++ ;
1615+ } else {
1616+ ret += str . slice ( 0 , n ) ;
1617+ state . buffer [ state . bufferIndex ] = str . slice ( n ) ;
1618+ }
1619+ break ;
1620+ }
1621+ }
1622+ } else {
1623+ ret = Buffer . allocUnsafe ( n ) ;
1624+
1625+ const retLen = n ;
1626+ while ( state . bufferIndex < state . buffer . length ) {
1627+ const buf = state . buffer [ state . bufferIndex ] ;
1628+ if ( n > buf . length ) {
1629+ ret . set ( buf , retLen - n ) ;
1630+ n -= buf . length ;
1631+ state . bufferIndex ++ ;
1632+ } else {
1633+ if ( n === buf . length ) {
1634+ ret . set ( buf , retLen - n ) ;
1635+ state . bufferIndex ++ ;
1636+ } else {
1637+ ret . set ( new Uint8Array ( buf . buffer , buf . byteOffset , n ) , retLen - n ) ;
1638+ state . buffer [ state . bufferIndex ] = buf . slice ( n ) ;
1639+ }
1640+ break ;
1641+ }
1642+ }
1643+ }
1644+
1645+ if ( state . bufferIndex === state . buffer . length ) {
1646+ state . buffer . length = 0 ;
1647+ state . bufferIndex = 0
1648+ } else if ( state . bufferIndex > 256 ) {
1649+ state . buffer = state . buffer . slice ( state . bufferIndex ) ;
1650+ state . bufferIndex = 0 ;
1651+ }
15671652 }
15681653
15691654 return ret ;
0 commit comments