Skip to content

Commit 9c9c408

Browse files
committed
stream: add Readable.readv
A faster alternative to Readable.read for certain use cases. e.g. fs.writevSync(fd, readable.readv())
1 parent 6176222 commit 9c9c408

File tree

1 file changed

+95
-3
lines changed

1 file changed

+95
-3
lines changed

lib/internal/streams/readable.js

Lines changed: 95 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -641,8 +641,16 @@ function howMuchToRead(n, state) {
641641
return (state[kState] & kEnded) !== 0 ? state.length : 0;
642642
}
643643

644+
Readable.prototype.readv = function readv () {
645+
return _read.call(this, true);
646+
};
647+
648+
Readable.prototype.read = function read () {
649+
return _read.call(this, false);
650+
}
651+
644652
// You can override either this method, or the async _read(n) below.
645-
Readable.prototype.read = function(n) {
653+
function _read (n, returnArr) {
646654
debug('read', n);
647655
// Same as parseInt(undefined, 10), however V8 7.3 performance regressed
648656
// in this scenario, so we are doing it manually.
@@ -748,7 +756,7 @@ Readable.prototype.read = function(n) {
748756

749757
let ret;
750758
if (n > 0)
751-
ret = fromList(n, state);
759+
ret = returnArr ? arrFromList(n, state) : fromList(n, state);
752760
else
753761
ret = null;
754762

@@ -777,7 +785,13 @@ Readable.prototype.read = function(n) {
777785

778786
if (ret !== null && (state[kState] & (kErrorEmitted | kCloseEmitted)) === 0) {
779787
state[kState] |= kDataEmitted;
780-
this.emit('data', ret);
788+
if (returnArr) {
789+
for (let i = 0; i < ret.length; ++i) {
790+
this.emit('data', ret[i]);
791+
}
792+
} else {
793+
this.emit('data', ret);
794+
}
781795
}
782796

783797
return ret;
@@ -1596,6 +1610,7 @@ function fromList(n, state) {
15961610
if ((state[kState] & kObjectMode) !== 0) {
15971611
ret = buf[idx];
15981612
buf[idx++] = null;
1613+
ret = returnArr ? [ret] : ret;
15991614
} else if (!n || n >= state.length) {
16001615
// Read it all, truncate the list.
16011616
if ((state[kState] & kDecoder) !== 0) {
@@ -1682,6 +1697,83 @@ function fromList(n, state) {
16821697
return ret;
16831698
}
16841699

1700+
function arrFromList(n, state) {
1701+
// nothing buffered.
1702+
if (state.length === 0)
1703+
return null;
1704+
1705+
let idx = state.bufferIndex;
1706+
let ret;
1707+
1708+
const buf = state.buffer;
1709+
const len = buf.length;
1710+
1711+
if ((state[kState] & kObjectMode) !== 0 || !n || n >= state.length) {
1712+
ret = buf.slice(idx);
1713+
idx += ret.length;
1714+
} else if (n < buf[idx].length) {
1715+
// `slice` is the same for buffers and strings.
1716+
ret = [buf[idx].slice(0, n)];
1717+
buf[idx] = buf[idx].slice(n);
1718+
} else if (n === buf[idx].length) {
1719+
// First chunk is a perfect match.
1720+
ret = buf[idx];
1721+
buf[idx++] = null;
1722+
ret = returnArr ? [ret] : ret;
1723+
} else if ((state[kState] & kDecoder) !== 0) {
1724+
ret = [];
1725+
while (idx < len) {
1726+
const str = buf[idx];
1727+
if (n > str.length) {
1728+
ret.push(str);
1729+
n -= str.length;
1730+
buf[idx++] = null;
1731+
} else {
1732+
if (n === buf.length) {
1733+
ret.push(str);
1734+
buf[idx++] = null;
1735+
} else {
1736+
ret.push(str.slice(0, n));
1737+
buf[idx] = str.slice(n);
1738+
}
1739+
break;
1740+
}
1741+
}
1742+
} else {
1743+
ret = [];
1744+
const retLen = n;
1745+
while (idx < len) {
1746+
const data = buf[idx];
1747+
if (n > data.length) {
1748+
ret.push(data);
1749+
n -= data.length;
1750+
buf[idx++] = null;
1751+
} else {
1752+
if (n === data.length) {
1753+
ret.push(data);
1754+
buf[idx++] = null;
1755+
} else {
1756+
ret.push(new FastBuffer(data.buffer, data.byteOffset, n));
1757+
buf[idx] = new FastBuffer(data.buffer, data.byteOffset + n, data.length - n);
1758+
}
1759+
break;
1760+
}
1761+
}
1762+
}
1763+
1764+
if (idx === len) {
1765+
state.buffer.length = 0;
1766+
state.bufferIndex = 0;
1767+
} else if (idx > 1024) {
1768+
state.buffer.splice(0, idx);
1769+
state.bufferIndex = 0;
1770+
} else {
1771+
state.bufferIndex = idx;
1772+
}
1773+
1774+
return ret;
1775+
}
1776+
16851777
function endReadable(stream) {
16861778
const state = stream._readableState;
16871779

0 commit comments

Comments
 (0)