j-templates 7.0.73 → 7.0.74
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DOM/index.d.ts +0 -2
- package/DOM/index.js +2 -2
- package/Node/vNode.js +0 -4
- package/Node/vNode.types.d.ts +0 -2
- package/Store/Tree/observableScope.js +107 -123
- package/Utils/bitSet.d.ts +23 -0
- package/Utils/bitSet.js +139 -0
- package/Utils/emitter.d.ts +0 -3
- package/Utils/emitter.js +6 -29
- package/package.json +1 -1
package/DOM/index.d.ts
CHANGED
package/DOM/index.js
CHANGED
|
@@ -16,5 +16,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./elements"), exports);
|
|
18
18
|
// export * from "./svgElements";
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
// export * from "./createPropertyAssignment";
|
|
20
|
+
// export * from "./createEventAssignment";
|
package/Node/vNode.js
CHANGED
|
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.vNode = void 0;
|
|
4
4
|
const Store_1 = require("../Store");
|
|
5
5
|
const observableScope_1 = require("../Store/Tree/observableScope");
|
|
6
|
-
const emitter_1 = require("../Utils/emitter");
|
|
7
6
|
const functions_1 = require("../Utils/functions");
|
|
8
7
|
const injector_1 = require("../Utils/injector");
|
|
9
8
|
const thread_1 = require("../Utils/thread");
|
|
@@ -22,7 +21,6 @@ var vNode;
|
|
|
22
21
|
node: definition.node ?? null,
|
|
23
22
|
children: null,
|
|
24
23
|
destroyed: false,
|
|
25
|
-
onDestroyed: null,
|
|
26
24
|
component: null,
|
|
27
25
|
scopes: [],
|
|
28
26
|
};
|
|
@@ -36,7 +34,6 @@ var vNode;
|
|
|
36
34
|
node: nodeConfig_1.NodeConfig.createTextNode(text),
|
|
37
35
|
children: null,
|
|
38
36
|
destroyed: false,
|
|
39
|
-
onDestroyed: null,
|
|
40
37
|
component: null,
|
|
41
38
|
scopes: [],
|
|
42
39
|
};
|
|
@@ -59,7 +56,6 @@ var vNode;
|
|
|
59
56
|
vnode.destroyed = true;
|
|
60
57
|
vnode.component?.Destroy();
|
|
61
58
|
Store_1.ObservableScope.DestroyAll(vnode.scopes);
|
|
62
|
-
vnode.onDestroyed && emitter_1.Emitter.Emit(vnode.onDestroyed);
|
|
63
59
|
for (let x = 0; vnode.children && x < vnode.children.length; x++) {
|
|
64
60
|
DestroyAll(vnode.children[x][1]);
|
|
65
61
|
Store_1.ObservableScope.Destroy(vnode.children[x][2]);
|
package/Node/vNode.types.d.ts
CHANGED
|
@@ -2,7 +2,6 @@ import { Component } from "./component";
|
|
|
2
2
|
import { IObservableScope } from "../Store/Tree/observableScope";
|
|
3
3
|
import { Injector } from "../Utils/injector";
|
|
4
4
|
import { RecursivePartial } from "../Utils/utils.types";
|
|
5
|
-
import { Emitter } from "../Utils/emitter";
|
|
6
5
|
export type FunctionOr<T> = {
|
|
7
6
|
(): T | Promise<T>;
|
|
8
7
|
} | T;
|
|
@@ -21,7 +20,6 @@ export type vNode = {
|
|
|
21
20
|
node: Node | null;
|
|
22
21
|
children: [any, vNode[], IObservableScope<string | vNode | vNode[]> | null][] | null;
|
|
23
22
|
destroyed: boolean;
|
|
24
|
-
onDestroyed: Emitter | null;
|
|
25
23
|
scopes: IObservableScope<unknown>[];
|
|
26
24
|
component: Component;
|
|
27
25
|
};
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ObservableScope = void 0;
|
|
4
4
|
exports.CalcScope = CalcScope;
|
|
5
|
-
const
|
|
5
|
+
const bitSet_1 = require("../../Utils/bitSet");
|
|
6
6
|
const emitter_1 = require("../../Utils/emitter");
|
|
7
7
|
const functions_1 = require("../../Utils/functions");
|
|
8
8
|
/**
|
|
@@ -45,6 +45,11 @@ function CreateStaticScope(initialValue) {
|
|
|
45
45
|
value: initialValue,
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Queue of scopes pending batched update processing.
|
|
50
|
+
* Scopes are added when their dependencies change and greedy batching is enabled.
|
|
51
|
+
* The queue is processed in a microtask to batch multiple updates efficiently.
|
|
52
|
+
*/
|
|
48
53
|
let scopeQueue = [];
|
|
49
54
|
/**
|
|
50
55
|
* Processes all queued scopes, recomputing dirty scopes and emitting changes.
|
|
@@ -89,93 +94,78 @@ function OnSet() {
|
|
|
89
94
|
emitter_1.Emitter.Emit(this.emitter, this);
|
|
90
95
|
}
|
|
91
96
|
/**
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
* @param state The current watch state.
|
|
96
|
-
* @param emitter The emitter to register.
|
|
97
|
-
*/
|
|
98
|
-
function RegisterSame(state, emitter) {
|
|
99
|
-
if (state.emitterIndex < state.emitters.length &&
|
|
100
|
-
state.emitters[state.emitterIndex] === emitter) {
|
|
101
|
-
state.emitterIndex++;
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
state.emitters = state.emitters.slice(0, state.emitterIndex);
|
|
105
|
-
state.strategy = SORTED_STRATEGY;
|
|
106
|
-
RegisterSorted(state, emitter);
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* Registers an emitter while maintaining sorted order by emitter ID.
|
|
110
|
-
* If insertion would break sort order, falls back to PUSH_STRATEGY.
|
|
111
|
-
* @param state The current watch state.
|
|
112
|
-
* @param emitter The emitter to register.
|
|
113
|
-
*/
|
|
114
|
-
function RegisterSorted(state, emitter) {
|
|
115
|
-
if (state.emitters.length === 0 ||
|
|
116
|
-
state.emitters[state.emitters.length - 1][0] < emitter[0])
|
|
117
|
-
state.emitters.push(emitter);
|
|
118
|
-
else {
|
|
119
|
-
state.strategy = PUSH_STRATEGY;
|
|
120
|
-
RegisterPush(state, emitter);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* Registers an emitter using PUSH_STRATEGY.
|
|
125
|
-
* Switches to DISTINCT_STRATEGY when the emitter count exceeds 50 to optimize memory.
|
|
126
|
-
* @param state The current watch state.
|
|
127
|
-
* @param emitter The emitter to register.
|
|
97
|
+
* Strategy where emitters are accessed in the same order as the previous execution.
|
|
98
|
+
* This allows for efficient reconciliation by tracking which emitters were accessed
|
|
99
|
+
* at the same positions in the array.
|
|
128
100
|
*/
|
|
129
|
-
|
|
130
|
-
state.emitters.push(emitter);
|
|
131
|
-
if (state.emitters.length > 50) {
|
|
132
|
-
const idSet = (state.emitterIds = new Set([state.emitters[0][0]]));
|
|
133
|
-
let writePos = 0;
|
|
134
|
-
for (let x = 1; x < state.emitters.length; x++) {
|
|
135
|
-
if (!idSet.has(state.emitters[x][0])) {
|
|
136
|
-
state.emitters[++writePos] = state.emitters[x];
|
|
137
|
-
idSet.add(state.emitters[x][0]);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
writePos++;
|
|
141
|
-
if (writePos < state.emitters.length)
|
|
142
|
-
state.emitters.splice(writePos);
|
|
143
|
-
state.strategy = DISTINCT_STRATEGY;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
101
|
+
const SAME_STRATEGY = 1;
|
|
146
102
|
/**
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
* @param state The current watch state.
|
|
150
|
-
* @param emitter The emitter to register.
|
|
103
|
+
* Strategy where new emitters are pushed to the array when accessed.
|
|
104
|
+
* Used when the access pattern changes from the previous execution.
|
|
151
105
|
*/
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
106
|
+
const PUSH_STRATEGY = 2;
|
|
107
|
+
function GetBitSetFor(emitters) {
|
|
108
|
+
const bitSet = bitSet_1.BitSetPool.Get(BIT_SET_POOL);
|
|
109
|
+
for (let x = 0; x < emitters.length; x++)
|
|
110
|
+
bitSet_1.BitSet.set(bitSet, emitters[x][0]);
|
|
111
|
+
return bitSet;
|
|
157
112
|
}
|
|
158
113
|
/**
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
114
|
+
* Registers an emitter as a dependency during a watch operation.
|
|
115
|
+
*
|
|
116
|
+
* This function tracks which emitters are accessed while executing a scope's getFunction.
|
|
117
|
+
* It uses two strategies for efficiency:
|
|
118
|
+
*
|
|
119
|
+
* - **SAME_STRATEGY**: When emitters are accessed in the same order as the previous execution,
|
|
120
|
+
* it tracks this via emitterIndex and skips array operations. Only switches to PUSH_STRATEGY
|
|
121
|
+
* when the order changes.
|
|
122
|
+
*
|
|
123
|
+
* - **PUSH_STRATEGY**: When access order differs or is new, emitters are pushed to the array.
|
|
124
|
+
* The BitSet prevents duplicates (same emitter accessed multiple times).
|
|
125
|
+
*
|
|
126
|
+
* The function does nothing if called outside a watch context (watchState is null).
|
|
127
|
+
*
|
|
128
|
+
* @param emitter The emitter to register as a dependency. Must have a unique ID at index 0.
|
|
162
129
|
*/
|
|
163
130
|
function RegisterEmitter(emitter) {
|
|
164
131
|
if (watchState === null)
|
|
165
132
|
return;
|
|
166
133
|
switch (watchState.strategy) {
|
|
167
|
-
case SAME_STRATEGY:
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
134
|
+
case SAME_STRATEGY: {
|
|
135
|
+
if (watchState.emitterIndex < watchState.emitters.length &&
|
|
136
|
+
watchState.emitters[watchState.emitterIndex][0] === emitter[0]) {
|
|
137
|
+
watchState.emitterIndex++;
|
|
138
|
+
// BitSet.set(watchState.emitterIds, emitter[0]);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
watchState.strategy = PUSH_STRATEGY;
|
|
142
|
+
watchState.emitters = watchState.emitters.slice(0, watchState.emitterIndex);
|
|
143
|
+
RegisterEmitter(emitter);
|
|
144
|
+
}
|
|
175
145
|
break;
|
|
176
|
-
|
|
177
|
-
|
|
146
|
+
}
|
|
147
|
+
case PUSH_STRATEGY: {
|
|
148
|
+
switch (watchState.emitters.length) {
|
|
149
|
+
case 0: {
|
|
150
|
+
watchState.emitters.push(emitter);
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
case 1: {
|
|
154
|
+
if (watchState.emitters[0][0] !== emitter[0])
|
|
155
|
+
watchState.emitters.push(emitter);
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
default: {
|
|
159
|
+
if (watchState.emitters[watchState.emitters.length - 1][0] !== emitter[0]) {
|
|
160
|
+
watchState.emitterIds ??= GetBitSetFor(watchState.emitters);
|
|
161
|
+
if (bitSet_1.BitSet.add(watchState.emitterIds, emitter[0]))
|
|
162
|
+
watchState.emitters.push(emitter);
|
|
163
|
+
}
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
178
167
|
break;
|
|
168
|
+
}
|
|
179
169
|
}
|
|
180
170
|
}
|
|
181
171
|
/**
|
|
@@ -200,15 +190,16 @@ function GetScopeValue(scope) {
|
|
|
200
190
|
return scope.value;
|
|
201
191
|
}
|
|
202
192
|
/**
|
|
203
|
-
*
|
|
204
|
-
*
|
|
193
|
+
* Global watch state representing the current dependency tracking context.
|
|
194
|
+
* This is set during scope execution and tracks which emitters/scopes are accessed.
|
|
195
|
+
* Nested watch contexts are supported via the parent reference pattern.
|
|
205
196
|
*/
|
|
206
|
-
const SAME_STRATEGY = 1;
|
|
207
|
-
const PUSH_STRATEGY = 2;
|
|
208
|
-
const SORTED_STRATEGY = 3;
|
|
209
|
-
const DISTINCT_STRATEGY = 4;
|
|
210
|
-
const SHRINK_STRATEGY = 5;
|
|
211
197
|
let watchState = null;
|
|
198
|
+
/**
|
|
199
|
+
* Pool for recycling BitSet objects to reduce garbage collection overhead.
|
|
200
|
+
* BitSets are borrowed during watch operations and returned after use.
|
|
201
|
+
*/
|
|
202
|
+
const BIT_SET_POOL = bitSet_1.BitSetPool.Create();
|
|
212
203
|
/**
|
|
213
204
|
* Executes a callback while tracking all scope and emitter dependencies.
|
|
214
205
|
* Creates a watch context that records what was accessed during execution.
|
|
@@ -220,21 +211,16 @@ function WatchFunction(callback, currentCalc, initialEmitters) {
|
|
|
220
211
|
const parent = watchState;
|
|
221
212
|
watchState = {
|
|
222
213
|
emitterIndex: 0,
|
|
214
|
+
strategy: initialEmitters === null ? PUSH_STRATEGY : SAME_STRATEGY,
|
|
223
215
|
value: null,
|
|
224
216
|
emitters: initialEmitters ?? [],
|
|
225
|
-
emitterIds: null,
|
|
217
|
+
emitterIds: null, // BitSetPool.Get(BIT_SET_POOL),
|
|
226
218
|
currentCalc,
|
|
227
219
|
nextCalc: null,
|
|
228
|
-
strategy: initialEmitters === null ? SORTED_STRATEGY : SAME_STRATEGY,
|
|
229
220
|
};
|
|
230
221
|
watchState.value = callback();
|
|
231
222
|
const resultState = watchState;
|
|
232
223
|
watchState = parent;
|
|
233
|
-
if (resultState.strategy === SAME_STRATEGY &&
|
|
234
|
-
resultState.emitterIndex < resultState.emitters.length) {
|
|
235
|
-
resultState.emitters = resultState.emitters.slice(0, resultState.emitterIndex);
|
|
236
|
-
resultState.strategy = SHRINK_STRATEGY;
|
|
237
|
-
}
|
|
238
224
|
return resultState;
|
|
239
225
|
}
|
|
240
226
|
/**
|
|
@@ -245,7 +231,11 @@ function WatchFunction(callback, currentCalc, initialEmitters) {
|
|
|
245
231
|
function ExecuteScope(scope) {
|
|
246
232
|
scope.dirty = false;
|
|
247
233
|
const state = WatchFunction(scope.getFunction, scope.calcScopes, scope.emitters);
|
|
248
|
-
|
|
234
|
+
if (state.strategy === SAME_STRATEGY &&
|
|
235
|
+
state.emitterIndex < state.emitters.length)
|
|
236
|
+
state.emitters = state.emitters.slice(0, state.emitterIndex);
|
|
237
|
+
UpdateEmitters(scope, state);
|
|
238
|
+
state.emitterIds && bitSet_1.BitSetPool.Return(BIT_SET_POOL, state.emitterIds);
|
|
249
239
|
const calcScopes = state.currentCalc;
|
|
250
240
|
scope.calcScopes = state.nextCalc;
|
|
251
241
|
for (const key in calcScopes)
|
|
@@ -272,7 +262,8 @@ function ExecuteFunction(callback, greedy, allowStatic) {
|
|
|
272
262
|
if (!allowStatic || async || state.emitters !== null) {
|
|
273
263
|
const scope = CreateDynamicScope(callback, greedy, async ? null : state.value);
|
|
274
264
|
scope.calcScopes = state.nextCalc;
|
|
275
|
-
UpdateEmitters(scope, state
|
|
265
|
+
UpdateEmitters(scope, state);
|
|
266
|
+
state.emitterIds && bitSet_1.BitSetPool.Return(BIT_SET_POOL, state.emitterIds);
|
|
276
267
|
if (async)
|
|
277
268
|
state.value.then(function (result) {
|
|
278
269
|
scope.value = result;
|
|
@@ -303,7 +294,7 @@ function CalcScope(callback, idOverride) {
|
|
|
303
294
|
return callback();
|
|
304
295
|
const nextScopes = (watchState.nextCalc ??= {});
|
|
305
296
|
const id = idOverride ?? "default";
|
|
306
|
-
if (nextScopes
|
|
297
|
+
if (Object.hasOwn(nextScopes, id)) {
|
|
307
298
|
RegisterScope(nextScopes[id]);
|
|
308
299
|
return GetScopeValue(nextScopes[id]);
|
|
309
300
|
}
|
|
@@ -315,39 +306,31 @@ function CalcScope(callback, idOverride) {
|
|
|
315
306
|
return GetScopeValue(nextScopes[id]);
|
|
316
307
|
}
|
|
317
308
|
/**
|
|
318
|
-
* Updates a scope's
|
|
319
|
-
*
|
|
320
|
-
*
|
|
321
|
-
*
|
|
322
|
-
*
|
|
309
|
+
* Updates a scope's emitter subscriptions based on the new watch state.
|
|
310
|
+
* Efficiently reconciles old and new emitter lists starting from emitterIndex.
|
|
311
|
+
*
|
|
312
|
+
* Emitters before emitterIndex are in the same position and don't need updates.
|
|
313
|
+
* Emitters at/after emitterIndex are removed if no longer accessed or added if newly accessed.
|
|
314
|
+
*
|
|
315
|
+
* @param scope The scope to update emitter subscriptions for.
|
|
316
|
+
* @param state The watch state containing the new emitter list.
|
|
323
317
|
*/
|
|
324
|
-
function UpdateEmitters(scope,
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
318
|
+
function UpdateEmitters(scope, state) {
|
|
319
|
+
const currentEmitters = scope.emitters;
|
|
320
|
+
const nextEmitters = state.emitters;
|
|
321
|
+
const nextEmitterIds = state.emitterIds;
|
|
322
|
+
const sameIndex = state.emitterIndex;
|
|
323
|
+
if (currentEmitters !== null) {
|
|
324
|
+
for (let x = sameIndex; x < currentEmitters.length; x++) {
|
|
325
|
+
if (nextEmitterIds === null || !bitSet_1.BitSet.remove(nextEmitterIds, currentEmitters[x][0]))
|
|
326
|
+
emitter_1.Emitter.Remove(currentEmitters[x], scope.setCallback);
|
|
330
327
|
}
|
|
331
|
-
case PUSH_STRATEGY:
|
|
332
|
-
case DISTINCT_STRATEGY:
|
|
333
|
-
strategy === PUSH_STRATEGY
|
|
334
|
-
? emitter_1.Emitter.Distinct(right)
|
|
335
|
-
: emitter_1.Emitter.Sort(right);
|
|
336
|
-
case SORTED_STRATEGY:
|
|
337
|
-
if (scope.emitters === null || scope.emitters.length === 0) {
|
|
338
|
-
for (let x = 0; x < right.length; x++)
|
|
339
|
-
emitter_1.Emitter.On(right[x], scope.setCallback);
|
|
340
|
-
}
|
|
341
|
-
else {
|
|
342
|
-
(0, array_1.ReconcileSortedEmitters)(scope.emitters, right, function (emitter) {
|
|
343
|
-
emitter_1.Emitter.On(emitter, scope.setCallback);
|
|
344
|
-
}, function (emitter) {
|
|
345
|
-
emitter_1.Emitter.Remove(emitter, scope.setCallback);
|
|
346
|
-
});
|
|
347
|
-
}
|
|
348
|
-
break;
|
|
349
328
|
}
|
|
350
|
-
|
|
329
|
+
for (let x = sameIndex; x < nextEmitters.length; x++) {
|
|
330
|
+
if (nextEmitterIds === null || bitSet_1.BitSet.has(nextEmitterIds, nextEmitters[x][0]))
|
|
331
|
+
emitter_1.Emitter.On(nextEmitters[x], scope.setCallback);
|
|
332
|
+
}
|
|
333
|
+
scope.emitters = nextEmitters;
|
|
351
334
|
}
|
|
352
335
|
/**
|
|
353
336
|
* Destroys multiple scopes, cleaning up their resources.
|
|
@@ -379,6 +362,7 @@ function DestroyScope(scope) {
|
|
|
379
362
|
scope.setCallback = null;
|
|
380
363
|
scope.destroyed = true;
|
|
381
364
|
scope.onDestroyed && emitter_1.Emitter.Emit(scope.onDestroyed, scope);
|
|
365
|
+
scope.onDestroyed && emitter_1.Emitter.Destroy(scope.onDestroyed);
|
|
382
366
|
}
|
|
383
367
|
var ObservableScope;
|
|
384
368
|
(function (ObservableScope) {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type BitSet = {
|
|
2
|
+
init: boolean;
|
|
3
|
+
buffer: Uint32Array | null;
|
|
4
|
+
activeFrames: Set<number>;
|
|
5
|
+
minFrame: number;
|
|
6
|
+
maxFrame: number;
|
|
7
|
+
};
|
|
8
|
+
export type BitSetPool = {
|
|
9
|
+
pool: BitSet[];
|
|
10
|
+
index: number;
|
|
11
|
+
};
|
|
12
|
+
export declare namespace BitSetPool {
|
|
13
|
+
function Create(): BitSetPool;
|
|
14
|
+
function Get(pool: BitSetPool): BitSet;
|
|
15
|
+
function Return(pool: BitSetPool, bitSet: BitSet): void;
|
|
16
|
+
}
|
|
17
|
+
export declare namespace BitSet {
|
|
18
|
+
function Create(): BitSet;
|
|
19
|
+
function set(set: BitSet, num: number): void;
|
|
20
|
+
function has(set: BitSet, num: number): boolean;
|
|
21
|
+
function add(set: BitSet, num: number): boolean;
|
|
22
|
+
function remove(set: BitSet, num: number): boolean;
|
|
23
|
+
}
|
package/Utils/bitSet.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BitSet = exports.BitSetPool = void 0;
|
|
4
|
+
// 100000 = 31
|
|
5
|
+
const FRAME_BIT_SHIFT = 5;
|
|
6
|
+
const DEFAULT_FRAME_COUNT = 1024;
|
|
7
|
+
const DEFAULT_FRAME_HALF = DEFAULT_FRAME_COUNT / 2;
|
|
8
|
+
function GetFrame(number) {
|
|
9
|
+
// Effectively equivalent to Math.floor(number / 32)
|
|
10
|
+
return number >>> FRAME_BIT_SHIFT;
|
|
11
|
+
}
|
|
12
|
+
function GetBit(number) {
|
|
13
|
+
// JavaScript only uses rightmost 5 bits of num for this operation
|
|
14
|
+
// Effectively equivalent to number % 32
|
|
15
|
+
return 1 << number;
|
|
16
|
+
}
|
|
17
|
+
function Resize(set, frame) {
|
|
18
|
+
if (set.minFrame <= frame && frame < set.maxFrame)
|
|
19
|
+
return;
|
|
20
|
+
const currentSize = set.maxFrame - set.minFrame;
|
|
21
|
+
let newMin = Math.min(set.minFrame, frame);
|
|
22
|
+
let newMax = Math.max(set.maxFrame, frame + 1);
|
|
23
|
+
let newSize = newMax - newMin;
|
|
24
|
+
const minimumNewSize = currentSize * 2;
|
|
25
|
+
if (newSize < minimumNewSize) {
|
|
26
|
+
const growBy = minimumNewSize - newSize;
|
|
27
|
+
const growByHalf = growBy / 2;
|
|
28
|
+
newMin = newMin - Math.floor(growByHalf);
|
|
29
|
+
newMax = newMax + Math.ceil(growByHalf);
|
|
30
|
+
if (newMin < 0) {
|
|
31
|
+
newMax -= newMin;
|
|
32
|
+
newMin = 0;
|
|
33
|
+
}
|
|
34
|
+
newSize = newMax - newMin;
|
|
35
|
+
}
|
|
36
|
+
const newBuffer = new Uint32Array(newSize);
|
|
37
|
+
newBuffer.set(set.buffer, set.minFrame - newMin);
|
|
38
|
+
set.buffer = newBuffer;
|
|
39
|
+
set.minFrame = newMin;
|
|
40
|
+
set.maxFrame = newMax;
|
|
41
|
+
}
|
|
42
|
+
function Initialize(set, initFrameNumber) {
|
|
43
|
+
if (set.init)
|
|
44
|
+
return;
|
|
45
|
+
set.init = true;
|
|
46
|
+
set.activeFrames.clear();
|
|
47
|
+
const frame = GetFrame(initFrameNumber);
|
|
48
|
+
const sizeHalf = (set.buffer?.length ?? DEFAULT_FRAME_COUNT) / 2;
|
|
49
|
+
set.buffer ??= new Uint32Array(DEFAULT_FRAME_COUNT);
|
|
50
|
+
set.minFrame = frame - Math.floor(sizeHalf);
|
|
51
|
+
set.maxFrame = frame + Math.ceil(sizeHalf);
|
|
52
|
+
if (set.minFrame < 0) {
|
|
53
|
+
set.maxFrame -= set.minFrame;
|
|
54
|
+
set.minFrame = 0;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
var BitSetPool;
|
|
58
|
+
(function (BitSetPool) {
|
|
59
|
+
function Create() {
|
|
60
|
+
return {
|
|
61
|
+
pool: [],
|
|
62
|
+
index: 0
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
BitSetPool.Create = Create;
|
|
66
|
+
function Get(pool) {
|
|
67
|
+
return pool.index === 0 ? BitSet.Create() : pool.pool[--pool.index];
|
|
68
|
+
}
|
|
69
|
+
BitSetPool.Get = Get;
|
|
70
|
+
function Return(pool, bitSet) {
|
|
71
|
+
bitSet.init = false;
|
|
72
|
+
pool.pool[pool.index++] = bitSet;
|
|
73
|
+
}
|
|
74
|
+
BitSetPool.Return = Return;
|
|
75
|
+
})(BitSetPool || (exports.BitSetPool = BitSetPool = {}));
|
|
76
|
+
var BitSet;
|
|
77
|
+
(function (BitSet) {
|
|
78
|
+
function Create() {
|
|
79
|
+
return {
|
|
80
|
+
init: false,
|
|
81
|
+
buffer: null,
|
|
82
|
+
activeFrames: new Set(),
|
|
83
|
+
minFrame: -1,
|
|
84
|
+
maxFrame: -1,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
BitSet.Create = Create;
|
|
88
|
+
function set(set, num) {
|
|
89
|
+
Initialize(set, num);
|
|
90
|
+
const frame = GetFrame(num);
|
|
91
|
+
Resize(set, frame);
|
|
92
|
+
if (!set.activeFrames.has(frame)) {
|
|
93
|
+
set.buffer[frame] = 0;
|
|
94
|
+
set.activeFrames.add(frame);
|
|
95
|
+
}
|
|
96
|
+
const frameOffset = frame - set.minFrame;
|
|
97
|
+
set.buffer[frameOffset] |= GetBit(num);
|
|
98
|
+
}
|
|
99
|
+
BitSet.set = set;
|
|
100
|
+
function has(set, num) {
|
|
101
|
+
if (set.buffer === null)
|
|
102
|
+
return false;
|
|
103
|
+
const frame = GetFrame(num);
|
|
104
|
+
if (!set.activeFrames.has(frame))
|
|
105
|
+
return false;
|
|
106
|
+
if (frame < set.minFrame || set.maxFrame <= frame)
|
|
107
|
+
return false;
|
|
108
|
+
const frameOffset = frame - set.minFrame;
|
|
109
|
+
const frameValue = set.buffer[frameOffset] & GetBit(num);
|
|
110
|
+
return frameValue !== 0;
|
|
111
|
+
}
|
|
112
|
+
BitSet.has = has;
|
|
113
|
+
function add(set, num) {
|
|
114
|
+
Initialize(set, num);
|
|
115
|
+
const frame = GetFrame(num);
|
|
116
|
+
Resize(set, frame);
|
|
117
|
+
if (!set.activeFrames.has(frame)) {
|
|
118
|
+
set.buffer[frame] = 0;
|
|
119
|
+
set.activeFrames.add(frame);
|
|
120
|
+
}
|
|
121
|
+
const frameOffset = frame - set.minFrame;
|
|
122
|
+
const frameStart = set.buffer[frameOffset];
|
|
123
|
+
set.buffer[frameOffset] |= GetBit(num);
|
|
124
|
+
return frameStart !== set.buffer[frameOffset];
|
|
125
|
+
}
|
|
126
|
+
BitSet.add = add;
|
|
127
|
+
function remove(set, num) {
|
|
128
|
+
if (set.buffer === null)
|
|
129
|
+
return false;
|
|
130
|
+
const frame = GetFrame(num);
|
|
131
|
+
if (!set.activeFrames.has(frame) || frame < set.minFrame || set.maxFrame <= frame)
|
|
132
|
+
return false;
|
|
133
|
+
const frameOffset = frame - set.minFrame;
|
|
134
|
+
const frameStart = set.buffer[frameOffset];
|
|
135
|
+
set.buffer[frameOffset] ^= GetBit(num);
|
|
136
|
+
return frameStart !== set.buffer[frameOffset];
|
|
137
|
+
}
|
|
138
|
+
BitSet.remove = remove;
|
|
139
|
+
})(BitSet || (exports.BitSet = BitSet = {}));
|
package/Utils/emitter.d.ts
CHANGED
|
@@ -8,7 +8,4 @@ export declare namespace Emitter {
|
|
|
8
8
|
function Destroy(emitter: Emitter): void;
|
|
9
9
|
function Remove(emitter: Emitter, callback: EmitterCallback): void;
|
|
10
10
|
function Clear(emitter: Emitter): void;
|
|
11
|
-
function Distinct(emitters: Emitter[]): void;
|
|
12
|
-
function Sort(emitters: Emitter[]): void;
|
|
13
|
-
function Compare(a: Emitter, b: Emitter): number;
|
|
14
11
|
}
|
package/Utils/emitter.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Emitter = void 0;
|
|
4
|
-
const
|
|
4
|
+
const idPool = [];
|
|
5
|
+
let idPoolIndex = 0;
|
|
6
|
+
let globalId = 0;
|
|
5
7
|
var Emitter;
|
|
6
8
|
(function (Emitter) {
|
|
7
|
-
let globalId = 0;
|
|
8
9
|
function Create() {
|
|
9
|
-
const
|
|
10
|
+
const emitterId = idPoolIndex === 0 ? ++globalId : idPool[--idPoolIndex];
|
|
11
|
+
const emitter = [emitterId];
|
|
10
12
|
return emitter;
|
|
11
13
|
}
|
|
12
14
|
Emitter.Create = Create;
|
|
@@ -33,6 +35,7 @@ var Emitter;
|
|
|
33
35
|
}
|
|
34
36
|
Emitter.Emit = Emit;
|
|
35
37
|
function Destroy(emitter) {
|
|
38
|
+
idPool[idPoolIndex++] = emitter[0];
|
|
36
39
|
emitter[0] = -1;
|
|
37
40
|
}
|
|
38
41
|
Emitter.Destroy = Destroy;
|
|
@@ -48,30 +51,4 @@ var Emitter;
|
|
|
48
51
|
emitter.splice(1);
|
|
49
52
|
}
|
|
50
53
|
Emitter.Clear = Clear;
|
|
51
|
-
function Distinct(emitters) {
|
|
52
|
-
if (emitters.length < 2)
|
|
53
|
-
return;
|
|
54
|
-
Sort(emitters);
|
|
55
|
-
let writePos = 0;
|
|
56
|
-
for (let x = 1; x < emitters.length; x++) {
|
|
57
|
-
if (emitters[x][0] !== emitters[writePos][0]) {
|
|
58
|
-
emitters[++writePos] = emitters[x];
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
writePos++;
|
|
62
|
-
if (writePos < emitters.length)
|
|
63
|
-
emitters.splice(writePos);
|
|
64
|
-
}
|
|
65
|
-
Emitter.Distinct = Distinct;
|
|
66
|
-
function Sort(emitters) {
|
|
67
|
-
if (emitters.length < 11)
|
|
68
|
-
(0, array_1.InsertionSortTuples)(emitters);
|
|
69
|
-
else
|
|
70
|
-
emitters.sort(Compare);
|
|
71
|
-
}
|
|
72
|
-
Emitter.Sort = Sort;
|
|
73
|
-
function Compare(a, b) {
|
|
74
|
-
return a[0] - b[0];
|
|
75
|
-
}
|
|
76
|
-
Emitter.Compare = Compare;
|
|
77
54
|
})(Emitter || (exports.Emitter = Emitter = {}));
|