Skip to content

Commit 45d8d9f

Browse files
committed
buffer: implement iterable interface
This makes possible to use `for..of` loop with buffers. Also related `keys`, `values` and `entries` methods are added for feature parity with `Uint8Array`. PR-URL: #525 Reviewed-By: Ben Noordhuis <[email protected]>
1 parent 3cbb5cd commit 45d8d9f

File tree

4 files changed

+230
-0
lines changed

4 files changed

+230
-0
lines changed

benchmark/buffers/buffer-iterate.js

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
var SlowBuffer = require('buffer').SlowBuffer;
2+
var common = require('../common.js');
3+
var assert = require('assert');
4+
5+
var bench = common.createBenchmark(main, {
6+
size: [16, 512, 1024, 4096, 16386],
7+
type: ['fast', 'slow'],
8+
method: ['for', 'forOf', 'iterator'],
9+
n: [1e3]
10+
});
11+
12+
var methods = {
13+
'for': benchFor,
14+
'forOf': benchForOf,
15+
'iterator': benchIterator
16+
};
17+
18+
function main(conf) {
19+
var len = +conf.size;
20+
var clazz = conf.type === 'fast' ? Buffer : SlowBuffer;
21+
var buffer = new clazz(len);
22+
buffer.fill(0);
23+
24+
methods[conf.method](buffer, conf.n);
25+
}
26+
27+
28+
function benchFor(buffer, n) {
29+
bench.start();
30+
31+
for (var k = 0; k < n; k++)
32+
for (var i = 0; i < buffer.length; i++)
33+
assert(buffer[i] === 0);
34+
35+
bench.end(n);
36+
}
37+
38+
function benchForOf(buffer, n) {
39+
bench.start();
40+
41+
for (var k = 0; k < n; k++)
42+
for (var b of buffer)
43+
assert(b === 0);
44+
45+
bench.end(n);
46+
}
47+
48+
function benchIterator(buffer, n) {
49+
bench.start();
50+
51+
for (var k = 0; k < n; k++) {
52+
var iter = buffer[Symbol.iterator]();
53+
var cur = iter.next();
54+
55+
while (!cur.done) {
56+
assert(cur.value === 0);
57+
cur = iter.next();
58+
}
59+
60+
}
61+
62+
bench.end(n);
63+
}

doc/api/buffer.markdown

+29
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,19 @@ buffer.
797797
var b = new Buffer(50);
798798
b.fill("h");
799799

800+
### buffer.values()
801+
802+
Creates iterator for buffer values (bytes). This function is called automatically
803+
when `buffer` is used in a `for..of` statement.
804+
805+
### buffer.keys()
806+
807+
Creates iterator for buffer keys (indices).
808+
809+
### buffer.entries()
810+
811+
Creates iterator for `[index, byte]` arrays.
812+
800813
## buffer.INSPECT_MAX_BYTES
801814

802815
* Number, Default: 50
@@ -807,6 +820,22 @@ be overridden by user modules.
807820
Note that this is a property on the buffer module returned by
808821
`require('buffer')`, not on the Buffer global, or a buffer instance.
809822

823+
## ES6 iteration
824+
825+
Buffers can be iterated over using `for..of` syntax:
826+
827+
var buf = new Buffer([1, 2, 3]);
828+
829+
for (var b of buf)
830+
console.log(b)
831+
832+
// 1
833+
// 2
834+
// 3
835+
836+
Additionally, `buffer.values()`, `buffer.keys()` and `buffer.entries()`
837+
methods can be used to create iterators.
838+
810839
## Class: SlowBuffer
811840

812841
Returns an un-pooled `Buffer`.

lib/buffer.js

+77
Original file line numberDiff line numberDiff line change
@@ -930,3 +930,80 @@ Buffer.prototype.writeDoubleBE = function writeDoubleBE(val, offset, noAssert) {
930930
internal.writeDoubleBE(this, val, offset);
931931
return offset + 8;
932932
};
933+
934+
// ES6 iterator
935+
936+
var ITERATOR_KIND_KEYS = 1;
937+
var ITERATOR_KIND_ENTRIES = 3;
938+
939+
function BufferIteratorResult(value, done) {
940+
this.value = value;
941+
this.done = done;
942+
}
943+
944+
var resultCache = new Array(256);
945+
946+
for (var i = 0; i < 256; i++)
947+
resultCache[i] = Object.freeze(new BufferIteratorResult(i, false));
948+
949+
var finalResult = Object.freeze(new BufferIteratorResult(undefined, true));
950+
951+
function BufferIterator(buffer, kind) {
952+
this._buffer = buffer;
953+
this._kind = kind;
954+
this._index = 0;
955+
}
956+
957+
BufferIterator.prototype.next = function() {
958+
var buffer = this._buffer;
959+
var kind = this._kind;
960+
var index = this._index;
961+
962+
if (index >= buffer.length)
963+
return finalResult;
964+
965+
this._index++;
966+
967+
if (kind === ITERATOR_KIND_ENTRIES)
968+
return new BufferIteratorResult([index, buffer[index]], false);
969+
970+
return new BufferIteratorResult(index, false);
971+
};
972+
973+
function BufferValueIterator(buffer) {
974+
BufferIterator.call(this, buffer, null);
975+
}
976+
977+
BufferValueIterator.prototype.next = function() {
978+
var buffer = this._buffer;
979+
var index = this._index;
980+
981+
if (index >= buffer.length)
982+
return finalResult;
983+
984+
this._index++;
985+
986+
return resultCache[buffer[index]];
987+
};
988+
989+
990+
BufferIterator.prototype[Symbol.iterator] = function() {
991+
return this;
992+
};
993+
994+
BufferValueIterator.prototype[Symbol.iterator] =
995+
BufferIterator.prototype[Symbol.iterator];
996+
997+
Buffer.prototype.keys = function() {
998+
return new BufferIterator(this, ITERATOR_KIND_KEYS);
999+
};
1000+
1001+
Buffer.prototype.entries = function() {
1002+
return new BufferIterator(this, ITERATOR_KIND_ENTRIES);
1003+
};
1004+
1005+
Buffer.prototype.values = function() {
1006+
return new BufferValueIterator(this);
1007+
};
1008+
1009+
Buffer.prototype[Symbol.iterator] = Buffer.prototype.values;

test/parallel/test-buffer-iterator.js

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
var common = require('../common');
2+
var assert = require('assert');
3+
4+
var buffer = new Buffer([1, 2, 3, 4, 5]);
5+
var arr;
6+
var b;
7+
8+
// buffers should be iterable
9+
10+
arr = [];
11+
12+
for (b of buffer)
13+
arr.push(b);
14+
15+
assert.deepEqual(arr, [1, 2, 3, 4, 5]);
16+
17+
18+
// buffer iterators should be iterable
19+
20+
arr = [];
21+
22+
for (b of buffer[Symbol.iterator]())
23+
arr.push(b);
24+
25+
assert.deepEqual(arr, [1, 2, 3, 4, 5]);
26+
27+
28+
// buffer#values() should return iterator for values
29+
30+
arr = [];
31+
32+
for (b of buffer.values())
33+
arr.push(b);
34+
35+
assert.deepEqual(arr, [1, 2, 3, 4, 5]);
36+
37+
38+
// buffer#keys() should return iterator for keys
39+
40+
arr = [];
41+
42+
for (b of buffer.keys())
43+
arr.push(b);
44+
45+
assert.deepEqual(arr, [0, 1, 2, 3, 4]);
46+
47+
48+
// buffer#entries() should return iterator for entries
49+
50+
arr = [];
51+
52+
for (var b of buffer.entries())
53+
arr.push(b);
54+
55+
assert.deepEqual(arr, [
56+
[0, 1],
57+
[1, 2],
58+
[2, 3],
59+
[3, 4],
60+
[4, 5]
61+
]);

0 commit comments

Comments
 (0)