@fluidframework/matrix 2.0.0-internal.3.0.5 → 2.0.0-internal.3.1.1
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/.eslintrc.js +20 -21
- package/.mocharc.js +2 -2
- package/README.md +21 -21
- package/api-extractor.json +2 -2
- package/bench/bsp-set-optimizations.md +5 -5
- package/bench/src/index.ts +38 -20
- package/bench/src/read/map.ts +16 -10
- package/bench/src/read/nativearray.ts +16 -10
- package/bench/src/read/test.ts +17 -19
- package/bench/src/read/tiled.ts +240 -181
- package/bench/src/util.ts +19 -18
- package/bench/tsconfig.json +8 -13
- package/dist/bspSet.d.ts.map +1 -1
- package/dist/bspSet.js.map +1 -1
- package/dist/handlecache.d.ts.map +1 -1
- package/dist/handlecache.js +1 -3
- package/dist/handlecache.js.map +1 -1
- package/dist/handletable.d.ts.map +1 -1
- package/dist/handletable.js +7 -3
- package/dist/handletable.js.map +1 -1
- package/dist/matrix.d.ts +1 -1
- package/dist/matrix.d.ts.map +1 -1
- package/dist/matrix.js +28 -19
- package/dist/matrix.js.map +1 -1
- package/dist/ops.d.ts.map +1 -1
- package/dist/ops.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/permutationvector.d.ts.map +1 -1
- package/dist/permutationvector.js +15 -8
- package/dist/permutationvector.js.map +1 -1
- package/dist/productSet.d.ts.map +1 -1
- package/dist/productSet.js +6 -3
- package/dist/productSet.js.map +1 -1
- package/dist/range.d.ts.map +1 -1
- package/dist/range.js.map +1 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js.map +1 -1
- package/dist/serialization.d.ts.map +1 -1
- package/dist/serialization.js.map +1 -1
- package/dist/sparsearray2d.d.ts.map +1 -1
- package/dist/sparsearray2d.js +12 -12
- package/dist/sparsearray2d.js.map +1 -1
- package/dist/split.d.ts.map +1 -1
- package/dist/split.js +5 -3
- package/dist/split.js.map +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/undoprovider.d.ts.map +1 -1
- package/dist/undoprovider.js.map +1 -1
- package/lib/bspSet.d.ts.map +1 -1
- package/lib/bspSet.js.map +1 -1
- package/lib/handlecache.d.ts.map +1 -1
- package/lib/handlecache.js +1 -3
- package/lib/handlecache.js.map +1 -1
- package/lib/handletable.d.ts.map +1 -1
- package/lib/handletable.js +7 -3
- package/lib/handletable.js.map +1 -1
- package/lib/matrix.d.ts +1 -1
- package/lib/matrix.d.ts.map +1 -1
- package/lib/matrix.js +29 -20
- package/lib/matrix.js.map +1 -1
- package/lib/ops.d.ts.map +1 -1
- package/lib/ops.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/permutationvector.d.ts.map +1 -1
- package/lib/permutationvector.js +15 -8
- package/lib/permutationvector.js.map +1 -1
- package/lib/productSet.d.ts.map +1 -1
- package/lib/productSet.js +6 -3
- package/lib/productSet.js.map +1 -1
- package/lib/range.d.ts.map +1 -1
- package/lib/range.js.map +1 -1
- package/lib/runtime.d.ts.map +1 -1
- package/lib/runtime.js.map +1 -1
- package/lib/serialization.d.ts.map +1 -1
- package/lib/serialization.js.map +1 -1
- package/lib/sparsearray2d.d.ts.map +1 -1
- package/lib/sparsearray2d.js +12 -12
- package/lib/sparsearray2d.js.map +1 -1
- package/lib/split.d.ts.map +1 -1
- package/lib/split.js +5 -3
- package/lib/split.js.map +1 -1
- package/lib/types.d.ts.map +1 -1
- package/lib/types.js.map +1 -1
- package/lib/undoprovider.d.ts.map +1 -1
- package/lib/undoprovider.js +1 -1
- package/lib/undoprovider.js.map +1 -1
- package/package.json +117 -116
- package/prettier.config.cjs +1 -1
- package/src/bspSet.ts +507 -434
- package/src/handlecache.ts +114 -112
- package/src/handletable.ts +66 -62
- package/src/matrix.ts +781 -710
- package/src/ops.ts +11 -11
- package/src/packageVersion.ts +1 -1
- package/src/permutationvector.ts +425 -368
- package/src/productSet.ts +852 -788
- package/src/range.ts +8 -8
- package/src/runtime.ts +35 -35
- package/src/serialization.ts +13 -9
- package/src/sparsearray2d.ts +196 -192
- package/src/split.ts +111 -90
- package/src/types.ts +3 -3
- package/src/undoprovider.ts +161 -144
- package/tsconfig.esnext.json +6 -6
- package/tsconfig.json +8 -12
package/src/range.ts
CHANGED
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Ensures that 0 \<= 'value' \< 'limit'. Throws a RangeError otherwise.
|
|
8
|
+
*/
|
|
9
9
|
export function ensureRange(value: number, limit: number) {
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
// Coerce 'value' to Uint32 so that we can range check with a single branch.
|
|
11
|
+
const _value = value >>> 0; // eslint-disable-line no-bitwise
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
if (_value >= limit) {
|
|
14
|
+
throw new RangeError("Invalid (row, col) coordinate.");
|
|
15
|
+
}
|
|
16
16
|
}
|
package/src/runtime.ts
CHANGED
|
@@ -4,49 +4,49 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
IChannelAttributes,
|
|
8
|
+
IFluidDataStoreRuntime,
|
|
9
|
+
IChannelServices,
|
|
10
|
+
IChannel,
|
|
11
|
+
IChannelFactory,
|
|
12
12
|
} from "@fluidframework/datastore-definitions";
|
|
13
13
|
import { pkgVersion } from "./packageVersion";
|
|
14
14
|
import { SharedMatrix } from "./matrix";
|
|
15
15
|
|
|
16
16
|
export class SharedMatrixFactory implements IChannelFactory {
|
|
17
|
-
|
|
17
|
+
public static Type = "https://graph.microsoft.com/types/sharedmatrix";
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
public static readonly Attributes: IChannelAttributes = {
|
|
20
|
+
type: SharedMatrixFactory.Type,
|
|
21
|
+
snapshotFormatVersion: "0.1",
|
|
22
|
+
packageVersion: pkgVersion,
|
|
23
|
+
};
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
public get type() {
|
|
26
|
+
return SharedMatrixFactory.Type;
|
|
27
|
+
}
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
public get attributes() {
|
|
30
|
+
return SharedMatrixFactory.Attributes;
|
|
31
|
+
}
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
33
|
+
/**
|
|
34
|
+
* {@inheritDoc @fluidframework/datastore-definitions#IChannelFactory.load}
|
|
35
|
+
*/
|
|
36
|
+
public async load(
|
|
37
|
+
runtime: IFluidDataStoreRuntime,
|
|
38
|
+
id: string,
|
|
39
|
+
services: IChannelServices,
|
|
40
|
+
attributes: IChannelAttributes,
|
|
41
|
+
): Promise<IChannel> {
|
|
42
|
+
const matrix = new SharedMatrix(runtime, id, attributes);
|
|
43
|
+
await matrix.load(services);
|
|
44
|
+
return matrix;
|
|
45
|
+
}
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
public create(document: IFluidDataStoreRuntime, id: string): IChannel {
|
|
48
|
+
const matrix = new SharedMatrix(document, id, this.attributes);
|
|
49
|
+
matrix.initializeLocal();
|
|
50
|
+
return matrix;
|
|
51
|
+
}
|
|
52
52
|
}
|
package/src/serialization.ts
CHANGED
|
@@ -10,15 +10,19 @@ import { IFluidSerializer } from "@fluidframework/shared-object-base";
|
|
|
10
10
|
import { bufferToString } from "@fluidframework/common-utils";
|
|
11
11
|
|
|
12
12
|
export const serializeBlob = (
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
handle: IFluidHandle,
|
|
14
|
+
path: string,
|
|
15
|
+
snapshot: Serializable,
|
|
16
|
+
serializer: IFluidSerializer,
|
|
17
17
|
) => new BlobTreeEntry(path, serializer.stringify(snapshot, handle));
|
|
18
18
|
|
|
19
|
-
export async function deserializeBlob(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
export async function deserializeBlob(
|
|
20
|
+
storage: IChannelStorageService,
|
|
21
|
+
path: string,
|
|
22
|
+
serializer: IFluidSerializer,
|
|
23
|
+
) {
|
|
24
|
+
const blob = await storage.readBlob(path);
|
|
25
|
+
const utf8 = bufferToString(blob, "utf8");
|
|
26
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
27
|
+
return serializer.parse(utf8);
|
|
24
28
|
}
|
package/src/sparsearray2d.ts
CHANGED
|
@@ -12,14 +12,13 @@ import { IMatrixReader, IMatrixWriter } from "@tiny-calc/nano";
|
|
|
12
12
|
//
|
|
13
13
|
// (Lookup table ~17% faster than inlining the bit-twiddling on Node v12 x64)
|
|
14
14
|
// (Array<T> ~2% faster than typed array on Node v12 x64)
|
|
15
|
-
const x8ToInterlacedX16 =
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
});
|
|
15
|
+
const x8ToInterlacedX16 = new Array(256).fill(0).map((value, i) => {
|
|
16
|
+
let j = i;
|
|
17
|
+
j = (j | (j << 4)) & 0x0f0f; // .... 7654 .... 3210
|
|
18
|
+
j = (j | (j << 2)) & 0x3333; // ..76 ..54 ..32 ..10
|
|
19
|
+
j = (j | (j << 1)) & 0x5555; // .7.6 .5.4 .3.2 .1.0
|
|
20
|
+
return j;
|
|
21
|
+
});
|
|
23
22
|
|
|
24
23
|
// Selects individual bytes from a given 32b integer. The left shift are used to
|
|
25
24
|
// clear upper bits (faster than using masks on Node 10 x64).
|
|
@@ -30,205 +29,210 @@ const byte3 = (x32: number) => (x32 << 24) >>> 24;
|
|
|
30
29
|
|
|
31
30
|
// Given a uint16 returns the corresponding uint32 integer where 0s are
|
|
32
31
|
// interleaved between the original bits. (e.g., 1111... -> 01010101...).
|
|
33
|
-
const interlaceBitsX16 = (x16: number) =>
|
|
32
|
+
const interlaceBitsX16 = (x16: number) =>
|
|
33
|
+
(x8ToInterlacedX16[byte2(x16)] << 16) | x8ToInterlacedX16[byte3(x16)];
|
|
34
34
|
|
|
35
35
|
const r0ToMorton16 = (row: number) => (interlaceBitsX16(row) << 1) >>> 0;
|
|
36
36
|
const c0ToMorton16 = (col: number) => interlaceBitsX16(col) >>> 0;
|
|
37
37
|
|
|
38
38
|
// Given a 2D uint16 coordinate returns the corresponding unt32 Morton coded
|
|
39
39
|
// coordinate. (See https://en.wikipedia.org/wiki/Z-order_curve)
|
|
40
|
-
const r0c0ToMorton2x16 = (row: number, col: number) =>
|
|
40
|
+
const r0c0ToMorton2x16 = (row: number, col: number) =>
|
|
41
|
+
(r0ToMorton16(row) | c0ToMorton16(col)) >>> 0;
|
|
41
42
|
|
|
42
43
|
type RecurArrayHelper<T> = RecurArray<T> | T;
|
|
43
44
|
type RecurArray<T> = RecurArrayHelper<T>[];
|
|
44
45
|
|
|
45
46
|
/** Undo JSON serialization's coercion of 'undefined' to null. */
|
|
46
|
-
const nullToUndefined = <T>(array: RecurArray<T | null>): RecurArray<T | undefined> =>
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
? nullToUndefined(value)
|
|
51
|
-
: value;
|
|
52
|
-
});
|
|
47
|
+
const nullToUndefined = <T>(array: RecurArray<T | null>): RecurArray<T | undefined> =>
|
|
48
|
+
array.map((value) => {
|
|
49
|
+
return value === null ? undefined : Array.isArray(value) ? nullToUndefined(value) : value;
|
|
50
|
+
});
|
|
53
51
|
|
|
54
52
|
type UA<T> = (T | undefined)[];
|
|
55
53
|
|
|
56
54
|
/**
|
|
57
55
|
* A sparse 4 billion x 4 billion array stored as 16x16 tiles.
|
|
58
56
|
*/
|
|
59
|
-
export class SparseArray2D<T>
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
57
|
+
export class SparseArray2D<T>
|
|
58
|
+
implements IMatrixReader<T | undefined>, IMatrixWriter<T | undefined>
|
|
59
|
+
{
|
|
60
|
+
constructor(private readonly root: UA<UA<UA<UA<UA<T>>>>> = [undefined]) {}
|
|
61
|
+
|
|
62
|
+
public get rowCount() {
|
|
63
|
+
return 0xffffffff;
|
|
64
|
+
}
|
|
65
|
+
public get colCount() {
|
|
66
|
+
return 0xffffffff;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public getCell(row: number, col: number): T | undefined {
|
|
70
|
+
const keyHi = r0c0ToMorton2x16(row >>> 16, col >>> 16);
|
|
71
|
+
const level0 = this.root[keyHi];
|
|
72
|
+
if (level0 !== undefined) {
|
|
73
|
+
const keyLo = r0c0ToMorton2x16(row, col);
|
|
74
|
+
const level1 = level0[byte0(keyLo)];
|
|
75
|
+
if (level1 !== undefined) {
|
|
76
|
+
const level2 = level1[byte1(keyLo)];
|
|
77
|
+
if (level2 !== undefined) {
|
|
78
|
+
const level3 = level2[byte2(keyLo)];
|
|
79
|
+
if (level3 !== undefined) {
|
|
80
|
+
return level3[byte3(keyLo)];
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
public get matrixProducer() {
|
|
90
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
91
|
+
return undefined as any;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
public setCell(row: number, col: number, value: T | undefined) {
|
|
95
|
+
const keyHi = r0c0ToMorton2x16(row >>> 16, col >>> 16);
|
|
96
|
+
const keyLo = r0c0ToMorton2x16(row, col);
|
|
97
|
+
|
|
98
|
+
const level0 = this.getLevel(this.root, keyHi);
|
|
99
|
+
const level1 = this.getLevel(level0, byte0(keyLo));
|
|
100
|
+
const level2 = this.getLevel(level1, byte1(keyLo));
|
|
101
|
+
const level3 = this.getLevel(level2, byte2(keyLo));
|
|
102
|
+
level3[byte3(keyLo)] = value;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Invokes the given 'callback' for each key in a 16 x 16 tile at the indicated row.
|
|
107
|
+
*
|
|
108
|
+
* (Note that 'rowBits' is the appropriate byte from 'r0ToMorton16' for the current
|
|
109
|
+
* level being traversed.)
|
|
110
|
+
*/
|
|
111
|
+
private forEachKeyInRow(rowBits: number, callback: (key: number) => void) {
|
|
112
|
+
for (let col = 0; col < 16; col++) {
|
|
113
|
+
// Perf: Potentially faster to replace 'c0ToMorton16()' with a short look up table?
|
|
114
|
+
callback((rowBits | c0ToMorton16(col)) >>> 0);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Invokes the given 'callback' for each key in a 16 x 16 tile at the indicated col.
|
|
120
|
+
*
|
|
121
|
+
* (Note that 'colBits' is the appropriate byte from 'c0ToMorton16' for the current
|
|
122
|
+
* level being traversed.)
|
|
123
|
+
*/
|
|
124
|
+
private forEachKeyInCol(col: number, callback: (key: number) => void) {
|
|
125
|
+
for (let row = 0; row < 16; row++) {
|
|
126
|
+
// Perf: Potentially faster to replace 'r0ToMorton16()' with a short look up table?
|
|
127
|
+
callback((r0ToMorton16(row) | col) >>> 0);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Invokes the give 'callback' with the next 'level' array for each populated region
|
|
133
|
+
* of the given row in the 'currentLevel'.
|
|
134
|
+
*
|
|
135
|
+
* (Note that 'rowBits' is the appropriate byte from 'r0ToMorton16' for the current
|
|
136
|
+
* level being traversed.)
|
|
137
|
+
*/
|
|
138
|
+
private forEachInRow<V extends UA<any>, U extends UA<V>>(
|
|
139
|
+
currentLevel: U,
|
|
140
|
+
rowBits: number,
|
|
141
|
+
callback: (level: V) => void,
|
|
142
|
+
) {
|
|
143
|
+
this.forEachKeyInRow(rowBits, (key) => {
|
|
144
|
+
const nextLevel = currentLevel[key];
|
|
145
|
+
if (nextLevel !== undefined) {
|
|
146
|
+
callback(nextLevel);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Invokes the give 'callback' with the next 'level' array for each populated region
|
|
153
|
+
* of the given col in the 'currentLevel'.
|
|
154
|
+
*
|
|
155
|
+
* (Note that 'colBits' is the appropriate byte from 'c0ToMorton16' for the current
|
|
156
|
+
* level being traversed.)
|
|
157
|
+
*/
|
|
158
|
+
private forEachInCol<V extends UA<any>, U extends UA<V>>(
|
|
159
|
+
currentLevel: U,
|
|
160
|
+
colBits: number,
|
|
161
|
+
callback: (level: V) => void,
|
|
162
|
+
) {
|
|
163
|
+
this.forEachKeyInCol(colBits, (key) => {
|
|
164
|
+
const nextLevel = currentLevel[key];
|
|
165
|
+
if (nextLevel !== undefined) {
|
|
166
|
+
callback(nextLevel);
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** Clears the all cells contained within the specified span of rows. */
|
|
172
|
+
public clearRows(rowStart: number, rowCount: number) {
|
|
173
|
+
const rowEnd = rowStart + rowCount;
|
|
174
|
+
for (let row = rowStart; row < rowEnd; row++) {
|
|
175
|
+
const rowHi = r0ToMorton16(row >>> 16);
|
|
176
|
+
|
|
177
|
+
// The top level of tree is a 64k x 64k tile. We need to scan all 64k entries.
|
|
178
|
+
for (let colHi = 0; colHi < 0x10000; colHi++) {
|
|
179
|
+
const keyHi = (rowHi | c0ToMorton16(colHi)) >>> 0;
|
|
180
|
+
const level0 = this.root[keyHi];
|
|
181
|
+
if (level0 !== undefined) {
|
|
182
|
+
// The remainder of the tree is divided in 16 x 16 tiles.
|
|
183
|
+
const rowLo = r0ToMorton16(row);
|
|
184
|
+
this.forEachInRow(level0, byte0(rowLo), (level1) => {
|
|
185
|
+
this.forEachInRow(level1, byte1(rowLo), (level2) => {
|
|
186
|
+
this.forEachInRow(level2, byte2(rowLo), (level3) => {
|
|
187
|
+
this.forEachKeyInRow(byte3(rowLo), (key) => {
|
|
188
|
+
level3[key] = undefined;
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** Clears the all cells contained within the specifed span of cols. */
|
|
199
|
+
public clearCols(colStart: number, colCount: number) {
|
|
200
|
+
const colEnd = colStart + colCount;
|
|
201
|
+
for (let col = colStart; col < colEnd; col++) {
|
|
202
|
+
const colHi = c0ToMorton16(col >>> 16);
|
|
203
|
+
|
|
204
|
+
// The top level of tree is a 64k x 64k tile. We need to scan all 64k entries.
|
|
205
|
+
for (let rowHi = 0; rowHi < 0x10000; rowHi++) {
|
|
206
|
+
const keyHi = (colHi | r0ToMorton16(rowHi)) >>> 0;
|
|
207
|
+
const level0 = this.root[keyHi];
|
|
208
|
+
if (level0 !== undefined) {
|
|
209
|
+
// The remainder of the tree is divided in 16 x 16 tiles.
|
|
210
|
+
const colLo = c0ToMorton16(col);
|
|
211
|
+
this.forEachInCol(level0, byte0(colLo), (level1) => {
|
|
212
|
+
this.forEachInCol(level1, byte1(colLo), (level2) => {
|
|
213
|
+
this.forEachInCol(level2, byte2(colLo), (level3) => {
|
|
214
|
+
this.forEachKeyInCol(byte3(colLo), (key) => {
|
|
215
|
+
level3[key] = undefined;
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
private getLevel<T>(parent: UA<UA<T>>, subKey: number) {
|
|
226
|
+
const level = parent[subKey];
|
|
227
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
228
|
+
return level === undefined ? (parent[subKey] = new Array(256).fill(undefined)) : level;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
public snapshot() {
|
|
232
|
+
return this.root;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
public static load<T>(data: RecurArray<T>) {
|
|
236
|
+
return new SparseArray2D<T>(nullToUndefined<T>(data) as SparseArray2D<T>["root"]);
|
|
237
|
+
}
|
|
234
238
|
}
|