mirror of
https://github.com/denoland/std.git
synced 2024-11-21 20:50:22 +00:00
perf(expect): add fast path for primitive keyed collections in equal()
(#5934)
Co-authored-by: Asher Gomez <ashersaupingomez@gmail.com>
This commit is contained in:
parent
43102325b7
commit
38455481a2
@ -5,8 +5,9 @@
|
||||
import type { EqualOptions } from "./_types.ts";
|
||||
import { AsymmetricMatcher } from "./_asymmetric_matchers.ts";
|
||||
|
||||
function isKeyedCollection(x: unknown): x is Set<unknown> {
|
||||
return [Symbol.iterator, "size"].every((k) => k in (x as Set<unknown>));
|
||||
type KeyedCollection = Set<unknown> | Map<unknown, unknown>;
|
||||
function isKeyedCollection(x: unknown): x is KeyedCollection {
|
||||
return x instanceof Set || x instanceof Map;
|
||||
}
|
||||
|
||||
function constructorsEqual(a: object, b: object) {
|
||||
@ -153,6 +154,31 @@ export function equal(c: unknown, d: unknown, options?: EqualOptions): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
const aKeys = [...a.keys()];
|
||||
const primitiveKeysFastPath = aKeys.every((k) => {
|
||||
return typeof k === "string" ||
|
||||
typeof k === "number" ||
|
||||
typeof k === "boolean" ||
|
||||
typeof k === "bigint" ||
|
||||
typeof k === "symbol" ||
|
||||
k == null;
|
||||
});
|
||||
if (primitiveKeysFastPath) {
|
||||
if (a instanceof Set) {
|
||||
return a.symmetricDifference(b).size === 0;
|
||||
}
|
||||
|
||||
for (const key of aKeys) {
|
||||
if (
|
||||
!b.has(key) ||
|
||||
!compare(a.get(key), (b as Map<unknown, unknown>).get(key))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
let unmatchedEntries = a.size;
|
||||
|
||||
for (const [aKey, aValue] of a.entries()) {
|
||||
|
@ -262,3 +262,31 @@ Deno.test("equal() matches when values have circular references", () => {
|
||||
mapB.set("prop", mapB);
|
||||
assert(equal(mapA, mapB));
|
||||
});
|
||||
|
||||
Deno.test("equal() fast path for primitive keyed collections", () => {
|
||||
const arr = Array.from({ length: 10_000 }, (_, i) => i);
|
||||
|
||||
const set1 = new Set(arr);
|
||||
const set2 = new Set(arr);
|
||||
assert(equal(set1, set2));
|
||||
|
||||
const map1 = new Map(arr.map((v) => [v, v]));
|
||||
const map2 = new Map(arr.map((v) => [v, v]));
|
||||
assert(equal(map1, map2));
|
||||
|
||||
const set3 = new Set(arr);
|
||||
const set4 = new Set(arr.with(-1, -1));
|
||||
assertFalse(equal(set3, set4));
|
||||
|
||||
// entries [...] 9998 => 9998, 9999 => 9999
|
||||
const map3 = new Map(arr.map((v) => [v, v]));
|
||||
// entries [...] 9998 => 9998, -1 => -1
|
||||
const map4 = new Map(arr.with(-1, -1).map((v) => [v, v]));
|
||||
assertFalse(equal(map3, map4));
|
||||
|
||||
// entries [...] 9998 => 9998, 9999 => 9999
|
||||
const map5 = new Map(arr.map((v, i) => [i, v]));
|
||||
// entries [...] 9998 => 9998, 9999 => -1
|
||||
const map6 = new Map(arr.with(-1, -1).map((v, i) => [i, v]));
|
||||
assertFalse(equal(map5, map6));
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user