Skip to content

Commit 0efea92

Browse files
committed
feat: implement HybridMap class and createHybridMap function
fix: ensure firstKey is non-null in memorizeFn cache eviction
1 parent bb9e05d commit 0efea92

File tree

3 files changed

+107
-1
lines changed

3 files changed

+107
-1
lines changed

src/perf/createHybridMap.ts

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
type Primitive = string | number | symbol | boolean | null | undefined
2+
type KeyType = object | Primitive
3+
4+
export class HybridMap<K extends KeyType, V> {
5+
private objectStore: WeakMap<object, V>
6+
private primitiveStore: Map<Primitive, V>
7+
8+
constructor(entries?: readonly (readonly [K, V])[] | null) {
9+
this.objectStore = new WeakMap()
10+
this.primitiveStore = new Map()
11+
if (entries) {
12+
for (const [k, v] of entries) {
13+
this.set(k, v)
14+
}
15+
}
16+
}
17+
18+
private isObjectKey(key: K): key is Record<any, any> {
19+
return typeof key === 'object' && key !== null
20+
}
21+
22+
set(key: K, value: V): this {
23+
if (this.isObjectKey(key)) {
24+
this.objectStore.set(key, value)
25+
}
26+
else {
27+
this.primitiveStore.set(key as Primitive, value)
28+
}
29+
return this
30+
}
31+
32+
get(key: K): V | undefined {
33+
if (this.isObjectKey(key)) {
34+
return this.objectStore.get(key as object)
35+
}
36+
else {
37+
return this.primitiveStore.get(key as Primitive)
38+
}
39+
}
40+
41+
has(key: K): boolean {
42+
if (this.isObjectKey(key)) {
43+
return this.objectStore.has(key as object)
44+
}
45+
else {
46+
return this.primitiveStore.has(key as Primitive)
47+
}
48+
}
49+
50+
delete(key: K): boolean {
51+
if (this.isObjectKey(key)) {
52+
return this.objectStore.delete(key as object)
53+
}
54+
else {
55+
return this.primitiveStore.delete(key as Primitive)
56+
}
57+
}
58+
59+
clear(): void {
60+
this.primitiveStore.clear()
61+
this.objectStore = new WeakMap()
62+
}
63+
64+
get size(): number {
65+
throw new Error(
66+
'HybridMap does not support size due to WeakMap limitations.',
67+
)
68+
}
69+
70+
forEach(): void {
71+
throw new Error(
72+
'HybridMap does not support forEach due to WeakMap limitations.',
73+
)
74+
}
75+
76+
keys() {
77+
throw new Error(
78+
'HybridMap does not support iteration due to WeakMap limitations.',
79+
)
80+
}
81+
82+
values() {
83+
throw new Error(
84+
'HybridMap does not support iteration due to WeakMap limitations.',
85+
)
86+
}
87+
88+
entries() {
89+
throw new Error(
90+
'HybridMap does not support iteration due to WeakMap limitations.',
91+
)
92+
}
93+
94+
[Symbol.iterator]() {
95+
throw new Error(
96+
'HybridMap does not support iteration due to WeakMap limitations.',
97+
)
98+
}
99+
}
100+
101+
export function createHybridMap<K extends KeyType, V>(
102+
entries?: readonly (readonly [K, V])[] | null,
103+
): HybridMap<K, V> {
104+
return new HybridMap(entries)
105+
}

src/perf/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ export * from './useRaf'
1010
export * from './useRic'
1111
export * from './once'
1212
export * from './createChunk'
13+
export * from './createHybridMap'

src/perf/memorizeFn.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export function memorizeFn(
2626

2727
// 检查缓存大小,如果达到最大值,删除最早的条目(Map的第一个条目)
2828
if (cache.size >= maxSize) {
29-
const firstKey = cache.keys().next().value
29+
const firstKey = cache.keys().next().value!
3030
cache.delete(firstKey)
3131
}
3232

0 commit comments

Comments
 (0)