diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /js/src/tests/test262/staging/JSON | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/tests/test262/staging/JSON')
4 files changed, 718 insertions, 0 deletions
diff --git a/js/src/tests/test262/staging/JSON/browser.js b/js/src/tests/test262/staging/JSON/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/staging/JSON/browser.js diff --git a/js/src/tests/test262/staging/JSON/json-parse-with-source-snapshot.js b/js/src/tests/test262/staging/JSON/json-parse-with-source-snapshot.js new file mode 100644 index 0000000000..45465333d4 --- /dev/null +++ b/js/src/tests/test262/staging/JSON/json-parse-with-source-snapshot.js @@ -0,0 +1,97 @@ +// |reftest| skip -- json-parse-with-source is not supported +// Copyright (C) 2023 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +description: V8 mjsunit test for JSON.parse with source snapshotting +includes: [deepEqual.js] +features: [json-parse-with-source] +---*/ + +const replacements = [42, + ['foo'], + {foo:'bar'}, + 'foo']; + +function TestArrayForwardModify(replacement) { + let alreadyReplaced = false; + let expectedKeys = ['0','1','']; + // lol who designed reviver semantics + if (typeof replacement === 'object') { + expectedKeys.splice(1, 0, ...Object.keys(replacement)); + } + const o = JSON.parse('[1, 2]', function (k, v, { source }) { + assert.sameValue(expectedKeys.shift(), k); + if (k === '0') { + if (!alreadyReplaced) { + this[1] = replacement; + alreadyReplaced = true; + } + } else if (k !== '') { + assert.sameValue(undefined, source); + } + return this[k]; + }); + assert.sameValue(0, expectedKeys.length); + assert.deepEqual([1, replacement], o); +} + +function TestObjectForwardModify(replacement) { + let alreadyReplaced = false; + let expectedKeys = ['p','q','']; + if (typeof replacement === 'object') { + expectedKeys.splice(1, 0, ...Object.keys(replacement)); + } + const o = JSON.parse('{"p":1, "q":2}', function (k, v, { source }) { + assert.sameValue(expectedKeys.shift(), k); + if (k === 'p') { + if (!alreadyReplaced) { + this.q = replacement; + alreadyReplaced = true; + } + } else if (k !== '') { + assert.sameValue(undefined, source); + } + return this[k]; + }); + assert.sameValue(0, expectedKeys.length); + assert.deepEqual({p:1, q:replacement}, o); +} + +for (const r of replacements) { + TestArrayForwardModify(r); + TestObjectForwardModify(r); +} + +(function TestArrayAppend() { + let log = []; + const o = JSON.parse('[1,[]]', function (k, v, { source }) { + log.push([k, v, source]); + if (v === 1) { + this[1].push('barf'); + } + return this[k]; + }); + assert.deepEqual([['0', 1, '1'], + ['0', 'barf', undefined], + ['1', ['barf'], undefined], + ['', [1, ['barf']], undefined]], + log); +})(); + +(function TestObjectAddProperty() { + let log = []; + const o = JSON.parse('{"p":1,"q":{}}', function (k, v, { source }) { + log.push([k, v, source]); + if (v === 1) { + this.q.added = 'barf'; + } + return this[k]; + }); + assert.deepEqual([['p', 1, '1'], + ['added', 'barf', undefined], + ['q', {added:'barf'}, undefined], + ['', {p:1, q:{added:'barf'}}, undefined]], + log); +})(); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/staging/JSON/json-parse-with-source.js b/js/src/tests/test262/staging/JSON/json-parse-with-source.js new file mode 100644 index 0000000000..f8674511ef --- /dev/null +++ b/js/src/tests/test262/staging/JSON/json-parse-with-source.js @@ -0,0 +1,292 @@ +// |reftest| skip -- json-parse-with-source is not supported +// Copyright (C) 2023 the V8 project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +description: V8 mjsunit test for JSON.parse with source +includes: [deepEqual.js] +features: [json-parse-with-source] +---*/ + +(function TestBigInt() { + const tooBigForNumber = BigInt(Number.MAX_SAFE_INTEGER) + 2n; + const intToBigInt = (key, val, { source }) => + typeof val === 'number' && val % 1 === 0 ? BigInt(source) : val; + const roundTripped = JSON.parse(String(tooBigForNumber), intToBigInt); + assert.sameValue(tooBigForNumber, roundTripped); + + const bigIntToRawJSON = (key, val) => + typeof val === 'bigint' ? JSON.rawJSON(val) : val; + const embedded = JSON.stringify({ tooBigForNumber }, bigIntToRawJSON); + assert.sameValue('{"tooBigForNumber":9007199254740993}', embedded); +})(); + +function GenerateParseReviverFunction(texts) { + let i = 0; + return function (key, value, context) { + assert(typeof context === 'object'); + assert.sameValue(Object.prototype, Object.getPrototypeOf(context)); + // The json value is a primitive value, it's context only has a source property. + if (texts[i] !== undefined) { + const descriptor = Object.getOwnPropertyDescriptor(context, 'source'); + assert(descriptor.configurable); + assert(descriptor.enumerable); + assert(descriptor.writable); + assert.sameValue(undefined, descriptor.get); + assert.sameValue(undefined, descriptor.set); + assert.sameValue(texts[i++], descriptor.value); + + assert.deepEqual(['source'], Object.getOwnPropertyNames(context)); + assert.deepEqual([], Object.getOwnPropertySymbols(context)); + } else { + // The json value is JSArray or JSObject, it's context has no property. + assert(!Object.hasOwn(context, 'source')); + assert.deepEqual([], Object.getOwnPropertyNames(context)); + assert.deepEqual([], Object.getOwnPropertySymbols(context)); + i++; + } + return value; + }; +} + +(function TestNumber() { + assert.sameValue(1, JSON.parse('1', GenerateParseReviverFunction(['1']))); + assert.sameValue(1.1, JSON.parse('1.1', GenerateParseReviverFunction(['1.1']))); + assert.sameValue(-1, JSON.parse('-1', GenerateParseReviverFunction(['-1']))); + assert.sameValue( + -1.1, + JSON.parse('-1.1', GenerateParseReviverFunction(['-1.1'])) + ); + assert.sameValue( + 11, + JSON.parse('1.1e1', GenerateParseReviverFunction(['1.1e1'])) + ); + assert.sameValue( + 11, + JSON.parse('1.1e+1', GenerateParseReviverFunction(['1.1e+1'])) + ); + assert.sameValue( + 0.11, + JSON.parse('1.1e-1', GenerateParseReviverFunction(['1.1e-1'])) + ); + assert.sameValue( + 11, + JSON.parse('1.1E1', GenerateParseReviverFunction(['1.1E1'])) + ); + assert.sameValue( + 11, + JSON.parse('1.1E+1', GenerateParseReviverFunction(['1.1E+1'])) + ); + assert.sameValue( + 0.11, + JSON.parse('1.1E-1', GenerateParseReviverFunction(['1.1E-1'])) + ); + + assert.sameValue('1', JSON.stringify(JSON.rawJSON(1))); + assert.sameValue('1.1', JSON.stringify(JSON.rawJSON(1.1))); + assert.sameValue('-1', JSON.stringify(JSON.rawJSON(-1))); + assert.sameValue('-1.1', JSON.stringify(JSON.rawJSON(-1.1))); + assert.sameValue('11', JSON.stringify(JSON.rawJSON(1.1e1))); + assert.sameValue('0.11', JSON.stringify(JSON.rawJSON(1.1e-1))); +})(); + +(function TestBasic() { + assert.sameValue( + null, + JSON.parse('null', GenerateParseReviverFunction(['null'])) + ); + assert.sameValue( + true, + JSON.parse('true', GenerateParseReviverFunction(['true'])) + ); + assert.sameValue( + false, + JSON.parse('false', GenerateParseReviverFunction(['false'])) + ); + assert.sameValue( + 'foo', + JSON.parse('"foo"', GenerateParseReviverFunction(['"foo"'])) + ); + + assert.sameValue('null', JSON.stringify(JSON.rawJSON(null))); + assert.sameValue('true', JSON.stringify(JSON.rawJSON(true))); + assert.sameValue('false', JSON.stringify(JSON.rawJSON(false))); + assert.sameValue('"foo"', JSON.stringify(JSON.rawJSON('"foo"'))); +})(); + +(function TestObject() { + assert.deepEqual( + {}, + JSON.parse('{}', GenerateParseReviverFunction([])) + ); + assert.deepEqual( + { 42: 37 }, + JSON.parse('{"42":37}', GenerateParseReviverFunction(['37'])) + ); + assert.deepEqual( + { x: 1, y: 2 }, + JSON.parse('{"x": 1, "y": 2}', GenerateParseReviverFunction(['1', '2'])) + ); + // undefined means the json value is JSObject or JSArray and the passed + // context to the reviver function has no source property. + assert.deepEqual( + { x: [1, 2], y: [2, 3] }, + JSON.parse( + '{"x": [1,2], "y": [2,3]}', + GenerateParseReviverFunction(['1', '2', undefined, '2', '3', undefined]) + ) + ); + assert.deepEqual( + { x: { x: 1, y: 2 } }, + JSON.parse( + '{"x": {"x": 1, "y": 2}}', + GenerateParseReviverFunction(['1', '2', undefined, undefined]) + ) + ); + + assert.sameValue('{"42":37}', JSON.stringify({ 42: JSON.rawJSON(37) })); + assert.sameValue( + '{"x":1,"y":2}', + JSON.stringify({ x: JSON.rawJSON(1), y: JSON.rawJSON(2) }) + ); + assert.sameValue( + '{"x":{"x":1,"y":2}}', + JSON.stringify({ x: { x: JSON.rawJSON(1), y: JSON.rawJSON(2) } }) + ); +})(); + +(function TestArray() { + assert.deepEqual([1], JSON.parse('[1.0]', GenerateParseReviverFunction(['1.0']))); + assert.deepEqual( + [1.1], + JSON.parse('[1.1]', GenerateParseReviverFunction(['1.1'])) + ); + assert.deepEqual([], JSON.parse('[]', GenerateParseReviverFunction([]))); + assert.deepEqual( + [1, '2', true, null, { x: 1, y: 1 }], + JSON.parse( + '[1, "2", true, null, {"x": 1, "y": 1}]', + GenerateParseReviverFunction(['1', '"2"', 'true', 'null', '1', '1']) + ) + ); + + assert.sameValue('[1,1.1]', JSON.stringify([JSON.rawJSON(1), JSON.rawJSON(1.1)])); + assert.sameValue( + '["1",true,null,false]', + JSON.stringify([ + JSON.rawJSON('"1"'), + JSON.rawJSON(true), + JSON.rawJSON(null), + JSON.rawJSON(false), + ]) + ); + assert.sameValue( + '[{"x":1,"y":1}]', + JSON.stringify([{ x: JSON.rawJSON(1), y: JSON.rawJSON(1) }]) + ); +})(); + +function assertIsRawJson(rawJson, expectedRawJsonValue) { + assert.sameValue(null, Object.getPrototypeOf(rawJson)); + assert(Object.hasOwn(rawJson, 'rawJSON')); + assert.deepEqual(['rawJSON'], Object.getOwnPropertyNames(rawJson)); + assert.deepEqual([], Object.getOwnPropertySymbols(rawJson)); + assert.sameValue(expectedRawJsonValue, rawJson.rawJSON); +} + +(function TestRawJson() { + assertIsRawJson(JSON.rawJSON(1), '1'); + assertIsRawJson(JSON.rawJSON(null), 'null'); + assertIsRawJson(JSON.rawJSON(true), 'true'); + assertIsRawJson(JSON.rawJSON(false), 'false'); + assertIsRawJson(JSON.rawJSON('"foo"'), '"foo"'); + + assert.throws(TypeError, () => { + JSON.rawJSON(Symbol('123')); + }); + + assert.throws(SyntaxError, () => { + JSON.rawJSON(undefined); + }); + + assert.throws(SyntaxError, () => { + JSON.rawJSON({}); + }); + + assert.throws(SyntaxError, () => { + JSON.rawJSON([]); + }); + + const ILLEGAL_END_CHARS = ['\n', '\t', '\r', ' ']; + for (const char of ILLEGAL_END_CHARS) { + assert.throws(SyntaxError, () => { + JSON.rawJSON(`${char}123`); + }); + assert.throws(SyntaxError, () => { + JSON.rawJSON(`123${char}`); + }); + } + + assert.throws(SyntaxError, () => { + JSON.rawJSON(''); + }); + + const values = [1, 1.1, null, false, true, '123']; + for (const value of values) { + assert(!JSON.isRawJSON(value)); + assert(JSON.isRawJSON(JSON.rawJSON(value))); + } + assert(!JSON.isRawJSON(undefined)); + assert(!JSON.isRawJSON(Symbol('123'))); + assert(!JSON.isRawJSON([])); + assert(!JSON.isRawJSON({ rawJSON: '123' })); +})(); + +(function TestReviverModifyJsonValue() { + { + let reviverCallIndex = 0; + const expectedKeys = ['a', 'b', 'c', '']; + const reviver = function(key, value, {source}) { + assert.sameValue(expectedKeys[reviverCallIndex++], key); + if (key == 'a') { + this.b = 2; + assert.sameValue('0', source); + } else if (key == 'b') { + this.c = 3; + assert.sameValue(2, value); + assert.sameValue(undefined, source); + } else if (key == 'c') { + assert.sameValue(3, value); + assert.sameValue(undefined, source); + } + return value; + } + assert.deepEqual({a: 0, b: 2, c: 3}, JSON.parse('{"a": 0, "b": 1, "c": [1, 2]}', reviver)); + } + { + let reviverCallIndex = 0; + const expectedKeys = ['0', '1', '2', '3', '']; + const reviver = function(key, value, {source}) { + assert.sameValue(expectedKeys[reviverCallIndex++], key); + if (key == '0') { + this[1] = 3; + assert.sameValue(1, value); + assert.sameValue('1', source); + } else if (key == '1') { + this[2] = 4; + assert.sameValue(3, value); + assert.sameValue(undefined, source); + } else if(key == '2') { + this[3] = 5; + assert.sameValue(4, value); + assert.sameValue(undefined, source); + } else if(key == '5'){ + assert.sameValue(5, value); + assert.sameValue(undefined, source); + } + return value; + } + assert.deepEqual([1, 3, 4, 5], JSON.parse('[1, 2, 3, {"a": 1}]', reviver)); + } +})(); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/staging/JSON/shell.js b/js/src/tests/test262/staging/JSON/shell.js new file mode 100644 index 0000000000..276ee734ff --- /dev/null +++ b/js/src/tests/test262/staging/JSON/shell.js @@ -0,0 +1,329 @@ +// GENERATED, DO NOT EDIT +// file: deepEqual.js +// Copyright 2019 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +description: > + Compare two values structurally +defines: [assert.deepEqual] +---*/ + +assert.deepEqual = function(actual, expected, message) { + var format = assert.deepEqual.format; + assert( + assert.deepEqual._compare(actual, expected), + `Expected ${format(actual)} to be structurally equal to ${format(expected)}. ${(message || '')}` + ); +}; + +assert.deepEqual.format = function(value, seen) { + switch (typeof value) { + case 'string': + return typeof JSON !== "undefined" ? JSON.stringify(value) : `"${value}"`; + case 'number': + case 'boolean': + case 'symbol': + case 'bigint': + return value.toString(); + case 'undefined': + return 'undefined'; + case 'function': + return `[Function${value.name ? `: ${value.name}` : ''}]`; + case 'object': + if (value === null) return 'null'; + if (value instanceof Date) return `Date "${value.toISOString()}"`; + if (value instanceof RegExp) return value.toString(); + if (!seen) { + seen = { + counter: 0, + map: new Map() + }; + } + + let usage = seen.map.get(value); + if (usage) { + usage.used = true; + return `[Ref: #${usage.id}]`; + } + + usage = { id: ++seen.counter, used: false }; + seen.map.set(value, usage); + + if (typeof Set !== "undefined" && value instanceof Set) { + return `Set {${Array.from(value).map(value => assert.deepEqual.format(value, seen)).join(', ')}}${usage.used ? ` as #${usage.id}` : ''}`; + } + if (typeof Map !== "undefined" && value instanceof Map) { + return `Map {${Array.from(value).map(pair => `${assert.deepEqual.format(pair[0], seen)} => ${assert.deepEqual.format(pair[1], seen)}}`).join(', ')}}${usage.used ? ` as #${usage.id}` : ''}`; + } + if (Array.isArray ? Array.isArray(value) : value instanceof Array) { + return `[${value.map(value => assert.deepEqual.format(value, seen)).join(', ')}]${usage.used ? ` as #${usage.id}` : ''}`; + } + let tag = Symbol.toStringTag in value ? value[Symbol.toStringTag] : 'Object'; + if (tag === 'Object' && Object.getPrototypeOf(value) === null) { + tag = '[Object: null prototype]'; + } + return `${tag ? `${tag} ` : ''}{ ${Object.keys(value).map(key => `${key.toString()}: ${assert.deepEqual.format(value[key], seen)}`).join(', ')} }${usage.used ? ` as #${usage.id}` : ''}`; + default: + return typeof value; + } +}; + +assert.deepEqual._compare = (function () { + var EQUAL = 1; + var NOT_EQUAL = -1; + var UNKNOWN = 0; + + function deepEqual(a, b) { + return compareEquality(a, b) === EQUAL; + } + + function compareEquality(a, b, cache) { + return compareIf(a, b, isOptional, compareOptionality) + || compareIf(a, b, isPrimitiveEquatable, comparePrimitiveEquality) + || compareIf(a, b, isObjectEquatable, compareObjectEquality, cache) + || NOT_EQUAL; + } + + function compareIf(a, b, test, compare, cache) { + return !test(a) + ? !test(b) ? UNKNOWN : NOT_EQUAL + : !test(b) ? NOT_EQUAL : cacheComparison(a, b, compare, cache); + } + + function tryCompareStrictEquality(a, b) { + return a === b ? EQUAL : UNKNOWN; + } + + function tryCompareTypeOfEquality(a, b) { + return typeof a !== typeof b ? NOT_EQUAL : UNKNOWN; + } + + function tryCompareToStringTagEquality(a, b) { + var aTag = Symbol.toStringTag in a ? a[Symbol.toStringTag] : undefined; + var bTag = Symbol.toStringTag in b ? b[Symbol.toStringTag] : undefined; + return aTag !== bTag ? NOT_EQUAL : UNKNOWN; + } + + function isOptional(value) { + return value === undefined + || value === null; + } + + function compareOptionality(a, b) { + return tryCompareStrictEquality(a, b) + || NOT_EQUAL; + } + + function isPrimitiveEquatable(value) { + switch (typeof value) { + case 'string': + case 'number': + case 'bigint': + case 'boolean': + case 'symbol': + return true; + default: + return isBoxed(value); + } + } + + function comparePrimitiveEquality(a, b) { + if (isBoxed(a)) a = a.valueOf(); + if (isBoxed(b)) b = b.valueOf(); + return tryCompareStrictEquality(a, b) + || tryCompareTypeOfEquality(a, b) + || compareIf(a, b, isNaNEquatable, compareNaNEquality) + || NOT_EQUAL; + } + + function isNaNEquatable(value) { + return typeof value === 'number'; + } + + function compareNaNEquality(a, b) { + return isNaN(a) && isNaN(b) ? EQUAL : NOT_EQUAL; + } + + function isObjectEquatable(value) { + return typeof value === 'object'; + } + + function compareObjectEquality(a, b, cache) { + if (!cache) cache = new Map(); + return getCache(cache, a, b) + || setCache(cache, a, b, EQUAL) // consider equal for now + || cacheComparison(a, b, tryCompareStrictEquality, cache) + || cacheComparison(a, b, tryCompareToStringTagEquality, cache) + || compareIf(a, b, isValueOfEquatable, compareValueOfEquality) + || compareIf(a, b, isToStringEquatable, compareToStringEquality) + || compareIf(a, b, isArrayLikeEquatable, compareArrayLikeEquality, cache) + || compareIf(a, b, isStructurallyEquatable, compareStructuralEquality, cache) + || compareIf(a, b, isIterableEquatable, compareIterableEquality, cache) + || cacheComparison(a, b, fail, cache); + } + + function isBoxed(value) { + return value instanceof String + || value instanceof Number + || value instanceof Boolean + || typeof Symbol === 'function' && value instanceof Symbol + || typeof BigInt === 'function' && value instanceof BigInt; + } + + function isValueOfEquatable(value) { + return value instanceof Date; + } + + function compareValueOfEquality(a, b) { + return compareIf(a.valueOf(), b.valueOf(), isPrimitiveEquatable, comparePrimitiveEquality) + || NOT_EQUAL; + } + + function isToStringEquatable(value) { + return value instanceof RegExp; + } + + function compareToStringEquality(a, b) { + return compareIf(a.toString(), b.toString(), isPrimitiveEquatable, comparePrimitiveEquality) + || NOT_EQUAL; + } + + function isArrayLikeEquatable(value) { + return (Array.isArray ? Array.isArray(value) : value instanceof Array) + || (typeof Uint8Array === 'function' && value instanceof Uint8Array) + || (typeof Uint8ClampedArray === 'function' && value instanceof Uint8ClampedArray) + || (typeof Uint16Array === 'function' && value instanceof Uint16Array) + || (typeof Uint32Array === 'function' && value instanceof Uint32Array) + || (typeof Int8Array === 'function' && value instanceof Int8Array) + || (typeof Int16Array === 'function' && value instanceof Int16Array) + || (typeof Int32Array === 'function' && value instanceof Int32Array) + || (typeof Float32Array === 'function' && value instanceof Float32Array) + || (typeof Float64Array === 'function' && value instanceof Float64Array) + || (typeof BigUint64Array === 'function' && value instanceof BigUint64Array) + || (typeof BigInt64Array === 'function' && value instanceof BigInt64Array); + } + + function compareArrayLikeEquality(a, b, cache) { + if (a.length !== b.length) return NOT_EQUAL; + for (var i = 0; i < a.length; i++) { + if (compareEquality(a[i], b[i], cache) === NOT_EQUAL) { + return NOT_EQUAL; + } + } + return EQUAL; + } + + function isStructurallyEquatable(value) { + return !(typeof Promise === 'function' && value instanceof Promise // only comparable by reference + || typeof WeakMap === 'function' && value instanceof WeakMap // only comparable by reference + || typeof WeakSet === 'function' && value instanceof WeakSet // only comparable by reference + || typeof Map === 'function' && value instanceof Map // comparable via @@iterator + || typeof Set === 'function' && value instanceof Set); // comparable via @@iterator + } + + function compareStructuralEquality(a, b, cache) { + var aKeys = []; + for (var key in a) aKeys.push(key); + + var bKeys = []; + for (var key in b) bKeys.push(key); + + if (aKeys.length !== bKeys.length) { + return NOT_EQUAL; + } + + aKeys.sort(); + bKeys.sort(); + + for (var i = 0; i < aKeys.length; i++) { + var aKey = aKeys[i]; + var bKey = bKeys[i]; + if (compareEquality(aKey, bKey, cache) === NOT_EQUAL) { + return NOT_EQUAL; + } + if (compareEquality(a[aKey], b[bKey], cache) === NOT_EQUAL) { + return NOT_EQUAL; + } + } + + return compareIf(a, b, isIterableEquatable, compareIterableEquality, cache) + || EQUAL; + } + + function isIterableEquatable(value) { + return typeof Symbol === 'function' + && typeof value[Symbol.iterator] === 'function'; + } + + function compareIteratorEquality(a, b, cache) { + if (typeof Map === 'function' && a instanceof Map && b instanceof Map || + typeof Set === 'function' && a instanceof Set && b instanceof Set) { + if (a.size !== b.size) return NOT_EQUAL; // exit early if we detect a difference in size + } + + var ar, br; + while (true) { + ar = a.next(); + br = b.next(); + if (ar.done) { + if (br.done) return EQUAL; + if (b.return) b.return(); + return NOT_EQUAL; + } + if (br.done) { + if (a.return) a.return(); + return NOT_EQUAL; + } + if (compareEquality(ar.value, br.value, cache) === NOT_EQUAL) { + if (a.return) a.return(); + if (b.return) b.return(); + return NOT_EQUAL; + } + } + } + + function compareIterableEquality(a, b, cache) { + return compareIteratorEquality(a[Symbol.iterator](), b[Symbol.iterator](), cache); + } + + function cacheComparison(a, b, compare, cache) { + var result = compare(a, b, cache); + if (cache && (result === EQUAL || result === NOT_EQUAL)) { + setCache(cache, a, b, /** @type {EQUAL | NOT_EQUAL} */(result)); + } + return result; + } + + function fail() { + return NOT_EQUAL; + } + + function setCache(cache, left, right, result) { + var otherCache; + + otherCache = cache.get(left); + if (!otherCache) cache.set(left, otherCache = new Map()); + otherCache.set(right, result); + + otherCache = cache.get(right); + if (!otherCache) cache.set(right, otherCache = new Map()); + otherCache.set(left, result); + } + + function getCache(cache, left, right) { + var otherCache; + var result; + + otherCache = cache.get(left); + result = otherCache && otherCache.get(right); + if (result) return result; + + otherCache = cache.get(right); + result = otherCache && otherCache.get(left); + if (result) return result; + + return UNKNOWN; + } + + return deepEqual; +})(); |