Skip to content

Commit

Permalink
faster iteration experiment
Browse files Browse the repository at this point in the history
  • Loading branch information
mweststrate committed Apr 27, 2024
1 parent 511ccee commit 52c2fe5
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 30 deletions.
16 changes: 10 additions & 6 deletions src/core/current.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,22 @@ function currentImpl(value: any): any {
if (!isDraftable(value) || isFrozen(value)) return value
const state: ImmerState | undefined = value[DRAFT_STATE]
let copy: any
let strict = true // we might not know, so true just to be safe
if (state) {
if (!state.modified_) return state.base_
// Optimization: avoid generating new drafts during copying
state.finalized_ = true
copy = shallowCopy(value, state.scope_.immer_.useStrictShallowCopy_)
} else {
copy = shallowCopy(value, true)
strict = state.scope_.immer_.useStrict_(value)
}
copy = shallowCopy(value, strict)
// recurse
each(copy, (key, childValue) => {
set(copy, key, currentImpl(childValue))
})
each(
copy,
(key, childValue) => {
set(copy, key, currentImpl(childValue))
},
strict
)
if (state) {
state.finalized_ = false
}
Expand Down
22 changes: 18 additions & 4 deletions src/core/finalize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,11 @@ function finalize(rootScope: ImmerScope, value: any, path?: PatchPath) {
const state: ImmerState = value[DRAFT_STATE]
// A plain object, might need freezing, might contain drafts
if (!state) {
each(value, (key, childValue) =>
finalizeProperty(rootScope, state, value, key, childValue, path)
each(
value,
(key, childValue) =>
finalizeProperty(rootScope, state, value, key, childValue, path),
rootScope.immer_.useStrict_(value)
)
return value
}
Expand All @@ -86,8 +89,19 @@ function finalize(rootScope: ImmerScope, value: any, path?: PatchPath) {
result.clear()
isSet = true
}
each(resultEach, (key, childValue) =>
finalizeProperty(rootScope, state, result, key, childValue, path, isSet)
each(
resultEach,
(key, childValue) =>
finalizeProperty(
rootScope,
state,
result,
key,
childValue,
path,
isSet
),
state.scope_.immer_.useStrict_(resultEach)
)
// everything inside is frozen, we can freeze here
maybeFreeze(rootScope, result, false)
Expand Down
12 changes: 10 additions & 2 deletions src/core/immerClass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,16 @@ import {
getCurrentScope,
NOTHING,
freeze,
current
current,
isPlainObject
} from "../internal"

interface ProducersFns {
produce: IProduce
produceWithPatches: IProduceWithPatches
}

export type StrictMode = boolean | "class_only";
export type StrictMode = boolean | "class_only"

export class Immer implements ProducersFns {
autoFreeze_: boolean = true
Expand Down Expand Up @@ -199,6 +200,13 @@ export class Immer implements ProducersFns {
applyPatchesImpl(draft, patches)
)
}

useStrict_(obj: any): boolean {
return (
this.useStrictShallowCopy_ === true ||
(this.useStrictShallowCopy_ === "class_only" && !isPlainObject(obj))
)
}
}

export function createProxy<T extends Objectish>(
Expand Down
34 changes: 19 additions & 15 deletions src/plugins/patches.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,21 +132,25 @@ export function enablePatches() {
inversePatches: Patch[]
) {
const {base_, copy_} = state
each(state.assigned_!, (key, assignedValue) => {
const origValue = get(base_, key)
const value = get(copy_!, key)
const op = !assignedValue ? REMOVE : has(base_, key) ? REPLACE : ADD
if (origValue === value && op === REPLACE) return
const path = basePath.concat(key as any)
patches.push(op === REMOVE ? {op, path} : {op, path, value})
inversePatches.push(
op === ADD
? {op: REMOVE, path}
: op === REMOVE
? {op: ADD, path, value: clonePatchValueIfNeeded(origValue)}
: {op: REPLACE, path, value: clonePatchValueIfNeeded(origValue)}
)
})
each(
state.assigned_!,
(key, assignedValue) => {
const origValue = get(base_, key)
const value = get(copy_!, key)
const op = !assignedValue ? REMOVE : has(base_, key) ? REPLACE : ADD
if (origValue === value && op === REPLACE) return
const path = basePath.concat(key as any)
patches.push(op === REMOVE ? {op, path} : {op, path, value})
inversePatches.push(
op === ADD
? {op: REMOVE, path}
: op === REMOVE
? {op: ADD, path, value: clonePatchValueIfNeeded(origValue)}
: {op: REPLACE, path, value: clonePatchValueIfNeeded(origValue)}
)
},
state.scope_.immer_.useStrict_(base_)
)
}

function generateSetPatches(
Expand Down
8 changes: 5 additions & 3 deletions src/utils/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,13 @@ export function original(value: Drafted<any>): any {
*/
export function each<T extends Objectish>(
obj: T,
iter: (key: string | number, value: any, source: T) => void
iter: (key: string | number, value: any, source: T) => void,
strict?: boolean
): void
export function each(obj: any, iter: any) {
export function each(obj: any, iter: any, strict: boolean = true) {
if (getArchtype(obj) === ArchType.Object) {
Reflect.ownKeys(obj).forEach(key => {
const keys = strict ? Reflect.ownKeys(obj) : Object.keys(obj)
keys.forEach(key => {
iter(key, obj[key], obj)
})
} else {
Expand Down

0 comments on commit 52c2fe5

Please sign in to comment.