11/* eslint-disable */
2- // Ported from https://github.com/stackblitz/alien-signals/blob/v1.0.4 /src/system.ts
2+ // Ported from https://github.com/stackblitz/alien-signals/blob/v1.0.13 /src/system.ts
33import type { ComputedRefImpl as Computed } from './computed.js'
44import type { ReactiveEffect as Effect } from './effect.js'
55
@@ -32,9 +32,16 @@ export const enum SubscriberFlags {
3232 Propagated = Dirty | PendingComputed ,
3333}
3434
35+ interface OneWayLink < T > {
36+ target : T
37+ linked : OneWayLink < T > | undefined
38+ }
39+
40+ const notifyBuffer : ( Effect | undefined ) [ ] = [ ]
41+
3542let batchDepth = 0
36- let queuedEffects : Effect | undefined
37- let queuedEffectsTail : Effect | undefined
43+ let notifyIndex = 0
44+ let notifyBufferLength = 0
3845
3946export function startBatch ( ) : void {
4047 ++ batchDepth
@@ -67,80 +74,81 @@ export function link(dep: Dependency, sub: Subscriber): Link | undefined {
6774 return linkNewDep ( dep , sub , nextDep , currentDep )
6875}
6976
70- export function propagate ( link : Link ) : void {
77+ export function propagate ( current : Link ) : void {
78+ let next = current . nextSub
79+ let branchs : OneWayLink < Link | undefined > | undefined
80+ let branchDepth = 0
7181 let targetFlag = SubscriberFlags . Dirty
72- let subs = link
73- let stack = 0
7482
7583 top: do {
76- const sub = link . sub
84+ const sub = current . sub
7785 const subFlags = sub . flags
7886
87+ let shouldNotify = false
88+
7989 if (
80- ( ! (
90+ ! (
8191 subFlags &
8292 ( SubscriberFlags . Tracking |
8393 SubscriberFlags . Recursed |
8494 SubscriberFlags . Propagated )
85- ) &&
86- ( ( sub . flags = subFlags | targetFlag ) , true ) ) ||
87- ( subFlags & SubscriberFlags . Recursed &&
88- ! ( subFlags & SubscriberFlags . Tracking ) &&
89- ( ( sub . flags = ( subFlags & ~ SubscriberFlags . Recursed ) | targetFlag ) ,
90- true ) ) ||
91- ( ! ( subFlags & SubscriberFlags . Propagated ) &&
92- isValidLink ( link , sub ) &&
93- ( ( sub . flags = subFlags | SubscriberFlags . Recursed | targetFlag ) ,
94- ( sub as Dependency ) . subs !== undefined ) )
95+ )
96+ ) {
97+ sub . flags = subFlags | targetFlag
98+ shouldNotify = true
99+ } else if (
100+ subFlags & SubscriberFlags . Recursed &&
101+ ! ( subFlags & SubscriberFlags . Tracking )
95102 ) {
103+ sub . flags = ( subFlags & ~ SubscriberFlags . Recursed ) | targetFlag
104+ shouldNotify = true
105+ } else if (
106+ ! ( subFlags & SubscriberFlags . Propagated ) &&
107+ isValidLink ( current , sub )
108+ ) {
109+ sub . flags = subFlags | SubscriberFlags . Recursed | targetFlag
110+ shouldNotify = ( sub as Dependency ) . subs !== undefined
111+ }
112+
113+ if ( shouldNotify ) {
96114 const subSubs = ( sub as Dependency ) . subs
97115 if ( subSubs !== undefined ) {
116+ current = subSubs
98117 if ( subSubs . nextSub !== undefined ) {
99- subSubs . prevSub = subs
100- link = subs = subSubs
101- targetFlag = SubscriberFlags . PendingComputed
102- ++ stack
103- } else {
104- link = subSubs
105- targetFlag = SubscriberFlags . PendingComputed
118+ branchs = { target : next , linked : branchs }
119+ ++ branchDepth
120+ next = current . nextSub
106121 }
122+ targetFlag = SubscriberFlags . PendingComputed
107123 continue
108124 }
109125 if ( subFlags & SubscriberFlags . Effect ) {
110- if ( queuedEffectsTail !== undefined ) {
111- queuedEffectsTail . depsTail ! . nextDep = sub . deps
112- } else {
113- queuedEffects = sub as Effect
114- }
115- queuedEffectsTail = sub as Effect
126+ notifyBuffer [ notifyBufferLength ++ ] = sub as Effect
116127 }
117128 } else if ( ! ( subFlags & ( SubscriberFlags . Tracking | targetFlag ) ) ) {
118129 sub . flags = subFlags | targetFlag
119130 } else if (
120131 ! ( subFlags & targetFlag ) &&
121132 subFlags & SubscriberFlags . Propagated &&
122- isValidLink ( link , sub )
133+ isValidLink ( current , sub )
123134 ) {
124135 sub . flags = subFlags | targetFlag
125136 }
126137
127- if ( ( link = subs . nextSub ! ) !== undefined ) {
128- subs = link
129- targetFlag = stack
138+ if ( ( current = next ! ) !== undefined ) {
139+ next = current . nextSub
140+ targetFlag = branchDepth
130141 ? SubscriberFlags . PendingComputed
131142 : SubscriberFlags . Dirty
132143 continue
133144 }
134145
135- while ( stack ) {
136- -- stack
137- const dep = subs . dep
138- const depSubs = dep . subs !
139- subs = depSubs . prevSub !
140- depSubs . prevSub = undefined
141- if ( ( link = subs . nextSub ! ) !== undefined ) {
142- subs = link
143- targetFlag = stack
146+ while ( branchDepth -- ) {
147+ current = branchs ! . target !
148+ branchs = branchs ! . linked
149+ if ( current !== undefined ) {
150+ next = current . nextSub
151+ targetFlag = branchDepth
144152 ? SubscriberFlags . PendingComputed
145153 : SubscriberFlags . Dirty
146154 continue top
@@ -194,35 +202,26 @@ export function processComputedUpdate(
194202 computed : Computed ,
195203 flags : SubscriberFlags ,
196204) : void {
197- if (
198- flags & SubscriberFlags . Dirty ||
199- ( checkDirty ( computed . deps ! )
200- ? true
201- : ( ( computed . flags = flags & ~ SubscriberFlags . PendingComputed ) , false ) )
202- ) {
205+ if ( flags & SubscriberFlags . Dirty || checkDirty ( computed . deps ! ) ) {
203206 if ( computed . update ( ) ) {
204207 const subs = computed . subs
205208 if ( subs !== undefined ) {
206209 shallowPropagate ( subs )
207210 }
208211 }
212+ } else {
213+ computed . flags = flags & ~ SubscriberFlags . PendingComputed
209214 }
210215}
211216
212217export function processEffectNotifications ( ) : void {
213- while ( queuedEffects !== undefined ) {
214- const effect = queuedEffects
215- const depsTail = effect . depsTail !
216- const queuedNext = depsTail . nextDep
217- if ( queuedNext !== undefined ) {
218- depsTail . nextDep = undefined
219- queuedEffects = queuedNext . sub as Effect
220- } else {
221- queuedEffects = undefined
222- queuedEffectsTail = undefined
223- }
218+ while ( notifyIndex < notifyBufferLength ) {
219+ const effect = notifyBuffer [ notifyIndex ] !
220+ notifyBuffer [ notifyIndex ++ ] = undefined
224221 effect . notify ( )
225222 }
223+ notifyIndex = 0
224+ notifyBufferLength = 0
226225}
227226
228227function linkNewDep (
@@ -259,15 +258,18 @@ function linkNewDep(
259258 return newLink
260259}
261260
262- function checkDirty ( link : Link ) : boolean {
263- let stack = 0
261+ function checkDirty ( current : Link ) : boolean {
262+ let prevLinks : OneWayLink < Link > | undefined
263+ let checkDepth = 0
264264 let dirty : boolean
265265
266266 top: do {
267267 dirty = false
268- const dep = link . dep
268+ const dep = current . dep
269269
270- if ( 'flags' in dep ) {
270+ if ( current . sub . flags & SubscriberFlags . Dirty ) {
271+ dirty = true
272+ } else if ( 'flags' in dep ) {
271273 const depFlags = dep . flags
272274 if (
273275 ( depFlags & ( SubscriberFlags . Computed | SubscriberFlags . Dirty ) ) ===
@@ -285,58 +287,49 @@ function checkDirty(link: Link): boolean {
285287 ( SubscriberFlags . Computed | SubscriberFlags . PendingComputed ) ) ===
286288 ( SubscriberFlags . Computed | SubscriberFlags . PendingComputed )
287289 ) {
288- const depSubs = dep . subs !
289- if ( depSubs . nextSub !== undefined ) {
290- depSubs . prevSub = link
290+ if ( current . nextSub !== undefined || current . prevSub !== undefined ) {
291+ prevLinks = { target : current , linked : prevLinks }
291292 }
292- link = dep . deps !
293- ++ stack
293+ current = dep . deps !
294+ ++ checkDepth
294295 continue
295296 }
296297 }
297298
298- if ( ! dirty && link . nextDep !== undefined ) {
299- link = link . nextDep
299+ if ( ! dirty && current . nextDep !== undefined ) {
300+ current = current . nextDep
300301 continue
301302 }
302303
303- if ( stack ) {
304- let sub = link . sub as Computed
305- do {
306- -- stack
307- const subSubs = sub . subs !
308-
309- if ( dirty ) {
310- if ( sub . update ( ) ) {
311- if ( ( link = subSubs . prevSub ! ) !== undefined ) {
312- subSubs . prevSub = undefined
313- shallowPropagate ( subSubs )
314- sub = link . sub as Computed
315- } else {
316- sub = subSubs . sub as Computed
317- }
318- continue
319- }
320- } else {
321- sub . flags &= ~ SubscriberFlags . PendingComputed
322- }
323-
324- if ( ( link = subSubs . prevSub ! ) !== undefined ) {
325- subSubs . prevSub = undefined
326- if ( link . nextDep !== undefined ) {
327- link = link . nextDep
328- continue top
329- }
330- sub = link . sub as Computed
331- } else {
332- if ( ( link = subSubs . nextDep ! ) !== undefined ) {
333- continue top
304+ while ( checkDepth ) {
305+ -- checkDepth
306+ const sub = current . sub as Computed
307+ const firstSub = sub . subs !
308+ if ( dirty ) {
309+ if ( sub . update ( ) ) {
310+ if ( firstSub . nextSub !== undefined ) {
311+ current = prevLinks ! . target
312+ prevLinks = prevLinks ! . linked
313+ shallowPropagate ( firstSub )
314+ } else {
315+ current = firstSub
334316 }
335- sub = subSubs . sub as Computed
317+ continue
336318 }
337-
338- dirty = false
339- } while ( stack )
319+ } else {
320+ sub . flags &= ~ SubscriberFlags . PendingComputed
321+ }
322+ if ( firstSub . nextSub !== undefined ) {
323+ current = prevLinks ! . target
324+ prevLinks = prevLinks ! . linked
325+ } else {
326+ current = firstSub
327+ }
328+ if ( current . nextDep !== undefined ) {
329+ current = current . nextDep
330+ continue top
331+ }
332+ dirty = false
340333 }
341334
342335 return dirty
0 commit comments