1
1
/* 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
3
3
import type { ComputedRefImpl as Computed } from './computed.js'
4
4
import type { ReactiveEffect as Effect } from './effect.js'
5
5
@@ -32,9 +32,16 @@ export const enum SubscriberFlags {
32
32
Propagated = Dirty | PendingComputed ,
33
33
}
34
34
35
+ interface OneWayLink < T > {
36
+ target : T
37
+ linked : OneWayLink < T > | undefined
38
+ }
39
+
40
+ const notifyBuffer : ( Effect | undefined ) [ ] = [ ]
41
+
35
42
let batchDepth = 0
36
- let queuedEffects : Effect | undefined
37
- let queuedEffectsTail : Effect | undefined
43
+ let notifyIndex = 0
44
+ let notifyBufferLength = 0
38
45
39
46
export function startBatch ( ) : void {
40
47
++ batchDepth
@@ -67,80 +74,81 @@ export function link(dep: Dependency, sub: Subscriber): Link | undefined {
67
74
return linkNewDep ( dep , sub , nextDep , currentDep )
68
75
}
69
76
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
71
81
let targetFlag = SubscriberFlags . Dirty
72
- let subs = link
73
- let stack = 0
74
82
75
83
top: do {
76
- const sub = link . sub
84
+ const sub = current . sub
77
85
const subFlags = sub . flags
78
86
87
+ let shouldNotify = false
88
+
79
89
if (
80
- ( ! (
90
+ ! (
81
91
subFlags &
82
92
( SubscriberFlags . Tracking |
83
93
SubscriberFlags . Recursed |
84
94
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 )
95
102
) {
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 ) {
96
114
const subSubs = ( sub as Dependency ) . subs
97
115
if ( subSubs !== undefined ) {
116
+ current = subSubs
98
117
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
106
121
}
122
+ targetFlag = SubscriberFlags . PendingComputed
107
123
continue
108
124
}
109
125
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
116
127
}
117
128
} else if ( ! ( subFlags & ( SubscriberFlags . Tracking | targetFlag ) ) ) {
118
129
sub . flags = subFlags | targetFlag
119
130
} else if (
120
131
! ( subFlags & targetFlag ) &&
121
132
subFlags & SubscriberFlags . Propagated &&
122
- isValidLink ( link , sub )
133
+ isValidLink ( current , sub )
123
134
) {
124
135
sub . flags = subFlags | targetFlag
125
136
}
126
137
127
- if ( ( link = subs . nextSub ! ) !== undefined ) {
128
- subs = link
129
- targetFlag = stack
138
+ if ( ( current = next ! ) !== undefined ) {
139
+ next = current . nextSub
140
+ targetFlag = branchDepth
130
141
? SubscriberFlags . PendingComputed
131
142
: SubscriberFlags . Dirty
132
143
continue
133
144
}
134
145
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
144
152
? SubscriberFlags . PendingComputed
145
153
: SubscriberFlags . Dirty
146
154
continue top
@@ -194,35 +202,26 @@ export function processComputedUpdate(
194
202
computed : Computed ,
195
203
flags : SubscriberFlags ,
196
204
) : 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 ! ) ) {
203
206
if ( computed . update ( ) ) {
204
207
const subs = computed . subs
205
208
if ( subs !== undefined ) {
206
209
shallowPropagate ( subs )
207
210
}
208
211
}
212
+ } else {
213
+ computed . flags = flags & ~ SubscriberFlags . PendingComputed
209
214
}
210
215
}
211
216
212
217
export 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
224
221
effect . notify ( )
225
222
}
223
+ notifyIndex = 0
224
+ notifyBufferLength = 0
226
225
}
227
226
228
227
function linkNewDep (
@@ -259,15 +258,18 @@ function linkNewDep(
259
258
return newLink
260
259
}
261
260
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
264
264
let dirty : boolean
265
265
266
266
top: do {
267
267
dirty = false
268
- const dep = link . dep
268
+ const dep = current . dep
269
269
270
- if ( 'flags' in dep ) {
270
+ if ( current . sub . flags & SubscriberFlags . Dirty ) {
271
+ dirty = true
272
+ } else if ( 'flags' in dep ) {
271
273
const depFlags = dep . flags
272
274
if (
273
275
( depFlags & ( SubscriberFlags . Computed | SubscriberFlags . Dirty ) ) ===
@@ -285,58 +287,49 @@ function checkDirty(link: Link): boolean {
285
287
( SubscriberFlags . Computed | SubscriberFlags . PendingComputed ) ) ===
286
288
( SubscriberFlags . Computed | SubscriberFlags . PendingComputed )
287
289
) {
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 }
291
292
}
292
- link = dep . deps !
293
- ++ stack
293
+ current = dep . deps !
294
+ ++ checkDepth
294
295
continue
295
296
}
296
297
}
297
298
298
- if ( ! dirty && link . nextDep !== undefined ) {
299
- link = link . nextDep
299
+ if ( ! dirty && current . nextDep !== undefined ) {
300
+ current = current . nextDep
300
301
continue
301
302
}
302
303
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
334
316
}
335
- sub = subSubs . sub as Computed
317
+ continue
336
318
}
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
340
333
}
341
334
342
335
return dirty
0 commit comments