@@ -34,6 +34,7 @@ const {
3434 SymbolAsyncDispose,
3535 SymbolAsyncIterator,
3636 Symbol,
37+ TypedArrayPrototypeSet,
3738} = primordials ;
3839
3940module . exports = Readable ;
@@ -73,6 +74,7 @@ const {
7374const { validateObject } = require ( 'internal/validators' ) ;
7475
7576const kState = Symbol ( 'kState' ) ;
77+ const FastBuffer = Buffer [ Symbol . species ] ;
7678
7779const { StringDecoder } = require ( 'string_decoder' ) ;
7880const from = require ( 'internal/streams/from' ) ;
@@ -278,7 +280,8 @@ function ReadableState(options, stream, isDuplex) {
278280 // A linked list is used to store data chunks instead of an array because the
279281 // linked list can remove elements from the beginning faster than
280282 // array.shift().
281- this . buffer = new BufferList ( ) ;
283+ this . buffer = [ ] ;
284+ this . bufferIndex = 0 ;
282285 this . length = 0 ;
283286 this . pipes = [ ] ;
284287
@@ -546,10 +549,19 @@ function addChunk(stream, state, chunk, addToFront) {
546549 } else {
547550 // Update the buffer info.
548551 state . length += ( state [ kState ] & kObjectMode ) !== 0 ? 1 : chunk . length ;
549- if ( addToFront )
552+ if ( addToFront ) {
553+ state . buffer . splice ( 0 , state . bufferIndex ) ;
554+ state . bufferIndex = 0 ;
550555 state . buffer . unshift ( chunk ) ;
551- else
556+
557+ // if (state.bufferIndex > 0) {
558+ // state.buffer[--state.bufferIndex] = chunk;
559+ // } else {
560+ // state.buffer.unshift(chunk); // Slow path
561+ // }
562+ } else {
552563 state . buffer . push ( chunk ) ;
564+ }
553565
554566 if ( ( state [ kState ] & kNeedReadable ) !== 0 )
555567 emitReadable ( stream ) ;
@@ -564,21 +576,24 @@ Readable.prototype.isPaused = function() {
564576
565577// Backwards compatibility.
566578Readable . prototype . setEncoding = function ( enc ) {
579+ const state = this . _readableState ;
580+
567581 const decoder = new StringDecoder ( enc ) ;
568- this . _readableState . decoder = decoder ;
582+ state . decoder = decoder ;
569583 // If setEncoding(null), decoder.encoding equals utf8.
570- this . _readableState . encoding = this . _readableState . decoder . encoding ;
584+ state . encoding = state . decoder . encoding ;
571585
572- const buffer = this . _readableState . buffer ;
573586 // Iterate over current buffer to convert already stored Buffers:
574587 let content = '' ;
575- for ( const data of buffer ) {
588+ for ( const data of state . buffer . slice ( state . bufferIndex ) ) {
576589 content += decoder . write ( data ) ;
577590 }
578- buffer . clear ( ) ;
591+ state . buffer . length = 0 ;
592+ state . bufferIndex = 0 ;
593+
579594 if ( content !== '' )
580- buffer . push ( content ) ;
581- this . _readableState . length = content . length ;
595+ state . buffer . push ( content ) ;
596+ state . length = content . length ;
582597 return this ;
583598} ;
584599
@@ -611,7 +626,7 @@ function howMuchToRead(n, state) {
611626 if ( NumberIsNaN ( n ) ) {
612627 // Only flow one buffer at a time.
613628 if ( ( state [ kState ] & kFlowing ) !== 0 && state . length )
614- return state . buffer . first ( ) . length ;
629+ return state . buffer [ state . bufferIndex ] . length ;
615630 return state . length ;
616631 }
617632 if ( n <= state . length )
@@ -1549,21 +1564,100 @@ function fromList(n, state) {
15491564 if ( state . length === 0 )
15501565 return null ;
15511566
1567+ let idx = state . bufferIndex ;
15521568 let ret ;
1553- if ( state . objectMode )
1554- ret = state . buffer . shift ( ) ;
1555- else if ( ! n || n >= state . length ) {
1569+
1570+ const buf = state . buffer ;
1571+ const len = buf . length ;
1572+
1573+ if ( ( state [ kState ] & kObjectMode ) !== 0 ) {
1574+ ret = buf [ idx ] ;
1575+ buf [ idx ++ ] = null ;
1576+ } else if ( ! n || n >= state . length ) {
15561577 // 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 ( ) ;
1578+ if ( ( state [ kState ] & kDecoder ) !== 0 ) {
1579+ ret = ''
1580+ while ( idx < len ) {
1581+ ret += buf [ idx ] ;
1582+ buf [ idx ++ ] = null ;
1583+ }
1584+ } else if ( len - idx === 0 ) {
1585+ ret = Buffer . alloc ( 0 )
1586+ } else if ( len - idx === 1 ) {
1587+ ret = buf [ idx ] ;
1588+ buf [ idx ++ ] = null ;
1589+ } else {
1590+ ret = Buffer . allocUnsafe ( state . length ) ;
1591+
1592+ let i = 0 ;
1593+ while ( idx < len ) {
1594+ TypedArrayPrototypeSet ( ret , buf [ idx ] , i ) ;
1595+ i += buf [ idx ] . length ;
1596+ buf [ idx ++ ] = null ;
1597+ }
1598+ }
15641599 } else {
15651600 // read part of list.
1566- ret = state . buffer . consume ( n , state . decoder ) ;
1601+
1602+ if ( n < buf [ idx ] . length ) {
1603+ // `slice` is the same for buffers and strings.
1604+ ret = buf [ idx ] . slice ( 0 , n ) ;
1605+ buf [ idx ] = buf [ idx ] . slice ( n ) ;
1606+ } else if ( n === buf [ idx ] . length ) {
1607+ // First chunk is a perfect match.
1608+ ret = buf [ idx ] ;
1609+ buf [ idx ++ ] = null ;
1610+ } else if ( ( state [ kState ] & kDecoder ) !== 0 ) {
1611+ ret = '' ;
1612+ while ( idx < len ) {
1613+ const str = buf [ idx ] ;
1614+ if ( n > str . length ) {
1615+ ret += str ;
1616+ n -= str . length ;
1617+ buf [ idx ++ ] = null ;
1618+ } else {
1619+ if ( n === buf . length ) {
1620+ ret += str ;
1621+ buf [ idx ++ ] = null ;
1622+ } else {
1623+ ret += str . slice ( 0 , n ) ;
1624+ buf [ idx ] = str . slice ( n ) ;
1625+ }
1626+ break ;
1627+ }
1628+ }
1629+ } else {
1630+ ret = Buffer . allocUnsafe ( n ) ;
1631+
1632+ const retLen = n ;
1633+ while ( idx < len ) {
1634+ const data = buf [ idx ] ;
1635+ if ( n > data . length ) {
1636+ TypedArrayPrototypeSet ( ret , data , retLen - n ) ;
1637+ n -= data . length ;
1638+ buf [ idx ++ ] = null ;
1639+ } else {
1640+ if ( n === data . length ) {
1641+ TypedArrayPrototypeSet ( ret , data , retLen - n ) ;
1642+ buf [ idx ++ ] = null ;
1643+ } else {
1644+ TypedArrayPrototypeSet ( ret , new FastBuffer ( data . buffer , data . byteOffset , n ) , retLen - n ) ;
1645+ buf [ idx ] = new FastBuffer ( data . buffer , data . byteOffset + n , data . length - n ) ;
1646+ }
1647+ break ;
1648+ }
1649+ }
1650+ }
1651+ }
1652+
1653+ if ( idx === buf . length ) {
1654+ state . buffer . length = 0 ;
1655+ state . bufferIndex = 0
1656+ } else if ( idx > 1024 ) {
1657+ state . buffer . splice ( 0 , idx ) ;
1658+ state . bufferIndex = 0 ;
1659+ } else {
1660+ state . bufferIndex = idx ;
15671661 }
15681662
15691663 return ret ;
0 commit comments