Skip to content

Commit

Permalink
re-use IteratorResult objects when possible in Iterator.concat
Browse files Browse the repository at this point in the history
  • Loading branch information
zloirock committed Dec 29, 2024
1 parent 57ffe82 commit 8de4f9a
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 8 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
- Added built-ins:
- `Error.isError`
- We have no bulletproof way to polyfill this method / check if the object is an error, so it's an enough naive implementation that is marked as `.sham`
- Added [`Iterator` sequencing stage 2.7 proposal](https://github.com/tc39/proposal-iterator-sequencing):
- Re-use `IteratorResult` objects when possible, [tc39/proposal-iterator-sequencing/17](https://github.com/tc39/proposal-iterator-sequencing/issues/17), [tc39/proposal-iterator-sequencing/18](https://github.com/tc39/proposal-iterator-sequencing/pull/18), December 2024 TC39 meeting
- Optimized `DataView.prototype.{ getFloat16, setFloat16 }` performance, [#1379](https://github.com/zloirock/core-js/pull/1379), thanks [**@LeviPesin**](https://github.com/LeviPesin)
- Dropped unneeded feature detection of non-standard `%TypedArray%.prototype.toSpliced`
- Dropped possible re-usage of some non-standard / early stage features (like `Math.scale`) available on global
Expand Down
10 changes: 6 additions & 4 deletions packages/core-js/internals/iterator-create-proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ var createIteratorProxyPrototype = function (IS_ITERATOR) {
next: function next() {
var state = getInternalState(this);
// for simplification:
// for `%WrapForValidIteratorPrototype%.next` our `nextHandler` returns `IterResultObject`
// for `%WrapForValidIteratorPrototype%.next` or with `state.returnHandlerResult` our `nextHandler` returns `IterResultObject`
// for `%IteratorHelperPrototype%.next` - just a value
if (IS_ITERATOR) return state.nextHandler();
if (state.done) return createIterResultObject(undefined, true);
try {
var result = state.done ? undefined : state.nextHandler();
return createIterResultObject(result, state.done);
var result = state.nextHandler();
return state.returnHandlerResult ? result : createIterResultObject(result, state.done);
} catch (error) {
state.done = true;
throw error;
Expand Down Expand Up @@ -57,13 +58,14 @@ var IteratorHelperPrototype = createIteratorProxyPrototype(false);

createNonEnumerableProperty(IteratorHelperPrototype, TO_STRING_TAG, 'Iterator Helper');

module.exports = function (nextHandler, IS_ITERATOR) {
module.exports = function (nextHandler, IS_ITERATOR, RETURN_HANDLER_RESULT) {
var IteratorProxy = function Iterator(record, state) {
if (state) {
state.iterator = record.iterator;
state.next = record.next;
} else state = record;
state.type = IS_ITERATOR ? WRAP_FOR_VALID_ITERATOR : ITERATOR_HELPER;
state.returnHandlerResult = !!RETURN_HANDLER_RESULT;
state.nextHandler = nextHandler;
state.counter = 0;
state.done = false;
Expand Down
7 changes: 4 additions & 3 deletions packages/core-js/modules/esnext.iterator.concat.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ var aCallable = require('../internals/a-callable');
var anObject = require('../internals/an-object');
var getIteratorMethod = require('../internals/get-iterator-method');
var createIteratorProxy = require('../internals/iterator-create-proxy');
var createIterResultObject = require('../internals/create-iter-result-object');

var $Array = Array;

Expand All @@ -16,7 +17,7 @@ var IteratorProxy = createIteratorProxy(function () {
var iterables = this.iterables;
if (iterableIndex >= iterables.length) {
this.done = true;
return;
return createIterResultObject(undefined, true);
}
var entry = iterables[iterableIndex];
this.iterables[iterableIndex] = null;
Expand All @@ -29,9 +30,9 @@ var IteratorProxy = createIteratorProxy(function () {
this.next = null;
continue;
}
return result.value;
return result;
}
});
}, false, true);

// `Iterator.concat` method
// https://github.com/tc39/proposal-iterator-sequencing
Expand Down
21 changes: 21 additions & 0 deletions tests/unit-global/esnext.iterator.concat.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,27 @@ QUnit.test('Iterator.concat', assert => {
assert.deepEqual(iterator.return(), { done: true, value: undefined }, '.return with active inner iterator with return result');
assert.true(called, 'inner .return called');

// https://github.com/tc39/proposal-iterator-sequencing/issues/17
const oldIterResult = {
done: false,
value: 123,
};
const testIterator = {
next() {
return oldIterResult;
},
};
const iterable = {
[Symbol.iterator]() {
return testIterator;
},
};
iterator = concat(iterable);
const iterResult = iterator.next();
assert.same(iterResult.done, false);
assert.same(iterResult.value, 123);
assert.same(iterResult, oldIterResult);

assert.throws(() => concat(createIterator([1, 2, 3])), TypeError, 'non-iterable iterator #1');
assert.throws(() => concat([], createIterator([1, 2, 3])), TypeError, 'non-iterable iterator #2');
assert.throws(() => concat(''), TypeError, 'iterable non-object argument #1');
Expand Down
24 changes: 23 additions & 1 deletion tests/unit-pure/esnext.iterator.concat.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { createIterable, createIterator } from '../helpers/helpers.js';

import concat from 'core-js-pure/full/iterator/concat';
import Iterator from 'core-js-pure/full/iterator';
import Iterator from 'core-js-pure/es/iterator';
import Symbol from 'core-js-pure/es/symbol';
import from from 'core-js-pure/es/array/from';

QUnit.test('Iterator.concat', assert => {
Expand Down Expand Up @@ -60,6 +61,27 @@ QUnit.test('Iterator.concat', assert => {
assert.deepEqual(iterator.return(), { done: true, value: undefined }, '.return with active inner iterator with return result');
assert.true(called, 'inner .return called');

// https://github.com/tc39/proposal-iterator-sequencing/issues/17
const oldIterResult = {
done: false,
value: 123,
};
const testIterator = {
next() {
return oldIterResult;
},
};
const iterable = {
[Symbol.iterator]() {
return testIterator;
},
};
iterator = concat(iterable);
const iterResult = iterator.next();
assert.same(iterResult.done, false);
assert.same(iterResult.value, 123);
assert.same(iterResult, oldIterResult);

assert.throws(() => concat(createIterator([1, 2, 3])), TypeError, 'non-iterable iterator #1');
assert.throws(() => concat([], createIterator([1, 2, 3])), TypeError, 'non-iterable iterator #2');
assert.throws(() => concat(''), TypeError, 'iterable non-object argument #1');
Expand Down

0 comments on commit 8de4f9a

Please sign in to comment.