Skip to content

Commit 081fe65

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 081fe65

File tree

1 file changed

+66
-0
lines changed

1 file changed

+66
-0
lines changed

lib/internal/streams/readable.js

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

644+
Readable.prototype.readv = function () {
645+
const state = this._readableState;
646+
647+
state[kState] &= ~kEmittedReadable;
648+
649+
// if we need a readable event, then we need to do some reading.
650+
let doRead = (state[kState] & kNeedReadable) !== 0;
651+
652+
// If we currently have less than the highWaterMark, then also read some.
653+
if (state.length === 0 || state.length - n < state.highWaterMark) {
654+
doRead = true;
655+
}
656+
657+
// However, if we've ended, then there's no point, if we're already
658+
// reading, then it's unnecessary, if we're constructing we have to wait,
659+
// and if we're destroyed or errored, then it's not allowed,
660+
if ((state[kState] & (kReading | kEnded | kDestroyed | kErrored | kConstructed)) !== kConstructed) {
661+
doRead = false;
662+
} else if (doRead) {
663+
state[kState] |= kReading | kSync;
664+
// If the length is currently zero, then we *need* a readable event.
665+
if (state.length === 0)
666+
state[kState] |= kNeedReadable;
667+
668+
// Call internal read method
669+
try {
670+
this._read(state.highWaterMark);
671+
} catch (err) {
672+
errorOrDestroy(this, err);
673+
}
674+
state[kState] &= ~kSync;
675+
}
676+
677+
const ret = state.buffer.splice(state.bufferIndex);
678+
state.bufferIndex = 0;
679+
state.length = 0;
680+
681+
if (ret.length === 0) {
682+
state[kState] |= state.length <= state.highWaterMark ? kNeedReadable : 0;
683+
} else if ((state[kState] & kMultiAwaitDrain) !== 0) {
684+
state.awaitDrainWriters.clear();
685+
} else {
686+
state.awaitDrainWriters = null;
687+
}
688+
689+
if (state.length === 0) {
690+
// If we have nothing in the buffer, then we want to know
691+
// as soon as we *do* get something into the buffer.
692+
if ((state[kState] & kEnded) === 0)
693+
state[kState] |= kNeedReadable;
694+
695+
// If we tried to read() past the EOF, then emit end on the next tick.
696+
if ((state[kState] & kEnded) !== 0)
697+
endReadable(this);
698+
}
699+
700+
if (ret !== null && (state[kState] & (kErrorEmitted | kCloseEmitted)) === 0) {
701+
state[kState] |= kDataEmitted;
702+
for (let n = 0; n < ret.length; n++) {
703+
this.emit('data', ret[n]);
704+
}
705+
}
706+
707+
return ret;
708+
};
709+
644710
// You can override either this method, or the async _read(n) below.
645711
Readable.prototype.read = function(n) {
646712
debug('read', n);

0 commit comments

Comments
 (0)