const OBJP = Object.getPrototypeOf({});
const FN = "function";
const STR = "string";
const equiv = (a, b) => {
  let proto;
  if (a === b) {
    return true;
  }
  if (a != null) {
    if (typeof a.equiv === FN) {
      return a.equiv(b);
    }
  } else {
    return a == b;
  }
  if (b != null) {
    if (typeof b.equiv === FN) {
      return b.equiv(a);
    }
  } else {
    return a == b;
  }
  if (typeof a === STR || typeof b === STR) {
    return false;
  }
  if ((proto = Object.getPrototypeOf(a), proto == null || proto === OBJP) && (proto = Object.getPrototypeOf(b), proto == null || proto === OBJP)) {
    return equivObject(a, b);
  }
  if (typeof a !== FN && a.length !== void 0 && typeof b !== FN && b.length !== void 0) {
    return equivArrayLike(a, b);
  }
  if (a instanceof Set && b instanceof Set) {
    return equivSet(a, b);
  }
  if (a instanceof Map && b instanceof Map) {
    return equivMap(a, b);
  }
  if (a instanceof Date && b instanceof Date) {
    return a.getTime() === b.getTime();
  }
  if (a instanceof RegExp && b instanceof RegExp) {
    return a.toString() === b.toString();
  }
  return a !== a && b !== b;
};
const equivArrayLike = (a, b, _equiv = equiv) => {
  let l = a.length;
  if (l === b.length) {
    while (l-- > 0 && _equiv(a[l], b[l])) ;
  }
  return l < 0;
};
const equivSet = (a, b, _equiv = equiv) => a.size === b.size && _equiv([...a.keys()].sort(), [...b.keys()].sort());
const equivMap = (a, b, _equiv = equiv) => a.size === b.size && _equiv([...a].sort(), [...b].sort());
const equivObject = (a, b, _equiv = equiv) => {
  if (Object.keys(a).length !== Object.keys(b).length) {
    return false;
  }
  for (let k in a) {
    if (!b.hasOwnProperty(k) || !_equiv(a[k], b[k])) {
      return false;
    }
  }
  return true;
};
export {
  equiv,
  equivArrayLike,
  equivMap,
  equivObject,
  equivSet
};
