typia
Version:
Superfast runtime validators with only one line
79 lines (78 loc) • 4.38 kB
JavaScript
//#region src/internal/_isUniqueItems.ts
const _isUniqueItems = (elements) => {
for (let i = 0; i < elements.length; i++) for (let j = i + 1; j < elements.length; j++) if (equals(/* @__PURE__ */ new WeakMap())(elements[i], elements[j])) return false;
return true;
};
const equals = (visited) => {
const next = (a, b) => {
if (a === b) return true;
if (a === null || b === null || typeof a !== "object" || typeof b !== "object") return false;
const previous = visited.get(a)?.get(b);
if (previous !== void 0) return previous;
const pairs = visited.get(a) ?? /* @__PURE__ */ new WeakMap();
visited.set(a, pairs);
pairs.set(b, true);
const result = compare(a, b);
pairs.set(b, result);
return result;
};
const compare = (a, b) => {
if (Array.isArray(a)) {
if (!Array.isArray(b) || a.length !== b.length) return false;
for (let i = 0; i < a.length; i++) {
const aHas = Object.hasOwn(a, i);
if (aHas !== Object.hasOwn(b, i) || aHas && !next(a[i], b[i])) return false;
}
return true;
}
if (Array.isArray(b)) return false;
if (a instanceof Set) {
if (!(b instanceof Set) || a.size !== b.size) return false;
const unmatched = [...b];
for (const value of a) {
const index = unmatched.findIndex((candidate) => next(value, candidate));
if (index === -1) return false;
unmatched.splice(index, 1);
}
return true;
}
if (a instanceof Map) {
if (!(b instanceof Map) || a.size !== b.size) return false;
const unmatched = [...b];
for (const [key, value] of a) {
const index = unmatched.findIndex(([candidateKey, candidateValue]) => next(key, candidateKey) && next(value, candidateValue));
if (index === -1) return false;
unmatched.splice(index, 1);
}
return true;
}
if (a instanceof Boolean) return b instanceof Boolean && a.valueOf() === b.valueOf();
if (Object.prototype.toString.call(a) === "[object BigInt]") return Object.prototype.toString.call(b) === "[object BigInt]" && a.valueOf() === b.valueOf();
if (Object.prototype.toString.call(a) === "[object Symbol]") return Object.prototype.toString.call(b) === "[object Symbol]" && a.valueOf() === b.valueOf();
if (a instanceof Number) return b instanceof Number && a.valueOf() === b.valueOf();
if (a instanceof String) return b instanceof String && a.valueOf() === b.valueOf();
if (a instanceof Date) return b instanceof Date && a.getTime() === b.getTime();
if (a instanceof RegExp) return b instanceof RegExp && a.source === b.source && a.flags === b.flags;
if (typeof File !== "undefined" && a instanceof File) return b instanceof File && a.name === b.name && a.size === b.size && a.type === b.type && a.lastModified === b.lastModified;
if (typeof Blob !== "undefined" && a instanceof Blob) return b instanceof Blob && a.size === b.size && a.type === b.type;
if (a instanceof DataView) {
if (!(b instanceof DataView) || a.byteLength !== b.byteLength) return false;
return bytes(a.buffer, a.byteOffset, a.byteLength).every((value, index) => value === bytes(b.buffer, b.byteOffset, b.byteLength)[index]);
}
if (ArrayBuffer.isView(a)) {
if (!ArrayBuffer.isView(b) || b instanceof DataView || Object.getPrototypeOf(a) !== Object.getPrototypeOf(b) || a.byteLength !== b.byteLength) return false;
const x = bytes(a.buffer, a.byteOffset, a.byteLength);
const y = bytes(b.buffer, b.byteOffset, b.byteLength);
return x.every((value, index) => value === y[index]);
}
if (a instanceof ArrayBuffer) return b instanceof ArrayBuffer && a.byteLength === b.byteLength && bytes(a).every((value, index) => value === bytes(b)[index]);
if (typeof SharedArrayBuffer !== "undefined" && a instanceof SharedArrayBuffer) return b instanceof SharedArrayBuffer && a.byteLength === b.byteLength && bytes(a).every((value, index) => value === bytes(b)[index]);
const keys = Reflect.ownKeys(a).filter((key) => Object.prototype.propertyIsEnumerable.call(a, key));
return keys.length === Reflect.ownKeys(b).filter((key) => Object.prototype.propertyIsEnumerable.call(b, key)).length && keys.every((key) => Object.prototype.propertyIsEnumerable.call(b, key) && next(a[key], b[key]));
};
return next;
};
const bytes = (buffer, byteOffset = 0, byteLength = buffer.byteLength) => new Uint8Array(buffer, byteOffset, byteLength);
//#endregion
export { _isUniqueItems };
//# sourceMappingURL=_isUniqueItems.mjs.map