Skip to content

Commit 144f3d9

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 144f3d9

File tree

1 file changed

+102
-33
lines changed

1 file changed

+102
-33
lines changed

lib/internal/streams/readable.js

Lines changed: 102 additions & 33 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 = fromList(n, state, returnArr);
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;
@@ -1582,7 +1596,7 @@ Readable._fromList = fromList;
15821596
// Length is the combined lengths of all the buffers in the list.
15831597
// This function is designed to be inlinable, so please take care when making
15841598
// changes to the function body.
1585-
function fromList(n, state) {
1599+
function fromList(n, state, returnArr) {
15861600
// nothing buffered.
15871601
if (state.length === 0)
15881602
return null;
@@ -1594,11 +1608,20 @@ function fromList(n, state) {
15941608
const len = buf.length;
15951609

15961610
if ((state[kState] & kObjectMode) !== 0) {
1597-
ret = buf[idx];
1598-
buf[idx++] = null;
1611+
if (returnArr) {
1612+
ret = buf.slice(idx);
1613+
idx += ret.length;
1614+
} else {
1615+
ret = buf[idx];
1616+
buf[idx++] = null;
1617+
ret = returnArr ? [ret] : ret;
1618+
}
15991619
} else if (!n || n >= state.length) {
16001620
// Read it all, truncate the list.
1601-
if ((state[kState] & kDecoder) !== 0) {
1621+
if (returnArr) {
1622+
ret = buf.slice(idx);
1623+
idx += ret.length;
1624+
} else if ((state[kState] & kDecoder) !== 0) {
16021625
ret = '';
16031626
while (idx < len) {
16041627
ret += buf[idx];
@@ -1623,48 +1646,94 @@ function fromList(n, state) {
16231646
// `slice` is the same for buffers and strings.
16241647
ret = buf[idx].slice(0, n);
16251648
buf[idx] = buf[idx].slice(n);
1649+
ret = returnArr ? [ret] : ret;
16261650
} else if (n === buf[idx].length) {
16271651
// First chunk is a perfect match.
16281652
ret = buf[idx];
16291653
buf[idx++] = null;
1654+
ret = returnArr ? [ret] : ret;
16301655
} else if ((state[kState] & kDecoder) !== 0) {
1631-
ret = '';
1632-
while (idx < len) {
1633-
const str = buf[idx];
1634-
if (n > str.length) {
1635-
ret += str;
1636-
n -= str.length;
1637-
buf[idx++] = null;
1638-
} else {
1639-
if (n === buf.length) {
1656+
if (returnArr) {
1657+
ret = [];
1658+
while (idx < len) {
1659+
const str = buf[idx];
1660+
if (n > str.length) {
1661+
ret.push(str);
1662+
n -= str.length;
1663+
buf[idx++] = null;
1664+
} else {
1665+
if (n === buf.length) {
1666+
ret.push(str);
1667+
buf[idx++] = null;
1668+
} else {
1669+
ret.push(str.slice(0, n));
1670+
buf[idx] = str.slice(n);
1671+
}
1672+
break;
1673+
}
1674+
}
1675+
} else {
1676+
ret = '';
1677+
while (idx < len) {
1678+
const str = buf[idx];
1679+
if (n > str.length) {
16401680
ret += str;
1681+
n -= str.length;
16411682
buf[idx++] = null;
16421683
} else {
1643-
ret += str.slice(0, n);
1644-
buf[idx] = str.slice(n);
1684+
if (n === buf.length) {
1685+
ret += str;
1686+
buf[idx++] = null;
1687+
} else {
1688+
ret += str.slice(0, n);
1689+
buf[idx] = str.slice(n);
1690+
}
1691+
break;
16451692
}
1646-
break;
16471693
}
16481694
}
16491695
} else {
1650-
ret = Buffer.allocUnsafe(n);
1651-
1652-
const retLen = n;
1653-
while (idx < len) {
1654-
const data = buf[idx];
1655-
if (n > data.length) {
1656-
TypedArrayPrototypeSet(ret, data, retLen - n);
1657-
n -= data.length;
1658-
buf[idx++] = null;
1659-
} else {
1660-
if (n === data.length) {
1696+
if (returnArr) {
1697+
ret = [];
1698+
1699+
const retLen = n;
1700+
while (idx < len) {
1701+
const data = buf[idx];
1702+
if (n > data.length) {
1703+
ret.push(data);
1704+
n -= data.length;
1705+
buf[idx++] = null;
1706+
} else {
1707+
if (n === data.length) {
1708+
ret.push(data);
1709+
buf[idx++] = null;
1710+
} else {
1711+
ret.push(new FastBuffer(data.buffer, data.byteOffset, n));
1712+
buf[idx] = new FastBuffer(data.buffer, data.byteOffset + n, data.length - n);
1713+
}
1714+
break;
1715+
}
1716+
}
1717+
} else {
1718+
ret = Buffer.allocUnsafe(n);
1719+
1720+
const retLen = n;
1721+
while (idx < len) {
1722+
const data = buf[idx];
1723+
if (n > data.length) {
16611724
TypedArrayPrototypeSet(ret, data, retLen - n);
1725+
n -= data.length;
16621726
buf[idx++] = null;
16631727
} else {
1664-
TypedArrayPrototypeSet(ret, new FastBuffer(data.buffer, data.byteOffset, n), retLen - n);
1665-
buf[idx] = new FastBuffer(data.buffer, data.byteOffset + n, data.length - n);
1728+
if (n === data.length) {
1729+
TypedArrayPrototypeSet(ret, data, retLen - n);
1730+
buf[idx++] = null;
1731+
} else {
1732+
TypedArrayPrototypeSet(ret, new FastBuffer(data.buffer, data.byteOffset, n), retLen - n);
1733+
buf[idx] = new FastBuffer(data.buffer, data.byteOffset + n, data.length - n);
1734+
}
1735+
break;
16661736
}
1667-
break;
16681737
}
16691738
}
16701739
}

0 commit comments

Comments
 (0)