@atlaspack/graph 3.4.1-canary.52 → 3.4.1-canary.521
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/CHANGELOG.md +432 -0
- package/benchmark/BitSet.js +37 -0
- package/dist/AdjacencyList.js +1348 -0
- package/dist/BitSet.js +108 -0
- package/dist/ContentGraph.js +70 -0
- package/dist/Graph.js +504 -0
- package/dist/index.js +17 -0
- package/dist/shared-buffer.js +24 -0
- package/dist/types.js +10 -0
- package/lib/AdjacencyList.js +35 -11
- package/lib/BitSet.js +36 -5
- package/lib/ContentGraph.js +2 -6
- package/lib/Graph.js +26 -13
- package/lib/index.js +2 -3
- package/lib/shared-buffer.js +5 -1
- package/lib/types/AdjacencyList.d.ts +609 -0
- package/lib/types/BitSet.d.ts +19 -0
- package/lib/types/ContentGraph.d.ts +23 -0
- package/lib/types/Graph.d.ts +92 -0
- package/lib/types/index.d.ts +7 -0
- package/lib/types/shared-buffer.d.ts +2 -0
- package/lib/types/types.d.ts +9 -0
- package/lib/types.js +1 -0
- package/package.json +16 -6
- package/src/{AdjacencyList.js → AdjacencyList.ts} +135 -107
- package/src/{BitSet.js → BitSet.ts} +31 -3
- package/src/{ContentGraph.js → ContentGraph.ts} +21 -20
- package/src/{Graph.js → Graph.ts} +104 -74
- package/src/{index.js → index.ts} +0 -2
- package/src/{shared-buffer.js → shared-buffer.ts} +6 -3
- package/src/{types.js → types.ts} +5 -7
- package/test/{AdjacencyList.test.js → AdjacencyList.test.ts} +21 -29
- package/test/{BitSet.test.js → BitSet.test.ts} +45 -5
- package/test/{ContentGraph.test.js → ContentGraph.test.ts} +2 -4
- package/test/{Graph.test.js → Graph.test.ts} +44 -36
- package/tsconfig.json +18 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// @flow
|
|
2
1
|
import assert from 'assert';
|
|
3
2
|
import nullthrows from 'nullthrows';
|
|
4
3
|
import {SharedBuffer} from './shared-buffer';
|
|
@@ -6,52 +5,59 @@ import {fromNodeId, toNodeId} from './types';
|
|
|
6
5
|
import {
|
|
7
6
|
ALL_EDGE_TYPES,
|
|
8
7
|
NULL_EDGE_TYPE,
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
NullEdgeType,
|
|
9
|
+
AllEdgeTypes,
|
|
11
10
|
} from './Graph';
|
|
12
11
|
import type {NodeId} from './types';
|
|
13
12
|
|
|
14
13
|
/** The address of the node in the nodes map. */
|
|
15
|
-
|
|
14
|
+
type NodeAddress = number;
|
|
16
15
|
|
|
17
|
-
|
|
16
|
+
type EdgeHash = number;
|
|
18
17
|
|
|
19
18
|
/** The address of the edge in the edges map. */
|
|
20
|
-
|
|
19
|
+
type EdgeAddress = number;
|
|
21
20
|
|
|
22
21
|
// eslint-disable-next-line no-unused-vars
|
|
23
|
-
export type SerializedAdjacencyList<TEdgeType> = {
|
|
24
|
-
nodes: Uint32Array
|
|
25
|
-
edges: Uint32Array
|
|
26
|
-
|
|
22
|
+
export type SerializedAdjacencyList<TEdgeType> = {
|
|
23
|
+
nodes: Uint32Array;
|
|
24
|
+
edges: Uint32Array;
|
|
25
|
+
};
|
|
27
26
|
|
|
28
27
|
// eslint-disable-next-line no-unused-vars
|
|
29
|
-
export type AdjacencyListOptions<TEdgeType> = {
|
|
28
|
+
export type AdjacencyListOptions<TEdgeType> = {
|
|
30
29
|
/** The initial number of edges to accommodate. */
|
|
31
|
-
initialCapacity?: number
|
|
30
|
+
initialCapacity?: number;
|
|
31
|
+
/** The initial number of nodes to accommodate. */
|
|
32
|
+
initialNodeCapacity?: number;
|
|
32
33
|
/** The max amount by which to grow the capacity. */
|
|
33
|
-
maxGrowFactor?: number
|
|
34
|
+
maxGrowFactor?: number;
|
|
34
35
|
/** The min amount by which to grow the capacity. */
|
|
35
|
-
minGrowFactor?: number
|
|
36
|
+
minGrowFactor?: number;
|
|
36
37
|
/** The size after which to grow the capacity by the minimum factor. */
|
|
37
|
-
peakCapacity?: number
|
|
38
|
+
peakCapacity?: number;
|
|
38
39
|
/** The percentage of deleted edges above which the capacity should shrink. */
|
|
39
|
-
unloadFactor?: number
|
|
40
|
+
unloadFactor?: number;
|
|
40
41
|
/** The amount by which to shrink the capacity. */
|
|
41
|
-
shrinkFactor?: number
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
type AdjacencyListParams = {
|
|
45
|
-
initialCapacity: number
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
42
|
+
shrinkFactor?: number;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
type AdjacencyListParams = {
|
|
46
|
+
initialCapacity: number;
|
|
47
|
+
initialNodeCapacity: number;
|
|
48
|
+
unloadFactor: number;
|
|
49
|
+
maxGrowFactor: number;
|
|
50
|
+
minGrowFactor: number;
|
|
51
|
+
peakCapacity: number;
|
|
52
|
+
shrinkFactor: number;
|
|
53
|
+
};
|
|
52
54
|
|
|
53
55
|
const DEFAULT_PARAMS: AdjacencyListParams = {
|
|
54
56
|
initialCapacity: 2,
|
|
57
|
+
// TODO: Find a heuristic for right-sizing nodes.
|
|
58
|
+
// e.g., given an average ratio of `e` edges for every `n` nodes,
|
|
59
|
+
// init nodes with `capacity * n / e`.
|
|
60
|
+
initialNodeCapacity: 2,
|
|
55
61
|
unloadFactor: 0.3,
|
|
56
62
|
maxGrowFactor: 8,
|
|
57
63
|
minGrowFactor: 2,
|
|
@@ -68,18 +74,18 @@ const DEFAULT_PARAMS: AdjacencyListParams = {
|
|
|
68
74
|
* `TooManyDeletes` = `3`: the edge map has too many deleted edges
|
|
69
75
|
* `NodesOverloaded` = `4`: the node map is overloaded
|
|
70
76
|
*/
|
|
71
|
-
const LinkResult: {
|
|
77
|
+
const LinkResult: {
|
|
72
78
|
/** The edge was successfully linked */
|
|
73
|
-
EdgeAdded: 0
|
|
79
|
+
EdgeAdded: 0;
|
|
74
80
|
/** The edge already exists */
|
|
75
|
-
EdgeExists: 1
|
|
81
|
+
EdgeExists: 1;
|
|
76
82
|
/** The edge map is overloaded */
|
|
77
|
-
EdgesOverloaded: 2
|
|
83
|
+
EdgesOverloaded: 2;
|
|
78
84
|
/** The edge map has too many deleted edges */
|
|
79
|
-
TooManyDeletes: 3
|
|
85
|
+
TooManyDeletes: 3;
|
|
80
86
|
/** The node map is overloaded */
|
|
81
|
-
NodesOverloaded: 4
|
|
82
|
-
|
|
87
|
+
NodesOverloaded: 4;
|
|
88
|
+
} = {
|
|
83
89
|
EdgeAdded: 0,
|
|
84
90
|
EdgeExists: 1,
|
|
85
91
|
EdgesOverloaded: 2,
|
|
@@ -121,7 +127,7 @@ const MAX_LINK_TRIES: 3 = 3;
|
|
|
121
127
|
* `getInboundEdgesByType` methods.
|
|
122
128
|
*
|
|
123
129
|
*/
|
|
124
|
-
export default class AdjacencyList<TEdgeType
|
|
130
|
+
export default class AdjacencyList<TEdgeType extends number = NullEdgeType> {
|
|
125
131
|
#nodes: NodeTypeMap<TEdgeType | NullEdgeType>;
|
|
126
132
|
#edges: EdgeTypeMap<TEdgeType | NullEdgeType>;
|
|
127
133
|
|
|
@@ -140,7 +146,9 @@ export default class AdjacencyList<TEdgeType: number = NullEdgeType> {
|
|
|
140
146
|
let nodes;
|
|
141
147
|
let edges;
|
|
142
148
|
|
|
149
|
+
// @ts-expect-error TS2339
|
|
143
150
|
if (opts?.nodes) {
|
|
151
|
+
// @ts-expect-error TS2339
|
|
144
152
|
({nodes, edges} = opts);
|
|
145
153
|
this.#nodes = new NodeTypeMap(nodes);
|
|
146
154
|
this.#edges = new EdgeTypeMap(edges);
|
|
@@ -148,12 +156,7 @@ export default class AdjacencyList<TEdgeType: number = NullEdgeType> {
|
|
|
148
156
|
} else {
|
|
149
157
|
this.#params = {...DEFAULT_PARAMS, ...opts};
|
|
150
158
|
|
|
151
|
-
let {initialCapacity} = this.#params;
|
|
152
|
-
|
|
153
|
-
// TODO: Find a heuristic for right-sizing nodes.
|
|
154
|
-
// e.g., given an average ratio of `e` edges for every `n` nodes,
|
|
155
|
-
// init nodes with `capacity * n / e`.
|
|
156
|
-
let initialNodeCapacity = 2;
|
|
159
|
+
let {initialCapacity, initialNodeCapacity} = this.#params;
|
|
157
160
|
|
|
158
161
|
NodeTypeMap.assertMaxCapacity(initialNodeCapacity);
|
|
159
162
|
EdgeTypeMap.assertMaxCapacity(initialCapacity);
|
|
@@ -167,7 +170,7 @@ export default class AdjacencyList<TEdgeType: number = NullEdgeType> {
|
|
|
167
170
|
* Create a new `AdjacencyList` with data serialized
|
|
168
171
|
* from another `AdjacencyList`.
|
|
169
172
|
*/
|
|
170
|
-
static deserialize(
|
|
173
|
+
static deserialize<TEdgeType extends number = NullEdgeType>(
|
|
171
174
|
opts: SerializedAdjacencyList<TEdgeType>,
|
|
172
175
|
): AdjacencyList<TEdgeType> {
|
|
173
176
|
return new AdjacencyList(opts);
|
|
@@ -184,35 +187,35 @@ export default class AdjacencyList<TEdgeType: number = NullEdgeType> {
|
|
|
184
187
|
}
|
|
185
188
|
|
|
186
189
|
/** Statistics about the current state of the `AdjacencyList`. */
|
|
187
|
-
get stats(): {
|
|
190
|
+
get stats(): {
|
|
188
191
|
/** The maximum number of edges the graph can contain. */
|
|
189
|
-
capacity: number
|
|
192
|
+
capacity: number;
|
|
190
193
|
/** The number of nodes in the graph. */
|
|
191
|
-
nodes: number
|
|
194
|
+
nodes: number;
|
|
192
195
|
/** The number of edge types associated with nodes in the graph. */
|
|
193
|
-
nodeEdgeTypes: number
|
|
196
|
+
nodeEdgeTypes: number;
|
|
194
197
|
/** The size of the raw nodes buffer, in mb. */
|
|
195
|
-
nodeBufferSize: string
|
|
198
|
+
nodeBufferSize: string;
|
|
196
199
|
/** The current load on the nodes array. */
|
|
197
|
-
nodeLoad: string
|
|
200
|
+
nodeLoad: string;
|
|
198
201
|
/** The number of edges in the graph. */
|
|
199
|
-
edges: number
|
|
202
|
+
edges: number;
|
|
200
203
|
/** The number of edges deleted from the graph. */
|
|
201
|
-
deleted: number
|
|
204
|
+
deleted: number;
|
|
202
205
|
/** The number of unique edge types in the graph. */
|
|
203
|
-
edgeTypes: number
|
|
206
|
+
edgeTypes: number;
|
|
204
207
|
/** The size of the raw edges buffer, in mb. */
|
|
205
|
-
edgeBufferSize: string
|
|
208
|
+
edgeBufferSize: string;
|
|
206
209
|
/** The current load on the edges array, including deletes. */
|
|
207
|
-
edgeLoadWithDeletes: string
|
|
210
|
+
edgeLoadWithDeletes: string;
|
|
208
211
|
/** The current load on the edges array. */
|
|
209
|
-
edgeLoad: string
|
|
212
|
+
edgeLoad: string;
|
|
210
213
|
/** The total number of edge hash collisions. */
|
|
211
|
-
collisions: number
|
|
214
|
+
collisions: number;
|
|
212
215
|
/** The number of collisions for the most common hash. */
|
|
213
|
-
maxCollisions: number
|
|
216
|
+
maxCollisions: number;
|
|
214
217
|
/** The average number of collisions per hash. */
|
|
215
|
-
avgCollisions: number
|
|
218
|
+
avgCollisions: number;
|
|
216
219
|
/**
|
|
217
220
|
* The actual distribution of hashes vs. the expected (uniform) distribution.
|
|
218
221
|
*
|
|
@@ -221,10 +224,11 @@ export default class AdjacencyList<TEdgeType: number = NullEdgeType> {
|
|
|
221
224
|
* > A ratio within one confidence interval (0.95 - 1.05) is indicative
|
|
222
225
|
* > that the hash function...has an expected uniform distribution.
|
|
223
226
|
*/
|
|
224
|
-
uniformity: number
|
|
225
|
-
|
|
227
|
+
uniformity: number;
|
|
228
|
+
} {
|
|
226
229
|
let edgeTypes = new Set();
|
|
227
230
|
let buckets = new Map();
|
|
231
|
+
// @ts-expect-error TS2488
|
|
228
232
|
for (let {from, to, type} of this.getAllEdges()) {
|
|
229
233
|
let hash = this.#edges.hash(from, to, type);
|
|
230
234
|
let bucket = buckets.get(hash) || new Set();
|
|
@@ -311,6 +315,7 @@ export default class AdjacencyList<TEdgeType: number = NullEdgeType> {
|
|
|
311
315
|
this.#edges.from(edge),
|
|
312
316
|
this.#edges.to(edge),
|
|
313
317
|
this.#edges.typeOf(edge),
|
|
318
|
+
// @ts-expect-error TS2345
|
|
314
319
|
edges,
|
|
315
320
|
nodes,
|
|
316
321
|
this.#params.unloadFactor,
|
|
@@ -324,7 +329,9 @@ export default class AdjacencyList<TEdgeType: number = NullEdgeType> {
|
|
|
324
329
|
);
|
|
325
330
|
|
|
326
331
|
// Finally, copy the new data arrays over to this graph.
|
|
332
|
+
// @ts-expect-error TS2322
|
|
327
333
|
this.#nodes = nodes;
|
|
334
|
+
// @ts-expect-error TS2322
|
|
328
335
|
this.#edges = edges;
|
|
329
336
|
}
|
|
330
337
|
|
|
@@ -418,11 +425,11 @@ export default class AdjacencyList<TEdgeType: number = NullEdgeType> {
|
|
|
418
425
|
/**
|
|
419
426
|
* Iterate over all edges in insertion order.
|
|
420
427
|
*/
|
|
421
|
-
*getAllEdges(): Iterator<{
|
|
422
|
-
type: TEdgeType | NullEdgeType
|
|
423
|
-
from: NodeId
|
|
424
|
-
to: NodeId
|
|
425
|
-
|
|
428
|
+
*getAllEdges(): Iterator<{
|
|
429
|
+
type: TEdgeType | NullEdgeType;
|
|
430
|
+
from: NodeId;
|
|
431
|
+
to: NodeId;
|
|
432
|
+
}> {
|
|
426
433
|
for (let edge of this.#edges) {
|
|
427
434
|
yield {
|
|
428
435
|
from: this.#edges.from(edge),
|
|
@@ -523,10 +530,14 @@ export default class AdjacencyList<TEdgeType: number = NullEdgeType> {
|
|
|
523
530
|
* Get a list of every node (labeled `from`) connecting _to_
|
|
524
531
|
* the given `to` node, along with the edge `type` connecting them.
|
|
525
532
|
*/
|
|
526
|
-
getInboundEdgesByType(
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
533
|
+
getInboundEdgesByType(to: NodeId): {
|
|
534
|
+
type: TEdgeType | NullEdgeType;
|
|
535
|
+
from: NodeId;
|
|
536
|
+
}[] {
|
|
537
|
+
let edges: Array<{
|
|
538
|
+
from: NodeId;
|
|
539
|
+
type: TEdgeType | NullEdgeType;
|
|
540
|
+
}> = [];
|
|
530
541
|
let node = this.#nodes.head(to);
|
|
531
542
|
while (node !== null) {
|
|
532
543
|
let type = this.#nodes.typeOf(node);
|
|
@@ -545,10 +556,14 @@ export default class AdjacencyList<TEdgeType: number = NullEdgeType> {
|
|
|
545
556
|
* Get a list of every node (labeled `to`) connected _from_
|
|
546
557
|
* the given `from` node, along with the edge `type` connecting them.
|
|
547
558
|
*/
|
|
548
|
-
getOutboundEdgesByType(
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
559
|
+
getOutboundEdgesByType(from: NodeId): {
|
|
560
|
+
type: TEdgeType | NullEdgeType;
|
|
561
|
+
to: NodeId;
|
|
562
|
+
}[] {
|
|
563
|
+
let edges: Array<{
|
|
564
|
+
to: NodeId;
|
|
565
|
+
type: TEdgeType | NullEdgeType;
|
|
566
|
+
}> = [];
|
|
552
567
|
let node = this.#nodes.head(from);
|
|
553
568
|
while (node !== null) {
|
|
554
569
|
let type = this.#nodes.typeOf(node);
|
|
@@ -578,12 +593,12 @@ export default class AdjacencyList<TEdgeType: number = NullEdgeType> {
|
|
|
578
593
|
| NullEdgeType
|
|
579
594
|
| Array<TEdgeType | NullEdgeType> = NULL_EDGE_TYPE,
|
|
580
595
|
): NodeId[] {
|
|
581
|
-
let matches = (node) =>
|
|
596
|
+
let matches = (node: number) =>
|
|
582
597
|
type === ALL_EDGE_TYPES ||
|
|
583
598
|
(Array.isArray(type)
|
|
584
599
|
? type.includes(this.#nodes.typeOf(node))
|
|
585
600
|
: type === this.#nodes.typeOf(node));
|
|
586
|
-
let nodes = [];
|
|
601
|
+
let nodes: Array<NodeId> = [];
|
|
587
602
|
let seen = new Set<NodeId>();
|
|
588
603
|
let node = this.#nodes.head(from);
|
|
589
604
|
while (node !== null) {
|
|
@@ -608,7 +623,7 @@ export default class AdjacencyList<TEdgeType: number = NullEdgeType> {
|
|
|
608
623
|
fn: (nodeId: NodeId) => boolean,
|
|
609
624
|
type: AllEdgeTypes | TEdgeType | NullEdgeType = ALL_EDGE_TYPES,
|
|
610
625
|
) {
|
|
611
|
-
const matches = (node) =>
|
|
626
|
+
const matches = (node: number) =>
|
|
612
627
|
type === ALL_EDGE_TYPES || type === this.#nodes.typeOf(node);
|
|
613
628
|
|
|
614
629
|
let node = this.#nodes.head(from);
|
|
@@ -629,10 +644,10 @@ export default class AdjacencyList<TEdgeType: number = NullEdgeType> {
|
|
|
629
644
|
|
|
630
645
|
forEachNodeIdConnectedTo(
|
|
631
646
|
to: NodeId,
|
|
632
|
-
fn: (nodeId: NodeId) => boolean |
|
|
647
|
+
fn: (nodeId: NodeId) => boolean | undefined,
|
|
633
648
|
type: AllEdgeTypes | TEdgeType | NullEdgeType = NULL_EDGE_TYPE,
|
|
634
649
|
) {
|
|
635
|
-
const matches = (node) =>
|
|
650
|
+
const matches = (node: number) =>
|
|
636
651
|
type === ALL_EDGE_TYPES || type === this.#nodes.typeOf(node);
|
|
637
652
|
|
|
638
653
|
let node = this.#nodes.head(to);
|
|
@@ -666,13 +681,13 @@ export default class AdjacencyList<TEdgeType: number = NullEdgeType> {
|
|
|
666
681
|
| NullEdgeType
|
|
667
682
|
| Array<TEdgeType | NullEdgeType> = NULL_EDGE_TYPE,
|
|
668
683
|
): NodeId[] {
|
|
669
|
-
let matches = (node) =>
|
|
684
|
+
let matches = (node: number) =>
|
|
670
685
|
type === ALL_EDGE_TYPES ||
|
|
671
686
|
(Array.isArray(type)
|
|
672
687
|
? type.includes(this.#nodes.typeOf(node))
|
|
673
688
|
: type === this.#nodes.typeOf(node));
|
|
674
689
|
|
|
675
|
-
let nodes = [];
|
|
690
|
+
let nodes: Array<NodeId> = [];
|
|
676
691
|
let seen = new Set<NodeId>();
|
|
677
692
|
let node = this.#nodes.head(to);
|
|
678
693
|
while (node !== null) {
|
|
@@ -739,7 +754,7 @@ export default class AdjacencyList<TEdgeType: number = NullEdgeType> {
|
|
|
739
754
|
* └────┼─────────┴─────────────────┘ │
|
|
740
755
|
* └─────────────────────────────────────────────┘
|
|
741
756
|
*/
|
|
742
|
-
export class SharedTypeMap<TItemType, THash, TAddress
|
|
757
|
+
export class SharedTypeMap<TItemType, THash, TAddress extends number>
|
|
743
758
|
implements Iterable<TAddress>
|
|
744
759
|
{
|
|
745
760
|
/**
|
|
@@ -779,7 +794,8 @@ export class SharedTypeMap<TItemType, THash, TAddress: number>
|
|
|
779
794
|
static #TYPE: 1 = 1;
|
|
780
795
|
|
|
781
796
|
/** The largest possible capacity. */
|
|
782
|
-
|
|
797
|
+
// @ts-expect-error TS1094
|
|
798
|
+
static get MAX_CAPACITY<TItemType, THash, TAddress extends number>(): number {
|
|
783
799
|
return Math.floor(
|
|
784
800
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Invalid_array_length#what_went_wrong
|
|
785
801
|
(2 ** 31 - 1 - this.HEADER_SIZE) / this.ITEM_SIZE,
|
|
@@ -787,7 +803,9 @@ export class SharedTypeMap<TItemType, THash, TAddress: number>
|
|
|
787
803
|
}
|
|
788
804
|
|
|
789
805
|
/** Assert that the given `capacity` does not exceed `MAX_CAPACITY`. */
|
|
790
|
-
static assertMaxCapacity
|
|
806
|
+
static assertMaxCapacity<TItemType, THash, TAddress extends number>(
|
|
807
|
+
capacity: number,
|
|
808
|
+
): void {
|
|
791
809
|
assert(capacity <= this.MAX_CAPACITY, `${this.name} capacity overflow!`);
|
|
792
810
|
}
|
|
793
811
|
|
|
@@ -815,6 +833,7 @@ export class SharedTypeMap<TItemType, THash, TAddress: number>
|
|
|
815
833
|
|
|
816
834
|
/** The address of the first item in the map. */
|
|
817
835
|
get addressableLimit(): number {
|
|
836
|
+
// @ts-expect-error TS2339
|
|
818
837
|
return this.constructor.HEADER_SIZE + this.capacity;
|
|
819
838
|
}
|
|
820
839
|
|
|
@@ -835,7 +854,6 @@ export class SharedTypeMap<TItemType, THash, TAddress: number>
|
|
|
835
854
|
if (typeof capacityOrData === 'number') {
|
|
836
855
|
let {BYTES_PER_ELEMENT} = Uint32Array;
|
|
837
856
|
let CAPACITY = SharedTypeMap.#CAPACITY;
|
|
838
|
-
// $FlowFixMe[incompatible-call]
|
|
839
857
|
this.data = new Uint32Array(
|
|
840
858
|
new SharedBuffer(this.getLength(capacityOrData) * BYTES_PER_ELEMENT),
|
|
841
859
|
);
|
|
@@ -854,6 +872,7 @@ export class SharedTypeMap<TItemType, THash, TAddress: number>
|
|
|
854
872
|
* and is expected to be of equal or smaller capacity to this map.
|
|
855
873
|
*/
|
|
856
874
|
set(data: Uint32Array): void {
|
|
875
|
+
// @ts-expect-error TS2339
|
|
857
876
|
let {HEADER_SIZE, ITEM_SIZE} = this.constructor;
|
|
858
877
|
let NEXT = SharedTypeMap.#NEXT;
|
|
859
878
|
let COUNT = SharedTypeMap.#COUNT;
|
|
@@ -902,31 +921,34 @@ export class SharedTypeMap<TItemType, THash, TAddress: number>
|
|
|
902
921
|
* get the length of the map, in bytes.
|
|
903
922
|
*/
|
|
904
923
|
getLength(capacity: number = this.capacity): number {
|
|
924
|
+
// @ts-expect-error TS2339
|
|
905
925
|
let {HEADER_SIZE, ITEM_SIZE} = this.constructor;
|
|
906
926
|
return capacity + HEADER_SIZE + ITEM_SIZE * capacity;
|
|
907
927
|
}
|
|
908
928
|
|
|
909
929
|
/** Get the next available address in the map. */
|
|
910
930
|
getNextAddress(): TAddress {
|
|
931
|
+
// @ts-expect-error TS2339
|
|
911
932
|
let {HEADER_SIZE, ITEM_SIZE} = this.constructor;
|
|
912
|
-
return (HEADER_SIZE + this.capacity + this.count * ITEM_SIZE
|
|
933
|
+
return (HEADER_SIZE + this.capacity + this.count * ITEM_SIZE) as any;
|
|
913
934
|
}
|
|
914
935
|
|
|
915
936
|
/** Get the address of the first item with the given hash. */
|
|
916
937
|
head(hash: THash): TAddress | null {
|
|
938
|
+
// @ts-expect-error TS2339
|
|
917
939
|
let {HEADER_SIZE} = this.constructor;
|
|
918
|
-
return (this.data[HEADER_SIZE + (hash
|
|
940
|
+
return (this.data[HEADER_SIZE + (hash as any)] as any) || null;
|
|
919
941
|
}
|
|
920
942
|
|
|
921
943
|
/** Get the address of the next item with the same hash as the given item. */
|
|
922
944
|
next(item: TAddress): TAddress | null {
|
|
923
945
|
let NEXT = SharedTypeMap.#NEXT;
|
|
924
|
-
return (this.data[(item
|
|
946
|
+
return (this.data[(item as any) + NEXT] as any) || null;
|
|
925
947
|
}
|
|
926
948
|
|
|
927
949
|
/** Get the type of the item at the given `item` address. */
|
|
928
950
|
typeOf(item: TAddress): TItemType {
|
|
929
|
-
return
|
|
951
|
+
return this.data[item + SharedTypeMap.#TYPE] as any;
|
|
930
952
|
}
|
|
931
953
|
|
|
932
954
|
/**
|
|
@@ -937,9 +959,10 @@ export class SharedTypeMap<TItemType, THash, TAddress: number>
|
|
|
937
959
|
let COUNT = SharedTypeMap.#COUNT;
|
|
938
960
|
let NEXT = SharedTypeMap.#NEXT;
|
|
939
961
|
let TYPE = SharedTypeMap.#TYPE;
|
|
962
|
+
// @ts-expect-error TS2339
|
|
940
963
|
let {HEADER_SIZE} = this.constructor;
|
|
941
964
|
|
|
942
|
-
this.data[item + TYPE] =
|
|
965
|
+
this.data[item + TYPE] = type as any;
|
|
943
966
|
|
|
944
967
|
let prev = this.head(hash);
|
|
945
968
|
if (prev !== null) {
|
|
@@ -951,7 +974,7 @@ export class SharedTypeMap<TItemType, THash, TAddress: number>
|
|
|
951
974
|
this.data[prev + NEXT] = item;
|
|
952
975
|
} else {
|
|
953
976
|
// This is the first item in the bucket!
|
|
954
|
-
this.data[HEADER_SIZE + (hash
|
|
977
|
+
this.data[HEADER_SIZE + (hash as any)] = item;
|
|
955
978
|
}
|
|
956
979
|
this.data[COUNT]++;
|
|
957
980
|
}
|
|
@@ -963,6 +986,7 @@ export class SharedTypeMap<TItemType, THash, TAddress: number>
|
|
|
963
986
|
let COUNT = SharedTypeMap.#COUNT;
|
|
964
987
|
let NEXT = SharedTypeMap.#NEXT;
|
|
965
988
|
let TYPE = SharedTypeMap.#TYPE;
|
|
989
|
+
// @ts-expect-error TS2339
|
|
966
990
|
let {HEADER_SIZE} = this.constructor;
|
|
967
991
|
|
|
968
992
|
this.data[item + TYPE] = 0;
|
|
@@ -976,6 +1000,7 @@ export class SharedTypeMap<TItemType, THash, TAddress: number>
|
|
|
976
1000
|
let candidate = head;
|
|
977
1001
|
while (candidate !== null && candidate !== item) {
|
|
978
1002
|
prev = candidate;
|
|
1003
|
+
// @ts-expect-error TS2322
|
|
979
1004
|
candidate = this.next(candidate);
|
|
980
1005
|
}
|
|
981
1006
|
if (prev !== null && next !== null) {
|
|
@@ -983,9 +1008,9 @@ export class SharedTypeMap<TItemType, THash, TAddress: number>
|
|
|
983
1008
|
} else if (prev !== null) {
|
|
984
1009
|
this.data[prev + NEXT] = 0;
|
|
985
1010
|
} else if (next !== null) {
|
|
986
|
-
this.data[HEADER_SIZE + (hash
|
|
1011
|
+
this.data[HEADER_SIZE + (hash as any)] = next;
|
|
987
1012
|
} else {
|
|
988
|
-
this.data[HEADER_SIZE + (hash
|
|
1013
|
+
this.data[HEADER_SIZE + (hash as any)] = 0;
|
|
989
1014
|
}
|
|
990
1015
|
this.data[item + NEXT] = 0;
|
|
991
1016
|
this.data[COUNT]--;
|
|
@@ -994,6 +1019,7 @@ export class SharedTypeMap<TItemType, THash, TAddress: number>
|
|
|
994
1019
|
forEach(cb: (item: TAddress) => void): void {
|
|
995
1020
|
let max = this.count;
|
|
996
1021
|
let len = this.length;
|
|
1022
|
+
// @ts-expect-error TS2339
|
|
997
1023
|
let {ITEM_SIZE} = this.constructor;
|
|
998
1024
|
for (
|
|
999
1025
|
let i = this.addressableLimit, count = 0;
|
|
@@ -1001,8 +1027,8 @@ export class SharedTypeMap<TItemType, THash, TAddress: number>
|
|
|
1001
1027
|
i += ITEM_SIZE
|
|
1002
1028
|
) {
|
|
1003
1029
|
// Skip items that don't have a type.
|
|
1004
|
-
if (this.typeOf(
|
|
1005
|
-
cb(
|
|
1030
|
+
if (this.typeOf(i as any)) {
|
|
1031
|
+
cb(i as any);
|
|
1006
1032
|
count++;
|
|
1007
1033
|
}
|
|
1008
1034
|
}
|
|
@@ -1012,10 +1038,10 @@ export class SharedTypeMap<TItemType, THash, TAddress: number>
|
|
|
1012
1038
|
// See https://github.com/facebook/flow/issues/1163#issuecomment-353523840
|
|
1013
1039
|
/*:: @@iterator(): Iterator<TAddress> { return ({}: any); } */
|
|
1014
1040
|
|
|
1015
|
-
// $FlowFixMe[unsupported-syntax]
|
|
1016
1041
|
*[Symbol.iterator](): Iterator<TAddress> {
|
|
1017
1042
|
let max = this.count;
|
|
1018
1043
|
let len = this.length;
|
|
1044
|
+
// @ts-expect-error TS2339
|
|
1019
1045
|
let {ITEM_SIZE} = this.constructor;
|
|
1020
1046
|
for (
|
|
1021
1047
|
let i = this.addressableLimit, count = 0;
|
|
@@ -1023,17 +1049,18 @@ export class SharedTypeMap<TItemType, THash, TAddress: number>
|
|
|
1023
1049
|
i += ITEM_SIZE
|
|
1024
1050
|
) {
|
|
1025
1051
|
if (this.data.subarray(i, i + ITEM_SIZE).some(Boolean)) {
|
|
1026
|
-
yield
|
|
1052
|
+
yield i as any;
|
|
1027
1053
|
count++;
|
|
1028
1054
|
}
|
|
1029
1055
|
}
|
|
1030
1056
|
}
|
|
1031
1057
|
|
|
1032
|
-
inspect(): {
|
|
1033
|
-
header: Uint32Array
|
|
1034
|
-
table: Uint32Array
|
|
1035
|
-
data: Uint32Array
|
|
1036
|
-
|
|
1058
|
+
inspect(): {
|
|
1059
|
+
header: Uint32Array;
|
|
1060
|
+
table: Uint32Array;
|
|
1061
|
+
data: Uint32Array;
|
|
1062
|
+
} {
|
|
1063
|
+
// @ts-expect-error TS2339
|
|
1037
1064
|
const {HEADER_SIZE} = this.constructor;
|
|
1038
1065
|
let min = this.addressableLimit;
|
|
1039
1066
|
|
|
@@ -1063,7 +1090,7 @@ export class SharedTypeMap<TItemType, THash, TAddress: number>
|
|
|
1063
1090
|
export class NodeTypeMap<TEdgeType> extends SharedTypeMap<
|
|
1064
1091
|
TEdgeType,
|
|
1065
1092
|
NodeId,
|
|
1066
|
-
NodeAddress
|
|
1093
|
+
NodeAddress
|
|
1067
1094
|
> {
|
|
1068
1095
|
/**
|
|
1069
1096
|
* In addition to the header defined by `SharedTypeMap`, the header for
|
|
@@ -1305,7 +1332,7 @@ export class NodeTypeMap<TEdgeType> extends SharedTypeMap<
|
|
|
1305
1332
|
export class EdgeTypeMap<TEdgeType> extends SharedTypeMap<
|
|
1306
1333
|
TEdgeType,
|
|
1307
1334
|
EdgeHash,
|
|
1308
|
-
EdgeAddress
|
|
1335
|
+
EdgeAddress
|
|
1309
1336
|
> {
|
|
1310
1337
|
/**
|
|
1311
1338
|
* In addition to the header defined by `SharedTypeMap`, the header for
|
|
@@ -1376,6 +1403,7 @@ export class EdgeTypeMap<TEdgeType> extends SharedTypeMap<
|
|
|
1376
1403
|
|
|
1377
1404
|
/** Get the next available address in the map. */
|
|
1378
1405
|
getNextAddress(): EdgeAddress {
|
|
1406
|
+
// @ts-expect-error TS2339
|
|
1379
1407
|
let {ITEM_SIZE} = this.constructor;
|
|
1380
1408
|
return this.addressableLimit + (this.count + this.deletes) * ITEM_SIZE;
|
|
1381
1409
|
}
|
|
@@ -1535,9 +1563,9 @@ export class EdgeTypeMap<TEdgeType> extends SharedTypeMap<
|
|
|
1535
1563
|
// the output widely. Then we do a series of prime multiplications and
|
|
1536
1564
|
// additions to combine the hashes into one value.
|
|
1537
1565
|
let hash = 17;
|
|
1538
|
-
hash = hash * 37 + hash32shift(
|
|
1539
|
-
hash = hash * 37 + hash32shift(
|
|
1540
|
-
hash = hash * 37 + hash32shift(
|
|
1566
|
+
hash = hash * 37 + hash32shift(from as any);
|
|
1567
|
+
hash = hash * 37 + hash32shift(to as any);
|
|
1568
|
+
hash = hash * 37 + hash32shift(type as any);
|
|
1541
1569
|
// Finally, we map the hash to a value modulo the edge capacity.
|
|
1542
1570
|
hash %= this.capacity;
|
|
1543
1571
|
return hash;
|
|
@@ -1554,14 +1582,14 @@ export class EdgeTypeMap<TEdgeType> extends SharedTypeMap<
|
|
|
1554
1582
|
* - `3` TooManyDeletes: the edge map has too many deleted edges
|
|
1555
1583
|
* - `4` NodesOverloaded: the node map is overloaded
|
|
1556
1584
|
*/
|
|
1557
|
-
function link<TEdgeType
|
|
1585
|
+
function link<TEdgeType extends number>(
|
|
1558
1586
|
from: NodeId,
|
|
1559
1587
|
to: NodeId,
|
|
1560
1588
|
type: TEdgeType | NullEdgeType,
|
|
1561
1589
|
edges: EdgeTypeMap<TEdgeType | NullEdgeType>,
|
|
1562
1590
|
nodes: NodeTypeMap<TEdgeType | NullEdgeType>,
|
|
1563
1591
|
unloadFactor: number = DEFAULT_PARAMS.unloadFactor,
|
|
1564
|
-
):
|
|
1592
|
+
): (typeof LinkResult)[keyof typeof LinkResult] {
|
|
1565
1593
|
let hash = edges.hash(from, to, type);
|
|
1566
1594
|
let edge = edges.addressOf(hash, from, to, type);
|
|
1567
1595
|
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
// @flow strict-local
|
|
2
|
-
|
|
3
1
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32#implementing_count_leading_ones_and_beyond
|
|
4
2
|
function ctz32(n: number): number {
|
|
5
3
|
if (n === 0) {
|
|
@@ -28,6 +26,12 @@ export class BitSet {
|
|
|
28
26
|
return res;
|
|
29
27
|
}
|
|
30
28
|
|
|
29
|
+
static intersect(a: BitSet, b: BitSet): BitSet {
|
|
30
|
+
let res = a.clone();
|
|
31
|
+
res.intersect(b);
|
|
32
|
+
return res;
|
|
33
|
+
}
|
|
34
|
+
|
|
31
35
|
get capacity(): number {
|
|
32
36
|
return this.bits.length * 32;
|
|
33
37
|
}
|
|
@@ -82,6 +86,31 @@ export class BitSet {
|
|
|
82
86
|
}
|
|
83
87
|
}
|
|
84
88
|
|
|
89
|
+
size(): number {
|
|
90
|
+
let bits = this.bits;
|
|
91
|
+
let setBitsCount = 0;
|
|
92
|
+
|
|
93
|
+
for (let k = 0; k < bits.length; k++) {
|
|
94
|
+
let chunk = bits[k];
|
|
95
|
+
|
|
96
|
+
while (chunk !== 0) {
|
|
97
|
+
chunk &= chunk - 1; // Clear the least significant bit set
|
|
98
|
+
setBitsCount++;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return setBitsCount;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
equals(other: BitSet): boolean {
|
|
106
|
+
for (let i = 0; i < this.bits.length; i++) {
|
|
107
|
+
if (this.bits[i] !== other.bits[i]) {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
|
|
85
114
|
forEach(fn: (bit: number) => void) {
|
|
86
115
|
// https://lemire.me/blog/2018/02/21/iterating-over-set-bits-quickly/
|
|
87
116
|
let bits = this.bits;
|
|
@@ -89,7 +118,6 @@ export class BitSet {
|
|
|
89
118
|
let v = bits[k];
|
|
90
119
|
while (v !== 0) {
|
|
91
120
|
let t = (v & -v) >>> 0;
|
|
92
|
-
// $FlowFixMe
|
|
93
121
|
fn((k << 5) + ctz32(v));
|
|
94
122
|
v ^= t;
|
|
95
123
|
}
|