11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst {
41cb0ef41Sopenharmony_ci  ArrayIsArray,
51cb0ef41Sopenharmony_ci  ArrayPrototypeFilter,
61cb0ef41Sopenharmony_ci  ArrayPrototypePush,
71cb0ef41Sopenharmony_ci  BigIntPrototypeValueOf,
81cb0ef41Sopenharmony_ci  BooleanPrototypeValueOf,
91cb0ef41Sopenharmony_ci  DatePrototypeGetTime,
101cb0ef41Sopenharmony_ci  Error,
111cb0ef41Sopenharmony_ci  NumberIsNaN,
121cb0ef41Sopenharmony_ci  NumberPrototypeValueOf,
131cb0ef41Sopenharmony_ci  ObjectGetOwnPropertySymbols,
141cb0ef41Sopenharmony_ci  ObjectGetPrototypeOf,
151cb0ef41Sopenharmony_ci  ObjectIs,
161cb0ef41Sopenharmony_ci  ObjectKeys,
171cb0ef41Sopenharmony_ci  ObjectPrototypeHasOwnProperty,
181cb0ef41Sopenharmony_ci  ObjectPrototypePropertyIsEnumerable,
191cb0ef41Sopenharmony_ci  ObjectPrototypeToString,
201cb0ef41Sopenharmony_ci  SafeMap,
211cb0ef41Sopenharmony_ci  SafeSet,
221cb0ef41Sopenharmony_ci  StringPrototypeValueOf,
231cb0ef41Sopenharmony_ci  SymbolPrototypeValueOf,
241cb0ef41Sopenharmony_ci  TypedArrayPrototypeGetSymbolToStringTag,
251cb0ef41Sopenharmony_ci  Uint8Array,
261cb0ef41Sopenharmony_ci} = primordials;
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_ciconst { compare } = internalBinding('buffer');
291cb0ef41Sopenharmony_ciconst assert = require('internal/assert');
301cb0ef41Sopenharmony_ciconst types = require('internal/util/types');
311cb0ef41Sopenharmony_ciconst {
321cb0ef41Sopenharmony_ci  isAnyArrayBuffer,
331cb0ef41Sopenharmony_ci  isArrayBufferView,
341cb0ef41Sopenharmony_ci  isDate,
351cb0ef41Sopenharmony_ci  isMap,
361cb0ef41Sopenharmony_ci  isRegExp,
371cb0ef41Sopenharmony_ci  isSet,
381cb0ef41Sopenharmony_ci  isNativeError,
391cb0ef41Sopenharmony_ci  isBoxedPrimitive,
401cb0ef41Sopenharmony_ci  isNumberObject,
411cb0ef41Sopenharmony_ci  isStringObject,
421cb0ef41Sopenharmony_ci  isBooleanObject,
431cb0ef41Sopenharmony_ci  isBigIntObject,
441cb0ef41Sopenharmony_ci  isSymbolObject,
451cb0ef41Sopenharmony_ci  isFloat32Array,
461cb0ef41Sopenharmony_ci  isFloat64Array,
471cb0ef41Sopenharmony_ci} = types;
481cb0ef41Sopenharmony_ciconst {
491cb0ef41Sopenharmony_ci  constants: {
501cb0ef41Sopenharmony_ci    ONLY_ENUMERABLE,
511cb0ef41Sopenharmony_ci    SKIP_SYMBOLS,
521cb0ef41Sopenharmony_ci  },
531cb0ef41Sopenharmony_ci  getOwnNonIndexProperties,
541cb0ef41Sopenharmony_ci} = internalBinding('util');
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ciconst kStrict = true;
571cb0ef41Sopenharmony_ciconst kLoose = false;
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_ciconst kNoIterator = 0;
601cb0ef41Sopenharmony_ciconst kIsArray = 1;
611cb0ef41Sopenharmony_ciconst kIsSet = 2;
621cb0ef41Sopenharmony_ciconst kIsMap = 3;
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_ci// Check if they have the same source and flags
651cb0ef41Sopenharmony_cifunction areSimilarRegExps(a, b) {
661cb0ef41Sopenharmony_ci  return a.source === b.source &&
671cb0ef41Sopenharmony_ci         a.flags === b.flags &&
681cb0ef41Sopenharmony_ci         a.lastIndex === b.lastIndex;
691cb0ef41Sopenharmony_ci}
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_cifunction areSimilarFloatArrays(a, b) {
721cb0ef41Sopenharmony_ci  if (a.byteLength !== b.byteLength) {
731cb0ef41Sopenharmony_ci    return false;
741cb0ef41Sopenharmony_ci  }
751cb0ef41Sopenharmony_ci  for (let offset = 0; offset < a.byteLength; offset++) {
761cb0ef41Sopenharmony_ci    if (a[offset] !== b[offset]) {
771cb0ef41Sopenharmony_ci      return false;
781cb0ef41Sopenharmony_ci    }
791cb0ef41Sopenharmony_ci  }
801cb0ef41Sopenharmony_ci  return true;
811cb0ef41Sopenharmony_ci}
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_cifunction areSimilarTypedArrays(a, b) {
841cb0ef41Sopenharmony_ci  if (a.byteLength !== b.byteLength) {
851cb0ef41Sopenharmony_ci    return false;
861cb0ef41Sopenharmony_ci  }
871cb0ef41Sopenharmony_ci  return compare(new Uint8Array(a.buffer, a.byteOffset, a.byteLength),
881cb0ef41Sopenharmony_ci                 new Uint8Array(b.buffer, b.byteOffset, b.byteLength)) === 0;
891cb0ef41Sopenharmony_ci}
901cb0ef41Sopenharmony_ci
911cb0ef41Sopenharmony_cifunction areEqualArrayBuffers(buf1, buf2) {
921cb0ef41Sopenharmony_ci  return buf1.byteLength === buf2.byteLength &&
931cb0ef41Sopenharmony_ci    compare(new Uint8Array(buf1), new Uint8Array(buf2)) === 0;
941cb0ef41Sopenharmony_ci}
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_cifunction isEqualBoxedPrimitive(val1, val2) {
971cb0ef41Sopenharmony_ci  if (isNumberObject(val1)) {
981cb0ef41Sopenharmony_ci    return isNumberObject(val2) &&
991cb0ef41Sopenharmony_ci           ObjectIs(NumberPrototypeValueOf(val1),
1001cb0ef41Sopenharmony_ci                    NumberPrototypeValueOf(val2));
1011cb0ef41Sopenharmony_ci  }
1021cb0ef41Sopenharmony_ci  if (isStringObject(val1)) {
1031cb0ef41Sopenharmony_ci    return isStringObject(val2) &&
1041cb0ef41Sopenharmony_ci           StringPrototypeValueOf(val1) === StringPrototypeValueOf(val2);
1051cb0ef41Sopenharmony_ci  }
1061cb0ef41Sopenharmony_ci  if (isBooleanObject(val1)) {
1071cb0ef41Sopenharmony_ci    return isBooleanObject(val2) &&
1081cb0ef41Sopenharmony_ci           BooleanPrototypeValueOf(val1) === BooleanPrototypeValueOf(val2);
1091cb0ef41Sopenharmony_ci  }
1101cb0ef41Sopenharmony_ci  if (isBigIntObject(val1)) {
1111cb0ef41Sopenharmony_ci    return isBigIntObject(val2) &&
1121cb0ef41Sopenharmony_ci           BigIntPrototypeValueOf(val1) === BigIntPrototypeValueOf(val2);
1131cb0ef41Sopenharmony_ci  }
1141cb0ef41Sopenharmony_ci  if (isSymbolObject(val1)) {
1151cb0ef41Sopenharmony_ci    return isSymbolObject(val2) &&
1161cb0ef41Sopenharmony_ci          SymbolPrototypeValueOf(val1) === SymbolPrototypeValueOf(val2);
1171cb0ef41Sopenharmony_ci  }
1181cb0ef41Sopenharmony_ci  /* c8 ignore next */
1191cb0ef41Sopenharmony_ci  assert.fail(`Unknown boxed type ${val1}`);
1201cb0ef41Sopenharmony_ci}
1211cb0ef41Sopenharmony_ci
1221cb0ef41Sopenharmony_ci// Notes: Type tags are historical [[Class]] properties that can be set by
1231cb0ef41Sopenharmony_ci// FunctionTemplate::SetClassName() in C++ or Symbol.toStringTag in JS
1241cb0ef41Sopenharmony_ci// and retrieved using Object.prototype.toString.call(obj) in JS
1251cb0ef41Sopenharmony_ci// See https://tc39.github.io/ecma262/#sec-object.prototype.tostring
1261cb0ef41Sopenharmony_ci// for a list of tags pre-defined in the spec.
1271cb0ef41Sopenharmony_ci// There are some unspecified tags in the wild too (e.g. typed array tags).
1281cb0ef41Sopenharmony_ci// Since tags can be altered, they only serve fast failures
1291cb0ef41Sopenharmony_ci//
1301cb0ef41Sopenharmony_ci// For strict comparison, objects should have
1311cb0ef41Sopenharmony_ci// a) The same built-in type tag.
1321cb0ef41Sopenharmony_ci// b) The same prototypes.
1331cb0ef41Sopenharmony_ci
1341cb0ef41Sopenharmony_cifunction innerDeepEqual(val1, val2, strict, memos) {
1351cb0ef41Sopenharmony_ci  // All identical values are equivalent, as determined by ===.
1361cb0ef41Sopenharmony_ci  if (val1 === val2) {
1371cb0ef41Sopenharmony_ci    if (val1 !== 0)
1381cb0ef41Sopenharmony_ci      return true;
1391cb0ef41Sopenharmony_ci    return strict ? ObjectIs(val1, val2) : true;
1401cb0ef41Sopenharmony_ci  }
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_ci  // Check more closely if val1 and val2 are equal.
1431cb0ef41Sopenharmony_ci  if (strict) {
1441cb0ef41Sopenharmony_ci    if (typeof val1 !== 'object') {
1451cb0ef41Sopenharmony_ci      return typeof val1 === 'number' && NumberIsNaN(val1) &&
1461cb0ef41Sopenharmony_ci        NumberIsNaN(val2);
1471cb0ef41Sopenharmony_ci    }
1481cb0ef41Sopenharmony_ci    if (typeof val2 !== 'object' || val1 === null || val2 === null) {
1491cb0ef41Sopenharmony_ci      return false;
1501cb0ef41Sopenharmony_ci    }
1511cb0ef41Sopenharmony_ci    if (ObjectGetPrototypeOf(val1) !== ObjectGetPrototypeOf(val2)) {
1521cb0ef41Sopenharmony_ci      return false;
1531cb0ef41Sopenharmony_ci    }
1541cb0ef41Sopenharmony_ci  } else {
1551cb0ef41Sopenharmony_ci    if (val1 === null || typeof val1 !== 'object') {
1561cb0ef41Sopenharmony_ci      if (val2 === null || typeof val2 !== 'object') {
1571cb0ef41Sopenharmony_ci        // eslint-disable-next-line eqeqeq
1581cb0ef41Sopenharmony_ci        return val1 == val2 || (NumberIsNaN(val1) && NumberIsNaN(val2));
1591cb0ef41Sopenharmony_ci      }
1601cb0ef41Sopenharmony_ci      return false;
1611cb0ef41Sopenharmony_ci    }
1621cb0ef41Sopenharmony_ci    if (val2 === null || typeof val2 !== 'object') {
1631cb0ef41Sopenharmony_ci      return false;
1641cb0ef41Sopenharmony_ci    }
1651cb0ef41Sopenharmony_ci  }
1661cb0ef41Sopenharmony_ci  const val1Tag = ObjectPrototypeToString(val1);
1671cb0ef41Sopenharmony_ci  const val2Tag = ObjectPrototypeToString(val2);
1681cb0ef41Sopenharmony_ci
1691cb0ef41Sopenharmony_ci  if (val1Tag !== val2Tag) {
1701cb0ef41Sopenharmony_ci    return false;
1711cb0ef41Sopenharmony_ci  }
1721cb0ef41Sopenharmony_ci
1731cb0ef41Sopenharmony_ci  if (ArrayIsArray(val1)) {
1741cb0ef41Sopenharmony_ci    // Check for sparse arrays and general fast path
1751cb0ef41Sopenharmony_ci    if (!ArrayIsArray(val2) || val1.length !== val2.length) {
1761cb0ef41Sopenharmony_ci      return false;
1771cb0ef41Sopenharmony_ci    }
1781cb0ef41Sopenharmony_ci    const filter = strict ? ONLY_ENUMERABLE : ONLY_ENUMERABLE | SKIP_SYMBOLS;
1791cb0ef41Sopenharmony_ci    const keys1 = getOwnNonIndexProperties(val1, filter);
1801cb0ef41Sopenharmony_ci    const keys2 = getOwnNonIndexProperties(val2, filter);
1811cb0ef41Sopenharmony_ci    if (keys1.length !== keys2.length) {
1821cb0ef41Sopenharmony_ci      return false;
1831cb0ef41Sopenharmony_ci    }
1841cb0ef41Sopenharmony_ci    return keyCheck(val1, val2, strict, memos, kIsArray, keys1);
1851cb0ef41Sopenharmony_ci  } else if (val1Tag === '[object Object]') {
1861cb0ef41Sopenharmony_ci    return keyCheck(val1, val2, strict, memos, kNoIterator);
1871cb0ef41Sopenharmony_ci  } else if (isDate(val1)) {
1881cb0ef41Sopenharmony_ci    if (!isDate(val2) ||
1891cb0ef41Sopenharmony_ci        DatePrototypeGetTime(val1) !== DatePrototypeGetTime(val2)) {
1901cb0ef41Sopenharmony_ci      return false;
1911cb0ef41Sopenharmony_ci    }
1921cb0ef41Sopenharmony_ci  } else if (isRegExp(val1)) {
1931cb0ef41Sopenharmony_ci    if (!isRegExp(val2) || !areSimilarRegExps(val1, val2)) {
1941cb0ef41Sopenharmony_ci      return false;
1951cb0ef41Sopenharmony_ci    }
1961cb0ef41Sopenharmony_ci  } else if (isNativeError(val1) || val1 instanceof Error) {
1971cb0ef41Sopenharmony_ci    // Do not compare the stack as it might differ even though the error itself
1981cb0ef41Sopenharmony_ci    // is otherwise identical.
1991cb0ef41Sopenharmony_ci    if ((!isNativeError(val2) && !(val2 instanceof Error)) ||
2001cb0ef41Sopenharmony_ci        val1.message !== val2.message ||
2011cb0ef41Sopenharmony_ci        val1.name !== val2.name) {
2021cb0ef41Sopenharmony_ci      return false;
2031cb0ef41Sopenharmony_ci    }
2041cb0ef41Sopenharmony_ci  } else if (isArrayBufferView(val1)) {
2051cb0ef41Sopenharmony_ci    if (TypedArrayPrototypeGetSymbolToStringTag(val1) !==
2061cb0ef41Sopenharmony_ci        TypedArrayPrototypeGetSymbolToStringTag(val2)) {
2071cb0ef41Sopenharmony_ci      return false;
2081cb0ef41Sopenharmony_ci    }
2091cb0ef41Sopenharmony_ci    if (!strict && (isFloat32Array(val1) || isFloat64Array(val1))) {
2101cb0ef41Sopenharmony_ci      if (!areSimilarFloatArrays(val1, val2)) {
2111cb0ef41Sopenharmony_ci        return false;
2121cb0ef41Sopenharmony_ci      }
2131cb0ef41Sopenharmony_ci    } else if (!areSimilarTypedArrays(val1, val2)) {
2141cb0ef41Sopenharmony_ci      return false;
2151cb0ef41Sopenharmony_ci    }
2161cb0ef41Sopenharmony_ci    // Buffer.compare returns true, so val1.length === val2.length. If they both
2171cb0ef41Sopenharmony_ci    // only contain numeric keys, we don't need to exam further than checking
2181cb0ef41Sopenharmony_ci    // the symbols.
2191cb0ef41Sopenharmony_ci    const filter = strict ? ONLY_ENUMERABLE : ONLY_ENUMERABLE | SKIP_SYMBOLS;
2201cb0ef41Sopenharmony_ci    const keys1 = getOwnNonIndexProperties(val1, filter);
2211cb0ef41Sopenharmony_ci    const keys2 = getOwnNonIndexProperties(val2, filter);
2221cb0ef41Sopenharmony_ci    if (keys1.length !== keys2.length) {
2231cb0ef41Sopenharmony_ci      return false;
2241cb0ef41Sopenharmony_ci    }
2251cb0ef41Sopenharmony_ci    return keyCheck(val1, val2, strict, memos, kNoIterator, keys1);
2261cb0ef41Sopenharmony_ci  } else if (isSet(val1)) {
2271cb0ef41Sopenharmony_ci    if (!isSet(val2) || val1.size !== val2.size) {
2281cb0ef41Sopenharmony_ci      return false;
2291cb0ef41Sopenharmony_ci    }
2301cb0ef41Sopenharmony_ci    return keyCheck(val1, val2, strict, memos, kIsSet);
2311cb0ef41Sopenharmony_ci  } else if (isMap(val1)) {
2321cb0ef41Sopenharmony_ci    if (!isMap(val2) || val1.size !== val2.size) {
2331cb0ef41Sopenharmony_ci      return false;
2341cb0ef41Sopenharmony_ci    }
2351cb0ef41Sopenharmony_ci    return keyCheck(val1, val2, strict, memos, kIsMap);
2361cb0ef41Sopenharmony_ci  } else if (isAnyArrayBuffer(val1)) {
2371cb0ef41Sopenharmony_ci    if (!isAnyArrayBuffer(val2) || !areEqualArrayBuffers(val1, val2)) {
2381cb0ef41Sopenharmony_ci      return false;
2391cb0ef41Sopenharmony_ci    }
2401cb0ef41Sopenharmony_ci  } else if (isBoxedPrimitive(val1)) {
2411cb0ef41Sopenharmony_ci    if (!isEqualBoxedPrimitive(val1, val2)) {
2421cb0ef41Sopenharmony_ci      return false;
2431cb0ef41Sopenharmony_ci    }
2441cb0ef41Sopenharmony_ci  } else if (ArrayIsArray(val2) ||
2451cb0ef41Sopenharmony_ci             isArrayBufferView(val2) ||
2461cb0ef41Sopenharmony_ci             isSet(val2) ||
2471cb0ef41Sopenharmony_ci             isMap(val2) ||
2481cb0ef41Sopenharmony_ci             isDate(val2) ||
2491cb0ef41Sopenharmony_ci             isRegExp(val2) ||
2501cb0ef41Sopenharmony_ci             isAnyArrayBuffer(val2) ||
2511cb0ef41Sopenharmony_ci             isBoxedPrimitive(val2) ||
2521cb0ef41Sopenharmony_ci             isNativeError(val2) ||
2531cb0ef41Sopenharmony_ci             val2 instanceof Error) {
2541cb0ef41Sopenharmony_ci    return false;
2551cb0ef41Sopenharmony_ci  }
2561cb0ef41Sopenharmony_ci  return keyCheck(val1, val2, strict, memos, kNoIterator);
2571cb0ef41Sopenharmony_ci}
2581cb0ef41Sopenharmony_ci
2591cb0ef41Sopenharmony_cifunction getEnumerables(val, keys) {
2601cb0ef41Sopenharmony_ci  return ArrayPrototypeFilter(
2611cb0ef41Sopenharmony_ci    keys,
2621cb0ef41Sopenharmony_ci    (k) => ObjectPrototypePropertyIsEnumerable(val, k),
2631cb0ef41Sopenharmony_ci  );
2641cb0ef41Sopenharmony_ci}
2651cb0ef41Sopenharmony_ci
2661cb0ef41Sopenharmony_cifunction keyCheck(val1, val2, strict, memos, iterationType, aKeys) {
2671cb0ef41Sopenharmony_ci  // For all remaining Object pairs, including Array, objects and Maps,
2681cb0ef41Sopenharmony_ci  // equivalence is determined by having:
2691cb0ef41Sopenharmony_ci  // a) The same number of owned enumerable properties
2701cb0ef41Sopenharmony_ci  // b) The same set of keys/indexes (although not necessarily the same order)
2711cb0ef41Sopenharmony_ci  // c) Equivalent values for every corresponding key/index
2721cb0ef41Sopenharmony_ci  // d) For Sets and Maps, equal contents
2731cb0ef41Sopenharmony_ci  // Note: this accounts for both named and indexed properties on Arrays.
2741cb0ef41Sopenharmony_ci  if (arguments.length === 5) {
2751cb0ef41Sopenharmony_ci    aKeys = ObjectKeys(val1);
2761cb0ef41Sopenharmony_ci    const bKeys = ObjectKeys(val2);
2771cb0ef41Sopenharmony_ci
2781cb0ef41Sopenharmony_ci    // The pair must have the same number of owned properties.
2791cb0ef41Sopenharmony_ci    if (aKeys.length !== bKeys.length) {
2801cb0ef41Sopenharmony_ci      return false;
2811cb0ef41Sopenharmony_ci    }
2821cb0ef41Sopenharmony_ci  }
2831cb0ef41Sopenharmony_ci
2841cb0ef41Sopenharmony_ci  // Cheap key test
2851cb0ef41Sopenharmony_ci  let i = 0;
2861cb0ef41Sopenharmony_ci  for (; i < aKeys.length; i++) {
2871cb0ef41Sopenharmony_ci    if (!ObjectPrototypePropertyIsEnumerable(val2, aKeys[i])) {
2881cb0ef41Sopenharmony_ci      return false;
2891cb0ef41Sopenharmony_ci    }
2901cb0ef41Sopenharmony_ci  }
2911cb0ef41Sopenharmony_ci
2921cb0ef41Sopenharmony_ci  if (strict && arguments.length === 5) {
2931cb0ef41Sopenharmony_ci    const symbolKeysA = ObjectGetOwnPropertySymbols(val1);
2941cb0ef41Sopenharmony_ci    if (symbolKeysA.length !== 0) {
2951cb0ef41Sopenharmony_ci      let count = 0;
2961cb0ef41Sopenharmony_ci      for (i = 0; i < symbolKeysA.length; i++) {
2971cb0ef41Sopenharmony_ci        const key = symbolKeysA[i];
2981cb0ef41Sopenharmony_ci        if (ObjectPrototypePropertyIsEnumerable(val1, key)) {
2991cb0ef41Sopenharmony_ci          if (!ObjectPrototypePropertyIsEnumerable(val2, key)) {
3001cb0ef41Sopenharmony_ci            return false;
3011cb0ef41Sopenharmony_ci          }
3021cb0ef41Sopenharmony_ci          ArrayPrototypePush(aKeys, key);
3031cb0ef41Sopenharmony_ci          count++;
3041cb0ef41Sopenharmony_ci        } else if (ObjectPrototypePropertyIsEnumerable(val2, key)) {
3051cb0ef41Sopenharmony_ci          return false;
3061cb0ef41Sopenharmony_ci        }
3071cb0ef41Sopenharmony_ci      }
3081cb0ef41Sopenharmony_ci      const symbolKeysB = ObjectGetOwnPropertySymbols(val2);
3091cb0ef41Sopenharmony_ci      if (symbolKeysA.length !== symbolKeysB.length &&
3101cb0ef41Sopenharmony_ci          getEnumerables(val2, symbolKeysB).length !== count) {
3111cb0ef41Sopenharmony_ci        return false;
3121cb0ef41Sopenharmony_ci      }
3131cb0ef41Sopenharmony_ci    } else {
3141cb0ef41Sopenharmony_ci      const symbolKeysB = ObjectGetOwnPropertySymbols(val2);
3151cb0ef41Sopenharmony_ci      if (symbolKeysB.length !== 0 &&
3161cb0ef41Sopenharmony_ci          getEnumerables(val2, symbolKeysB).length !== 0) {
3171cb0ef41Sopenharmony_ci        return false;
3181cb0ef41Sopenharmony_ci      }
3191cb0ef41Sopenharmony_ci    }
3201cb0ef41Sopenharmony_ci  }
3211cb0ef41Sopenharmony_ci
3221cb0ef41Sopenharmony_ci  if (aKeys.length === 0 &&
3231cb0ef41Sopenharmony_ci      (iterationType === kNoIterator ||
3241cb0ef41Sopenharmony_ci        (iterationType === kIsArray && val1.length === 0) ||
3251cb0ef41Sopenharmony_ci        val1.size === 0)) {
3261cb0ef41Sopenharmony_ci    return true;
3271cb0ef41Sopenharmony_ci  }
3281cb0ef41Sopenharmony_ci
3291cb0ef41Sopenharmony_ci  // Use memos to handle cycles.
3301cb0ef41Sopenharmony_ci  if (memos === undefined) {
3311cb0ef41Sopenharmony_ci    memos = {
3321cb0ef41Sopenharmony_ci      val1: new SafeMap(),
3331cb0ef41Sopenharmony_ci      val2: new SafeMap(),
3341cb0ef41Sopenharmony_ci      position: 0,
3351cb0ef41Sopenharmony_ci    };
3361cb0ef41Sopenharmony_ci  } else {
3371cb0ef41Sopenharmony_ci    // We prevent up to two map.has(x) calls by directly retrieving the value
3381cb0ef41Sopenharmony_ci    // and checking for undefined. The map can only contain numbers, so it is
3391cb0ef41Sopenharmony_ci    // safe to check for undefined only.
3401cb0ef41Sopenharmony_ci    const val2MemoA = memos.val1.get(val1);
3411cb0ef41Sopenharmony_ci    if (val2MemoA !== undefined) {
3421cb0ef41Sopenharmony_ci      const val2MemoB = memos.val2.get(val2);
3431cb0ef41Sopenharmony_ci      if (val2MemoB !== undefined) {
3441cb0ef41Sopenharmony_ci        return val2MemoA === val2MemoB;
3451cb0ef41Sopenharmony_ci      }
3461cb0ef41Sopenharmony_ci    }
3471cb0ef41Sopenharmony_ci    memos.position++;
3481cb0ef41Sopenharmony_ci  }
3491cb0ef41Sopenharmony_ci
3501cb0ef41Sopenharmony_ci  memos.val1.set(val1, memos.position);
3511cb0ef41Sopenharmony_ci  memos.val2.set(val2, memos.position);
3521cb0ef41Sopenharmony_ci
3531cb0ef41Sopenharmony_ci  const areEq = objEquiv(val1, val2, strict, aKeys, memos, iterationType);
3541cb0ef41Sopenharmony_ci
3551cb0ef41Sopenharmony_ci  memos.val1.delete(val1);
3561cb0ef41Sopenharmony_ci  memos.val2.delete(val2);
3571cb0ef41Sopenharmony_ci
3581cb0ef41Sopenharmony_ci  return areEq;
3591cb0ef41Sopenharmony_ci}
3601cb0ef41Sopenharmony_ci
3611cb0ef41Sopenharmony_cifunction setHasEqualElement(set, val1, strict, memo) {
3621cb0ef41Sopenharmony_ci  // Go looking.
3631cb0ef41Sopenharmony_ci  for (const val2 of set) {
3641cb0ef41Sopenharmony_ci    if (innerDeepEqual(val1, val2, strict, memo)) {
3651cb0ef41Sopenharmony_ci      // Remove the matching element to make sure we do not check that again.
3661cb0ef41Sopenharmony_ci      set.delete(val2);
3671cb0ef41Sopenharmony_ci      return true;
3681cb0ef41Sopenharmony_ci    }
3691cb0ef41Sopenharmony_ci  }
3701cb0ef41Sopenharmony_ci
3711cb0ef41Sopenharmony_ci  return false;
3721cb0ef41Sopenharmony_ci}
3731cb0ef41Sopenharmony_ci
3741cb0ef41Sopenharmony_ci// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness#Loose_equality_using
3751cb0ef41Sopenharmony_ci// Sadly it is not possible to detect corresponding values properly in case the
3761cb0ef41Sopenharmony_ci// type is a string, number, bigint or boolean. The reason is that those values
3771cb0ef41Sopenharmony_ci// can match lots of different string values (e.g., 1n == '+00001').
3781cb0ef41Sopenharmony_cifunction findLooseMatchingPrimitives(prim) {
3791cb0ef41Sopenharmony_ci  switch (typeof prim) {
3801cb0ef41Sopenharmony_ci    case 'undefined':
3811cb0ef41Sopenharmony_ci      return null;
3821cb0ef41Sopenharmony_ci    case 'object': // Only pass in null as object!
3831cb0ef41Sopenharmony_ci      return undefined;
3841cb0ef41Sopenharmony_ci    case 'symbol':
3851cb0ef41Sopenharmony_ci      return false;
3861cb0ef41Sopenharmony_ci    case 'string':
3871cb0ef41Sopenharmony_ci      prim = +prim;
3881cb0ef41Sopenharmony_ci      // Loose equal entries exist only if the string is possible to convert to
3891cb0ef41Sopenharmony_ci      // a regular number and not NaN.
3901cb0ef41Sopenharmony_ci      // Fall through
3911cb0ef41Sopenharmony_ci    case 'number':
3921cb0ef41Sopenharmony_ci      if (NumberIsNaN(prim)) {
3931cb0ef41Sopenharmony_ci        return false;
3941cb0ef41Sopenharmony_ci      }
3951cb0ef41Sopenharmony_ci  }
3961cb0ef41Sopenharmony_ci  return true;
3971cb0ef41Sopenharmony_ci}
3981cb0ef41Sopenharmony_ci
3991cb0ef41Sopenharmony_cifunction setMightHaveLoosePrim(a, b, prim) {
4001cb0ef41Sopenharmony_ci  const altValue = findLooseMatchingPrimitives(prim);
4011cb0ef41Sopenharmony_ci  if (altValue != null)
4021cb0ef41Sopenharmony_ci    return altValue;
4031cb0ef41Sopenharmony_ci
4041cb0ef41Sopenharmony_ci  return b.has(altValue) && !a.has(altValue);
4051cb0ef41Sopenharmony_ci}
4061cb0ef41Sopenharmony_ci
4071cb0ef41Sopenharmony_cifunction mapMightHaveLoosePrim(a, b, prim, item, memo) {
4081cb0ef41Sopenharmony_ci  const altValue = findLooseMatchingPrimitives(prim);
4091cb0ef41Sopenharmony_ci  if (altValue != null) {
4101cb0ef41Sopenharmony_ci    return altValue;
4111cb0ef41Sopenharmony_ci  }
4121cb0ef41Sopenharmony_ci  const curB = b.get(altValue);
4131cb0ef41Sopenharmony_ci  if ((curB === undefined && !b.has(altValue)) ||
4141cb0ef41Sopenharmony_ci      !innerDeepEqual(item, curB, false, memo)) {
4151cb0ef41Sopenharmony_ci    return false;
4161cb0ef41Sopenharmony_ci  }
4171cb0ef41Sopenharmony_ci  return !a.has(altValue) && innerDeepEqual(item, curB, false, memo);
4181cb0ef41Sopenharmony_ci}
4191cb0ef41Sopenharmony_ci
4201cb0ef41Sopenharmony_cifunction setEquiv(a, b, strict, memo) {
4211cb0ef41Sopenharmony_ci  // This is a lazily initiated Set of entries which have to be compared
4221cb0ef41Sopenharmony_ci  // pairwise.
4231cb0ef41Sopenharmony_ci  let set = null;
4241cb0ef41Sopenharmony_ci  for (const val of a) {
4251cb0ef41Sopenharmony_ci    // Note: Checking for the objects first improves the performance for object
4261cb0ef41Sopenharmony_ci    // heavy sets but it is a minor slow down for primitives. As they are fast
4271cb0ef41Sopenharmony_ci    // to check this improves the worst case scenario instead.
4281cb0ef41Sopenharmony_ci    if (typeof val === 'object' && val !== null) {
4291cb0ef41Sopenharmony_ci      if (set === null) {
4301cb0ef41Sopenharmony_ci        set = new SafeSet();
4311cb0ef41Sopenharmony_ci      }
4321cb0ef41Sopenharmony_ci      // If the specified value doesn't exist in the second set it's a non-null
4331cb0ef41Sopenharmony_ci      // object (or non strict only: a not matching primitive) we'll need to go
4341cb0ef41Sopenharmony_ci      // hunting for something that's deep-(strict-)equal to it. To make this
4351cb0ef41Sopenharmony_ci      // O(n log n) complexity we have to copy these values in a new set first.
4361cb0ef41Sopenharmony_ci      set.add(val);
4371cb0ef41Sopenharmony_ci    } else if (!b.has(val)) {
4381cb0ef41Sopenharmony_ci      if (strict)
4391cb0ef41Sopenharmony_ci        return false;
4401cb0ef41Sopenharmony_ci
4411cb0ef41Sopenharmony_ci      // Fast path to detect missing string, symbol, undefined and null values.
4421cb0ef41Sopenharmony_ci      if (!setMightHaveLoosePrim(a, b, val)) {
4431cb0ef41Sopenharmony_ci        return false;
4441cb0ef41Sopenharmony_ci      }
4451cb0ef41Sopenharmony_ci
4461cb0ef41Sopenharmony_ci      if (set === null) {
4471cb0ef41Sopenharmony_ci        set = new SafeSet();
4481cb0ef41Sopenharmony_ci      }
4491cb0ef41Sopenharmony_ci      set.add(val);
4501cb0ef41Sopenharmony_ci    }
4511cb0ef41Sopenharmony_ci  }
4521cb0ef41Sopenharmony_ci
4531cb0ef41Sopenharmony_ci  if (set !== null) {
4541cb0ef41Sopenharmony_ci    for (const val of b) {
4551cb0ef41Sopenharmony_ci      // We have to check if a primitive value is already
4561cb0ef41Sopenharmony_ci      // matching and only if it's not, go hunting for it.
4571cb0ef41Sopenharmony_ci      if (typeof val === 'object' && val !== null) {
4581cb0ef41Sopenharmony_ci        if (!setHasEqualElement(set, val, strict, memo))
4591cb0ef41Sopenharmony_ci          return false;
4601cb0ef41Sopenharmony_ci      } else if (!strict &&
4611cb0ef41Sopenharmony_ci                 !a.has(val) &&
4621cb0ef41Sopenharmony_ci                 !setHasEqualElement(set, val, strict, memo)) {
4631cb0ef41Sopenharmony_ci        return false;
4641cb0ef41Sopenharmony_ci      }
4651cb0ef41Sopenharmony_ci    }
4661cb0ef41Sopenharmony_ci    return set.size === 0;
4671cb0ef41Sopenharmony_ci  }
4681cb0ef41Sopenharmony_ci
4691cb0ef41Sopenharmony_ci  return true;
4701cb0ef41Sopenharmony_ci}
4711cb0ef41Sopenharmony_ci
4721cb0ef41Sopenharmony_cifunction mapHasEqualEntry(set, map, key1, item1, strict, memo) {
4731cb0ef41Sopenharmony_ci  // To be able to handle cases like:
4741cb0ef41Sopenharmony_ci  //   Map([[{}, 'a'], [{}, 'b']]) vs Map([[{}, 'b'], [{}, 'a']])
4751cb0ef41Sopenharmony_ci  // ... we need to consider *all* matching keys, not just the first we find.
4761cb0ef41Sopenharmony_ci  for (const key2 of set) {
4771cb0ef41Sopenharmony_ci    if (innerDeepEqual(key1, key2, strict, memo) &&
4781cb0ef41Sopenharmony_ci      innerDeepEqual(item1, map.get(key2), strict, memo)) {
4791cb0ef41Sopenharmony_ci      set.delete(key2);
4801cb0ef41Sopenharmony_ci      return true;
4811cb0ef41Sopenharmony_ci    }
4821cb0ef41Sopenharmony_ci  }
4831cb0ef41Sopenharmony_ci
4841cb0ef41Sopenharmony_ci  return false;
4851cb0ef41Sopenharmony_ci}
4861cb0ef41Sopenharmony_ci
4871cb0ef41Sopenharmony_cifunction mapEquiv(a, b, strict, memo) {
4881cb0ef41Sopenharmony_ci  let set = null;
4891cb0ef41Sopenharmony_ci
4901cb0ef41Sopenharmony_ci  for (const { 0: key, 1: item1 } of a) {
4911cb0ef41Sopenharmony_ci    if (typeof key === 'object' && key !== null) {
4921cb0ef41Sopenharmony_ci      if (set === null) {
4931cb0ef41Sopenharmony_ci        set = new SafeSet();
4941cb0ef41Sopenharmony_ci      }
4951cb0ef41Sopenharmony_ci      set.add(key);
4961cb0ef41Sopenharmony_ci    } else {
4971cb0ef41Sopenharmony_ci      // By directly retrieving the value we prevent another b.has(key) check in
4981cb0ef41Sopenharmony_ci      // almost all possible cases.
4991cb0ef41Sopenharmony_ci      const item2 = b.get(key);
5001cb0ef41Sopenharmony_ci      if (((item2 === undefined && !b.has(key)) ||
5011cb0ef41Sopenharmony_ci          !innerDeepEqual(item1, item2, strict, memo))) {
5021cb0ef41Sopenharmony_ci        if (strict)
5031cb0ef41Sopenharmony_ci          return false;
5041cb0ef41Sopenharmony_ci        // Fast path to detect missing string, symbol, undefined and null
5051cb0ef41Sopenharmony_ci        // keys.
5061cb0ef41Sopenharmony_ci        if (!mapMightHaveLoosePrim(a, b, key, item1, memo))
5071cb0ef41Sopenharmony_ci          return false;
5081cb0ef41Sopenharmony_ci        if (set === null) {
5091cb0ef41Sopenharmony_ci          set = new SafeSet();
5101cb0ef41Sopenharmony_ci        }
5111cb0ef41Sopenharmony_ci        set.add(key);
5121cb0ef41Sopenharmony_ci      }
5131cb0ef41Sopenharmony_ci    }
5141cb0ef41Sopenharmony_ci  }
5151cb0ef41Sopenharmony_ci
5161cb0ef41Sopenharmony_ci  if (set !== null) {
5171cb0ef41Sopenharmony_ci    for (const { 0: key, 1: item } of b) {
5181cb0ef41Sopenharmony_ci      if (typeof key === 'object' && key !== null) {
5191cb0ef41Sopenharmony_ci        if (!mapHasEqualEntry(set, a, key, item, strict, memo))
5201cb0ef41Sopenharmony_ci          return false;
5211cb0ef41Sopenharmony_ci      } else if (!strict &&
5221cb0ef41Sopenharmony_ci                 (!a.has(key) ||
5231cb0ef41Sopenharmony_ci                   !innerDeepEqual(a.get(key), item, false, memo)) &&
5241cb0ef41Sopenharmony_ci                 !mapHasEqualEntry(set, a, key, item, false, memo)) {
5251cb0ef41Sopenharmony_ci        return false;
5261cb0ef41Sopenharmony_ci      }
5271cb0ef41Sopenharmony_ci    }
5281cb0ef41Sopenharmony_ci    return set.size === 0;
5291cb0ef41Sopenharmony_ci  }
5301cb0ef41Sopenharmony_ci
5311cb0ef41Sopenharmony_ci  return true;
5321cb0ef41Sopenharmony_ci}
5331cb0ef41Sopenharmony_ci
5341cb0ef41Sopenharmony_cifunction objEquiv(a, b, strict, keys, memos, iterationType) {
5351cb0ef41Sopenharmony_ci  // Sets and maps don't have their entries accessible via normal object
5361cb0ef41Sopenharmony_ci  // properties.
5371cb0ef41Sopenharmony_ci  let i = 0;
5381cb0ef41Sopenharmony_ci
5391cb0ef41Sopenharmony_ci  if (iterationType === kIsSet) {
5401cb0ef41Sopenharmony_ci    if (!setEquiv(a, b, strict, memos)) {
5411cb0ef41Sopenharmony_ci      return false;
5421cb0ef41Sopenharmony_ci    }
5431cb0ef41Sopenharmony_ci  } else if (iterationType === kIsMap) {
5441cb0ef41Sopenharmony_ci    if (!mapEquiv(a, b, strict, memos)) {
5451cb0ef41Sopenharmony_ci      return false;
5461cb0ef41Sopenharmony_ci    }
5471cb0ef41Sopenharmony_ci  } else if (iterationType === kIsArray) {
5481cb0ef41Sopenharmony_ci    for (; i < a.length; i++) {
5491cb0ef41Sopenharmony_ci      if (ObjectPrototypeHasOwnProperty(a, i)) {
5501cb0ef41Sopenharmony_ci        if (!ObjectPrototypeHasOwnProperty(b, i) ||
5511cb0ef41Sopenharmony_ci            !innerDeepEqual(a[i], b[i], strict, memos)) {
5521cb0ef41Sopenharmony_ci          return false;
5531cb0ef41Sopenharmony_ci        }
5541cb0ef41Sopenharmony_ci      } else if (ObjectPrototypeHasOwnProperty(b, i)) {
5551cb0ef41Sopenharmony_ci        return false;
5561cb0ef41Sopenharmony_ci      } else {
5571cb0ef41Sopenharmony_ci        // Array is sparse.
5581cb0ef41Sopenharmony_ci        const keysA = ObjectKeys(a);
5591cb0ef41Sopenharmony_ci        for (; i < keysA.length; i++) {
5601cb0ef41Sopenharmony_ci          const key = keysA[i];
5611cb0ef41Sopenharmony_ci          if (!ObjectPrototypeHasOwnProperty(b, key) ||
5621cb0ef41Sopenharmony_ci              !innerDeepEqual(a[key], b[key], strict, memos)) {
5631cb0ef41Sopenharmony_ci            return false;
5641cb0ef41Sopenharmony_ci          }
5651cb0ef41Sopenharmony_ci        }
5661cb0ef41Sopenharmony_ci        if (keysA.length !== ObjectKeys(b).length) {
5671cb0ef41Sopenharmony_ci          return false;
5681cb0ef41Sopenharmony_ci        }
5691cb0ef41Sopenharmony_ci        return true;
5701cb0ef41Sopenharmony_ci      }
5711cb0ef41Sopenharmony_ci    }
5721cb0ef41Sopenharmony_ci  }
5731cb0ef41Sopenharmony_ci
5741cb0ef41Sopenharmony_ci  // The pair must have equivalent values for every corresponding key.
5751cb0ef41Sopenharmony_ci  // Possibly expensive deep test:
5761cb0ef41Sopenharmony_ci  for (i = 0; i < keys.length; i++) {
5771cb0ef41Sopenharmony_ci    const key = keys[i];
5781cb0ef41Sopenharmony_ci    if (!innerDeepEqual(a[key], b[key], strict, memos)) {
5791cb0ef41Sopenharmony_ci      return false;
5801cb0ef41Sopenharmony_ci    }
5811cb0ef41Sopenharmony_ci  }
5821cb0ef41Sopenharmony_ci  return true;
5831cb0ef41Sopenharmony_ci}
5841cb0ef41Sopenharmony_ci
5851cb0ef41Sopenharmony_cifunction isDeepEqual(val1, val2) {
5861cb0ef41Sopenharmony_ci  return innerDeepEqual(val1, val2, kLoose);
5871cb0ef41Sopenharmony_ci}
5881cb0ef41Sopenharmony_ci
5891cb0ef41Sopenharmony_cifunction isDeepStrictEqual(val1, val2) {
5901cb0ef41Sopenharmony_ci  return innerDeepEqual(val1, val2, kStrict);
5911cb0ef41Sopenharmony_ci}
5921cb0ef41Sopenharmony_ci
5931cb0ef41Sopenharmony_cimodule.exports = {
5941cb0ef41Sopenharmony_ci  isDeepEqual,
5951cb0ef41Sopenharmony_ci  isDeepStrictEqual,
5961cb0ef41Sopenharmony_ci};
597