Skip to content

Commit

Permalink
refactor proxyMap&Set
Browse files Browse the repository at this point in the history
  • Loading branch information
dai-shi committed Oct 15, 2024
1 parent 98ae310 commit 5759902
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 39 deletions.
14 changes: 5 additions & 9 deletions src/vanilla/utils/proxyMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export function proxyMap<K, V>(entries?: Iterable<[K, V]> | undefined | null) {
const initialData: Array<K | V> = []
let initialIndex = 0
const indexMap = new Map<K, number>()

const snapMapCache = new WeakMap<object, Map<K, number>>()
const registerSnapMap = () => {
const cache = snapCache.get(vObject)
Expand All @@ -33,7 +34,7 @@ export function proxyMap<K, V>(entries?: Iterable<[K, V]> | undefined | null) {
}
const getSnapMap = (x: any) => snapMapCache.get(x)

if (entries !== null && typeof entries !== 'undefined') {
if (entries) {
if (typeof entries[Symbol.iterator] !== 'function') {
throw new TypeError(
'proxyMap:\n\tinitial state must be iterable\n\t\ttip: structure should be [[key, value]]',
Expand Down Expand Up @@ -97,7 +98,6 @@ export function proxyMap<K, V>(entries?: Iterable<[K, V]> | undefined | null) {
this.data[nextIndex++] = v
this.index = nextIndex
}

return this
},
delete(key: K) {
Expand All @@ -109,7 +109,6 @@ export function proxyMap<K, V>(entries?: Iterable<[K, V]> | undefined | null) {
if (index === undefined) {
return false
}

delete this.data[index]
delete this.data[index + 1]
indexMap.delete(k)
Expand All @@ -119,9 +118,9 @@ export function proxyMap<K, V>(entries?: Iterable<[K, V]> | undefined | null) {
if (!isProxy(this)) {
throw new Error('Cannot perform mutations on a snapshot')
}
indexMap.clear()
this.data.length = 0 // empty array
this.index = 0
this.data.length = 0
indexMap.clear()
},
forEach(cb: (value: V, key: K, map: Map<K, V>) => void) {
const map = getSnapMap(this) || indexMap
Expand Down Expand Up @@ -154,20 +153,17 @@ export function proxyMap<K, V>(entries?: Iterable<[K, V]> | undefined | null) {
return 'Map'
},
toJSON(): Map<K, V> {
const map = getSnapMap(this) || indexMap
return new Map([...map].map(([k, i]) => [k, this.data[i + 1] as V]))
return new Map(this.entries())
},
}

const proxiedObject = proxy(vObject)

Object.defineProperties(proxiedObject, {
size: { enumerable: false },
index: { enumerable: false },
data: { enumerable: false },
toJSON: { enumerable: false },
})

Object.seal(proxiedObject)

return proxiedObject as unknown as Map<K, V> & {
Expand Down
51 changes: 21 additions & 30 deletions src/vanilla/utils/proxySet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export function proxySet<T>(initialValues?: Iterable<T> | null) {
const initialData: T[] = []
const indexMap = new Map<T, number>()
let initialIndex = 0

const snapMapCache = new WeakMap<object, Map<T, number>>()
const registerSnapMap = () => {
const cache = snapCache.get(vObject)
Expand All @@ -33,7 +34,7 @@ export function proxySet<T>(initialValues?: Iterable<T> | null) {
}
const getSnapMap = (x: any) => snapMapCache.get(x)

if (initialValues !== null && typeof initialValues !== 'undefined') {
if (initialValues) {
if (typeof initialValues[Symbol.iterator] !== 'function') {
throw new TypeError('not iterable')
}
Expand All @@ -55,6 +56,16 @@ export function proxySet<T>(initialValues?: Iterable<T> | null) {
}
return indexMap.size
},
has(v: T) {
const map = getSnapMap(this) || indexMap
const value = maybeProxify(v)
const exists = map.has(value)
if (!exists && !isProxy(this)) {
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
this.index
}
return exists
},
add(value: T) {
if (!isProxy(this)) {
throw new Error('Cannot perform mutations on a snapshot')
Expand All @@ -64,6 +75,7 @@ export function proxySet<T>(initialValues?: Iterable<T> | null) {
let nextIndex = this.index
indexMap.set(v, nextIndex)
this.data[nextIndex++] = v
this.index = nextIndex
}
return this
},
Expand All @@ -76,7 +88,6 @@ export function proxySet<T>(initialValues?: Iterable<T> | null) {
if (index === undefined) {
return false
}

delete this.data[index]
indexMap.delete(v)
return true
Expand All @@ -85,46 +96,34 @@ export function proxySet<T>(initialValues?: Iterable<T> | null) {
if (!isProxy(this)) {
throw new Error('Cannot perform mutations on a snapshot')
}
this.data.length = 0
this.data.length = 0 // empty array
this.index = 0
indexMap.clear()
},
forEach(cb) {
const set = getSnapMap(this) || indexMap
set.forEach((index) => {
const map = getSnapMap(this) || indexMap
map.forEach((index) => {
cb(this.data[index]!, this.data[index]!, this)
})
},
has(v: T) {
const iMap = getSnapMap(this) || indexMap
const value = maybeProxify(v)
const exists = iMap.has(value)
if (!exists && !isProxy(this)) {
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
this.index
}
return exists
},
*values(): IterableIterator<T> {
const iMap = getSnapMap(this) || indexMap
for (const index of iMap.values()) {
const map = getSnapMap(this) || indexMap
for (const index of map.values()) {
yield this.data[index]!
}
},
keys(): IterableIterator<T> {
return this.values()
},
*entries(): IterableIterator<[T, T]> {
const iMap = getSnapMap(this) || indexMap
for (const index of iMap.values()) {
const map = getSnapMap(this) || indexMap
for (const index of map.values()) {
const value = this.data[index]!
yield [value, value]
}
},
toJSON(): Set<T> {
// filtering is about twice as fast as creating a new set and deleting
// the undefined value because filter actually skips empty slots
return new Set(this.data.filter((v) => v !== undefined) as T[])
return new Set(this.values())
},
[Symbol.iterator]() {
return this.values()
Expand All @@ -135,13 +134,11 @@ export function proxySet<T>(initialValues?: Iterable<T> | null) {
intersection(other: Set<T>): Set<T> {
const otherSet = proxySet<T>(other)
const resultSet = proxySet<T>()

for (const value of this.values()) {
if (otherSet.has(value)) {
resultSet.add(value)
}
}

return proxySet(resultSet)
},
isDisjointFrom(other: Set<T>): boolean {
Expand All @@ -168,38 +165,32 @@ export function proxySet<T>(initialValues?: Iterable<T> | null) {
symmetricDifference(other: Set<T>) {
const resultSet = proxySet<T>()
const otherSet = proxySet<T>(other)

for (const value of this.values()) {
if (!otherSet.has(value)) {
resultSet.add(value)
}
}

return proxySet(resultSet)
},
union(other: Set<T>) {
const resultSet = proxySet<T>()
const otherSet = proxySet<T>(other)

for (const value of this.values()) {
resultSet.add(value)
}
for (const value of otherSet) {
resultSet.add(value)
}

return proxySet(resultSet)
},
}

const proxiedObject = proxy(vObject)

Object.defineProperties(proxiedObject, {
size: { enumerable: false },
data: { enumerable: false },
toJSON: { enumerable: false },
})

Object.seal(proxiedObject)

return proxiedObject as unknown as InternalProxySet<T> & {
Expand Down

0 comments on commit 5759902

Please sign in to comment.