@@ -73,6 +73,7 @@ const {
7373const { validateObject } = require ( 'internal/validators' ) ;
7474
7575const kState = Symbol ( 'kState' ) ;
76+ const FastBuffer = Buffer [ Symbol . species ] ;
7677
7778const { StringDecoder } = require ( 'string_decoder' ) ;
7879const from = require ( 'internal/streams/from' ) ;
@@ -278,7 +279,8 @@ function ReadableState(options, stream, isDuplex) {
278279 // A linked list is used to store data chunks instead of an array because the
279280 // linked list can remove elements from the beginning faster than
280281 // array.shift().
281- this . buffer = new BufferList ( ) ;
282+ this . buffer = [ ] ;
283+ this . bufferIndex = 0 ;
282284 this . length = 0 ;
283285 this . pipes = [ ] ;
284286
@@ -546,10 +548,15 @@ function addChunk(stream, state, chunk, addToFront) {
546548 } else {
547549 // Update the buffer info.
548550 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 {
552558 state . buffer . push ( chunk ) ;
559+ }
553560
554561 if ( ( state [ kState ] & kNeedReadable ) !== 0 )
555562 emitReadable ( stream ) ;
@@ -564,21 +571,24 @@ Readable.prototype.isPaused = function() {
564571
565572// Backwards compatibility.
566573Readable . prototype . setEncoding = function ( enc ) {
574+ const state = this . _readableState ;
575+
567576 const decoder = new StringDecoder ( enc ) ;
568- this . _readableState . decoder = decoder ;
577+ state . decoder = decoder ;
569578 // If setEncoding(null), decoder.encoding equals utf8.
570- this . _readableState . encoding = this . _readableState . decoder . encoding ;
579+ state . encoding = state . decoder . encoding ;
571580
572- const buffer = this . _readableState . buffer ;
573581 // Iterate over current buffer to convert already stored Buffers:
574582 let content = '' ;
575- for ( const data of buffer ) {
583+ for ( const data of state . buffer . slice ( state . bufferIndex ) ) {
576584 content += decoder . write ( data ) ;
577585 }
578- buffer . clear ( ) ;
586+ state . buffer . length = 0 ;
587+ state . bufferIndex = 0 ;
588+
579589 if ( content !== '' )
580590 buffer . push ( content ) ;
581- this . _readableState . length = content . length ;
591+ state . length = content . length ;
582592 return this ;
583593} ;
584594
@@ -611,7 +621,7 @@ function howMuchToRead(n, state) {
611621 if ( NumberIsNaN ( n ) ) {
612622 // Only flow one buffer at a time.
613623 if ( ( state [ kState ] & kFlowing ) !== 0 && state . length )
614- return state . buffer . first ( ) . length ;
624+ return state . buffer [ state . bufferIndex ] . length ;
615625 return state . length ;
616626 }
617627 if ( n <= state . length )
@@ -1550,20 +1560,100 @@ function fromList(n, state) {
15501560 return null ;
15511561
15521562 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 ) {
15561566 // 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+
1579+ const idx = state . bufferIndex ;
1580+ const buf = state . buffer ;
1581+ const len = buf . length ;
1582+
1583+ let i = 0 ;
1584+ for ( let n = idx ; n < len ; n ++ ) {
1585+ ret . set ( buf [ n ] , i ) ;
1586+ i += buf [ n ] . length ;
1587+ }
1588+ }
1589+ state . buffer . length = 0 ;
1590+ state . bufferIndex = 0 ;
15641591 } else {
15651592 // read part of list.
1566- ret = state . buffer . consume ( n , state . decoder ) ;
1593+
1594+ const buf = state . buffer ;
1595+ const len = buf . length ;
1596+
1597+ let idx = state . bufferIndex ;
1598+
1599+ if ( n < buf [ idx ] . length ) {
1600+ // `slice` is the same for buffers and strings.
1601+ ret = buf [ idx ] . slice ( 0 , n ) ;
1602+ buf [ idx ] = buf [ idx ] . slice ( n ) ;
1603+ } else if ( n === data . length ) {
1604+ // First chunk is a perfect match.
1605+ ret = buf [ idx ++ ] ;
1606+ } else if ( ( state [ kState ] & kDecoder ) !== 0 ) {
1607+ ret = '' ;
1608+ while ( idx < state . buffer . length ) {
1609+ const str = buf [ idx ] ;
1610+ if ( n > str . length ) {
1611+ ret += str ;
1612+ n -= str . length ;
1613+ idx ++ ;
1614+ } else {
1615+ if ( n === buf . length ) {
1616+ ret += str ;
1617+ idx ++ ;
1618+ } else {
1619+ ret += str . slice ( 0 , n ) ;
1620+ buf [ idx ] = str . slice ( n ) ;
1621+ }
1622+ break ;
1623+ }
1624+ }
1625+ } else {
1626+ ret = Buffer . allocUnsafe ( n ) ;
1627+
1628+ const retLen = n ;
1629+ while ( idx < len ) {
1630+ const data = buf [ idx ] ;
1631+ if ( n > data . length ) {
1632+ ret . set ( data , retLen - n ) ;
1633+ n -= data . length ;
1634+ idx ++ ;
1635+ } else {
1636+ if ( n === data . length ) {
1637+ ret . set ( data , retLen - n ) ;
1638+ idx ++ ;
1639+ } else {
1640+ ret . set ( new FastBuffer ( data . buffer , data . byteOffset , n ) , retLen - n ) ;
1641+ buf [ idx ] = new FastBuffer ( data . buffer , data . byteOffset + n ) ;
1642+ }
1643+ break ;
1644+ }
1645+ }
1646+ }
1647+
1648+ if ( idx === buf . length ) {
1649+ state . buffer . length = 0 ;
1650+ state . bufferIndex = 0
1651+ } else if ( idx > 1024 ) {
1652+ state . buffer . splice ( 0 , idx ) ;
1653+ state . bufferIndex = 0 ;
1654+ } else {
1655+ state . bufferIndex = idx ;
1656+ }
15671657 }
15681658
15691659 return ret ;
0 commit comments