Files
scriptc/tests/corpus/checked-iterator-consumption.js
Chris Tate a4fd6ed2c0 Optimize structured-data consumption and storage
- Consume native iterator values directly while preserving custom iteration and cleanup behavior.
- Reuse bounded object-key storage and simplify text splitting and empty-string checks.
- Cover iterator reentrancy, property ownership, and storage boundaries.
2026-10-05 14:03:40 -05:00

104 lines
3.8 KiB
JavaScript

const consume = {
collect(source, visit) {
const values = [];
for (const value of source) {
values.push(value);
visit(value);
}
return values;
},
mapped(source, visit) { return Array.from(source, visit); }
};
const parsed = JSON.parse('[null,false,true,0,"",{"name":"kept"},[2]]');
const copy = consume.collect(parsed, () => {});
parsed[5].name = "changed";
console.log(JSON.stringify(copy), copy[5] === parsed[5]);
console.log(JSON.stringify(consume.mapped(parsed, (value, index) => [index, value])));
const live = JSON.parse('[1]');
console.log(JSON.stringify(consume.collect(live, value => {
if (value === 1) live.push(undefined, 3);
})));
console.log(JSON.stringify(consume.collect("a😀é", () => {})));
console.log(JSON.stringify(consume.collect(new Uint8Array([0, 255]), () => {})));
const map = new Map([["a", 1], ["b", 2]]);
console.log(JSON.stringify(consume.collect(map.values(), value => {
if (value === 1) { map.delete("b"); map.set("c", 3); }
})));
const set = new Set([1, 2]);
console.log(JSON.stringify(consume.mapped(set.values(), value => {
if (value === 1) { set.delete(2); set.add(3); }
return value * 2;
})));
// Explicit next() results stay independent objects even when the same
// iterator is also consumed by a loop.
const publicCursor = JSON.parse('[4,5,6]').values();
const first = publicCursor.next();
const second = publicCursor.next();
first.value = 99;
first.done = true;
console.log(first === second, second.value, second.done);
console.log(JSON.stringify(consume.collect(publicCursor, () => {})));
console.log(publicCursor.next().done, publicCursor.next().done);
// A custom factory and a captured custom next method keep their effects.
const custom = JSON.parse('[8,9]');
custom[Symbol.iterator] = function () {
let index = 0;
return {
get next() {
console.log("captured");
return function () {
const value = index++;
return {
get done() { console.log("done", value); return value === 2; },
get value() { console.log("value", value); return value + 10; }
};
};
}
};
};
console.log(JSON.stringify(consume.collect(custom, () => {})));
console.log(JSON.stringify(consume.mapped(custom, value => value)));
// An inherited getter can exhaust the iterator while its outer step is
// still reading a value. That outer value must survive nested consumption.
function nestedConsumption(mapped) {
let source = new Array(2);
source[1] = 2;
const prototype = Object.create(Array.prototype);
const cursor = source.values();
Object.defineProperty(prototype, "0", { get() {
console.log("nested", JSON.stringify(consume.collect(cursor, () => {})));
return 10;
} });
Object.setPrototypeOf(source, prototype);
source = null;
const result = mapped ? consume.mapped(cursor, value => value) : consume.collect(cursor, () => {});
console.log("outer", JSON.stringify(result), cursor.next().done);
}
nestedConsumption(false);
nestedConsumption(true);
// A failed value read advances the cursor without exhausting it.
const failing = new Array(2);
failing[1] = 4;
const failingPrototype = Object.create(Array.prototype);
Object.defineProperty(failingPrototype, "0", { get() { throw new Error("indexed read"); } });
Object.setPrototypeOf(failing, failingPrototype);
const failingCursor = failing.values();
try { consume.collect(failingCursor, () => {}); } catch (error) { console.log(error.message); }
console.log(JSON.stringify(consume.collect(failingCursor, () => {})));
const closing = JSON.parse('[1,2]').values();
for (const value of closing) { console.log(value); break; }
console.log(closing.next().value);
const wrapped = {
[Symbol.iterator]() { return this; },
next() { return { value: 3, done: false }; },
return() { console.log("closed"); return { value: undefined, done: true }; }
};
for (const value of wrapped) { console.log(value); break; }