Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

buffer: implement iterable interface #525

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions benchmark/buffers/buffer-iterate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
var SlowBuffer = require('buffer').SlowBuffer;
var common = require('../common.js');
var assert = require('assert');

var bench = common.createBenchmark(main, {
size: [16, 512, 1024, 4096, 16386],
type: ['fast', 'slow'],
method: ['for', 'forOf', 'iterator'],
n: [1e3]
});

var methods = {
'for': benchFor,
'forOf': benchForOf,
'iterator': benchIterator
};

function main(conf) {
var len = +conf.size;
var clazz = conf.type === 'fast' ? Buffer : SlowBuffer;
var buffer = new clazz(len);
buffer.fill(0);

methods[conf.method](buffer, conf.n);
}


function benchFor(buffer, n) {
bench.start();

for (var k = 0; k < n; k++)
for (var i = 0; i < buffer.length; i++)
assert(buffer[i] === 0);

bench.end(n);
}

function benchForOf(buffer, n) {
bench.start();

for (var k = 0; k < n; k++)
for (var b of buffer)
assert(b === 0);

bench.end(n);
}

function benchIterator(buffer, n) {
bench.start();

for (var k = 0; k < n; k++) {
var iter = buffer[Symbol.iterator]();
var cur = iter.next();

while (!cur.done) {
assert(cur.value === 0);
cur = iter.next();
}

}

bench.end(n);
}
29 changes: 29 additions & 0 deletions doc/api/buffer.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,19 @@ buffer.
var b = new Buffer(50);
b.fill("h");

### buffer.values()

Creates iterator for buffer values (bytes). This function is called automatically
when `buffer` is used in a `for..of` statement.

### buffer.keys()

Creates iterator for buffer keys (indices).

### buffer.entries()

Creates iterator for `[index, byte]` arrays.

## buffer.INSPECT_MAX_BYTES

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

## ES6 iteration

Buffers can be iterated over using `for..of` syntax:

var buf = new Buffer([1, 2, 3]);

for (var b of buf)
console.log(b)

// 1
// 2
// 3

Additionally, `buffer.values()`, `buffer.keys()` and `buffer.entries()`
methods can be used to create iterators.

## Class: SlowBuffer

Returns an un-pooled `Buffer`.
Expand Down
77 changes: 77 additions & 0 deletions lib/buffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -930,3 +930,80 @@ Buffer.prototype.writeDoubleBE = function writeDoubleBE(val, offset, noAssert) {
internal.writeDoubleBE(this, val, offset);
return offset + 8;
};

// ES6 iterator

var ITERATOR_KIND_KEYS = 1;
var ITERATOR_KIND_ENTRIES = 3;

function BufferIteratorResult(value, done) {
this.value = value;
this.done = done;
}

var resultCache = new Array(256);

for (var i = 0; i < 256; i++)
resultCache[i] = Object.freeze(new BufferIteratorResult(i, false));

var finalResult = Object.freeze(new BufferIteratorResult(undefined, true));

function BufferIterator(buffer, kind) {
this._buffer = buffer;
this._kind = kind;
this._index = 0;
}

BufferIterator.prototype.next = function() {
var buffer = this._buffer;
var kind = this._kind;
var index = this._index;

if (index >= buffer.length)
return finalResult;

this._index++;

if (kind === ITERATOR_KIND_ENTRIES)
return new BufferIteratorResult([index, buffer[index]], false);

return new BufferIteratorResult(index, false);
};

function BufferValueIterator(buffer) {
BufferIterator.call(this, buffer, null);
}

BufferValueIterator.prototype.next = function() {
var buffer = this._buffer;
var index = this._index;

if (index >= buffer.length)
return finalResult;

this._index++;

return resultCache[buffer[index]];
};


BufferIterator.prototype[Symbol.iterator] = function() {
return this;
};

BufferValueIterator.prototype[Symbol.iterator] =
BufferIterator.prototype[Symbol.iterator];

Buffer.prototype.keys = function() {
return new BufferIterator(this, ITERATOR_KIND_KEYS);
};

Buffer.prototype.entries = function() {
return new BufferIterator(this, ITERATOR_KIND_ENTRIES);
};

Buffer.prototype.values = function() {
return new BufferValueIterator(this);
};

Buffer.prototype[Symbol.iterator] = Buffer.prototype.values;
61 changes: 61 additions & 0 deletions test/parallel/test-buffer-iterator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
var common = require('../common');
var assert = require('assert');

var buffer = new Buffer([1, 2, 3, 4, 5]);
var arr;
var b;

// buffers should be iterable

arr = [];

for (b of buffer)
arr.push(b);

assert.deepEqual(arr, [1, 2, 3, 4, 5]);


// buffer iterators should be iterable

arr = [];

for (b of buffer[Symbol.iterator]())
arr.push(b);

assert.deepEqual(arr, [1, 2, 3, 4, 5]);


// buffer#values() should return iterator for values

arr = [];

for (b of buffer.values())
arr.push(b);

assert.deepEqual(arr, [1, 2, 3, 4, 5]);


// buffer#keys() should return iterator for keys

arr = [];

for (b of buffer.keys())
arr.push(b);

assert.deepEqual(arr, [0, 1, 2, 3, 4]);


// buffer#entries() should return iterator for entries

arr = [];

for (var b of buffer.entries())
arr.push(b);

assert.deepEqual(arr, [
[0, 1],
[1, 2],
[2, 3],
[3, 4],
[4, 5]
]);