@atlaspack/graph 3.5.20 → 3.5.21

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.
@@ -0,0 +1,1348 @@
1
+ "use strict";
2
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
+ if (kind === "m") throw new TypeError("Private method is not writable");
4
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
6
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
+ };
8
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
10
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
+ };
13
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
16
+ var _AdjacencyList_nodes, _AdjacencyList_edges, _AdjacencyList_params, _a, _SharedTypeMap_CAPACITY, _SharedTypeMap_COUNT, _SharedTypeMap_NEXT, _SharedTypeMap_TYPE, _b, _NodeTypeMap_NEXT_ID, _NodeTypeMap_FIRST_IN, _NodeTypeMap_FIRST_OUT, _NodeTypeMap_LAST_IN, _NodeTypeMap_LAST_OUT, _c, _EdgeTypeMap_DELETES, _EdgeTypeMap_FROM, _EdgeTypeMap_TO, _EdgeTypeMap_NEXT_IN, _EdgeTypeMap_PREV_IN, _EdgeTypeMap_NEXT_OUT, _EdgeTypeMap_PREV_OUT;
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.EdgeTypeMap = exports.NodeTypeMap = exports.SharedTypeMap = void 0;
19
+ const assert_1 = __importDefault(require("assert"));
20
+ const nullthrows_1 = __importDefault(require("nullthrows"));
21
+ const shared_buffer_1 = require("./shared-buffer");
22
+ const types_1 = require("./types");
23
+ const Graph_1 = require("./Graph");
24
+ const DEFAULT_PARAMS = {
25
+ initialCapacity: 2,
26
+ unloadFactor: 0.3,
27
+ maxGrowFactor: 8,
28
+ minGrowFactor: 2,
29
+ peakCapacity: 2 ** 18,
30
+ shrinkFactor: 0.5,
31
+ };
32
+ /**
33
+ * An Enum representing the result of a call to `link`.
34
+ *
35
+ * `EdgeAdded` = `0`: the edge was successfully linked
36
+ * `EdgeExists` = `1`: the edge already exists
37
+ * `EdgesOverloaded` = `2`: the edge map is overloaded
38
+ * `TooManyDeletes` = `3`: the edge map has too many deleted edges
39
+ * `NodesOverloaded` = `4`: the node map is overloaded
40
+ */
41
+ const LinkResult = {
42
+ EdgeAdded: 0,
43
+ EdgeExists: 1,
44
+ EdgesOverloaded: 2,
45
+ TooManyDeletes: 3,
46
+ NodesOverloaded: 4,
47
+ };
48
+ /**
49
+ * Allow 3 attempts to link an edge before erroring.
50
+ *
51
+ * The three attempts correspond to the three possible inconclusive link results:
52
+ * - `LinkResult.EdgesOverloaded`
53
+ * - `LinkResult.TooManyDeletes`
54
+ * - `LinkResult.NodesOverloaded`
55
+ *
56
+ * If after 3 tries, the link result is still one of these,
57
+ * this is considered an error.
58
+ */
59
+ const MAX_LINK_TRIES = 3;
60
+ /**
61
+ * `AdjacencyList` maps nodes to lists of their adjacent nodes.
62
+ *
63
+ * It is implemented as a hashmap of nodes, where each node has
64
+ * doubly linked lists of edges of each unique edge type.
65
+ * The edges are stored in a separate hashmap, where each edge has
66
+ * a pointer to the originating node, the terminating node, and
67
+ * the next and previous edges to and from adjacent nodes.
68
+ *
69
+ * The hash maps are each stored in a `Uint32Array` backed
70
+ * by a `SharedArrayBuffer`. See `SharedTypeMap` for more details.
71
+ *
72
+ * It's primary interface is through the `getNodeIdsConnectedFrom`
73
+ * and `getNodeIdsConnectedTo` methods, which return the list of
74
+ * nodes connected from or to a given node, respectively.
75
+ *
76
+ * It is also possible to get the lists of edges connected from or to
77
+ * a given node, using the `getOutboundEdgesByType` and
78
+ * `getInboundEdgesByType` methods.
79
+ *
80
+ */
81
+ class AdjacencyList {
82
+ /**
83
+ * Create a new `AdjacencyList` in one of two ways:
84
+ * - with specified options, or
85
+ * - with data serialized from a previous `AdjacencyList`.
86
+ */
87
+ constructor(opts) {
88
+ _AdjacencyList_nodes.set(this, void 0);
89
+ _AdjacencyList_edges.set(this, void 0);
90
+ _AdjacencyList_params.set(this, void 0);
91
+ let nodes;
92
+ let edges;
93
+ // @ts-expect-error TS2339
94
+ if (opts?.nodes) {
95
+ // @ts-expect-error TS2339
96
+ ({ nodes, edges } = opts);
97
+ __classPrivateFieldSet(this, _AdjacencyList_nodes, new NodeTypeMap(nodes), "f");
98
+ __classPrivateFieldSet(this, _AdjacencyList_edges, new EdgeTypeMap(edges), "f");
99
+ __classPrivateFieldSet(this, _AdjacencyList_params, { ...DEFAULT_PARAMS, initialCapacity: __classPrivateFieldGet(this, _AdjacencyList_edges, "f").capacity }, "f");
100
+ }
101
+ else {
102
+ __classPrivateFieldSet(this, _AdjacencyList_params, { ...DEFAULT_PARAMS, ...opts }, "f");
103
+ let { initialCapacity } = __classPrivateFieldGet(this, _AdjacencyList_params, "f");
104
+ // TODO: Find a heuristic for right-sizing nodes.
105
+ // e.g., given an average ratio of `e` edges for every `n` nodes,
106
+ // init nodes with `capacity * n / e`.
107
+ let initialNodeCapacity = 2;
108
+ NodeTypeMap.assertMaxCapacity(initialNodeCapacity);
109
+ EdgeTypeMap.assertMaxCapacity(initialCapacity);
110
+ __classPrivateFieldSet(this, _AdjacencyList_nodes, new NodeTypeMap(initialNodeCapacity), "f");
111
+ __classPrivateFieldSet(this, _AdjacencyList_edges, new EdgeTypeMap(initialCapacity), "f");
112
+ }
113
+ }
114
+ /**
115
+ * Create a new `AdjacencyList` with data serialized
116
+ * from another `AdjacencyList`.
117
+ */
118
+ static deserialize(opts) {
119
+ return new AdjacencyList(opts);
120
+ }
121
+ /**
122
+ * Returns a serializable object of the nodes and edges in the AdjacencyList.
123
+ */
124
+ serialize() {
125
+ return {
126
+ nodes: __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").data,
127
+ edges: __classPrivateFieldGet(this, _AdjacencyList_edges, "f").data,
128
+ };
129
+ }
130
+ /** Statistics about the current state of the `AdjacencyList`. */
131
+ get stats() {
132
+ let edgeTypes = new Set();
133
+ let buckets = new Map();
134
+ // @ts-expect-error TS2488
135
+ for (let { from, to, type } of this.getAllEdges()) {
136
+ let hash = __classPrivateFieldGet(this, _AdjacencyList_edges, "f").hash(from, to, type);
137
+ let bucket = buckets.get(hash) || new Set();
138
+ let key = `${String(from)}, ${String(to)}, ${String(type)}`;
139
+ (0, assert_1.default)(!bucket.has(key), `Duplicate node detected: ${key}`);
140
+ bucket.add(key);
141
+ buckets.set(hash, bucket);
142
+ edgeTypes.add(type);
143
+ }
144
+ let maxCollisions = 0;
145
+ let collisions = 0;
146
+ let distribution = 0;
147
+ /**
148
+ * The expected distribution of hashes across available hash buckets.
149
+ *
150
+ * See: https://en.wikipedia.org/wiki/Hash_function#Testing_and_measurement
151
+ */
152
+ let uniformDistribution = (__classPrivateFieldGet(this, _AdjacencyList_edges, "f").count / (2 * __classPrivateFieldGet(this, _AdjacencyList_edges, "f").capacity)) *
153
+ (__classPrivateFieldGet(this, _AdjacencyList_edges, "f").count + 2 * __classPrivateFieldGet(this, _AdjacencyList_edges, "f").capacity - 1);
154
+ for (let bucket of buckets.values()) {
155
+ maxCollisions = Math.max(maxCollisions, bucket.size - 1);
156
+ collisions += bucket.size - 1;
157
+ distribution += (bucket.size * (bucket.size + 1)) / 2;
158
+ }
159
+ return {
160
+ capacity: __classPrivateFieldGet(this, _AdjacencyList_edges, "f").capacity,
161
+ nodes: (0, types_1.fromNodeId)(__classPrivateFieldGet(this, _AdjacencyList_nodes, "f").nextId),
162
+ nodeEdgeTypes: __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").count,
163
+ nodeLoad: `${Math.round(__classPrivateFieldGet(this, _AdjacencyList_nodes, "f").load * 100)}%`,
164
+ nodeBufferSize: __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").bufferSize,
165
+ edges: __classPrivateFieldGet(this, _AdjacencyList_edges, "f").count,
166
+ deleted: __classPrivateFieldGet(this, _AdjacencyList_edges, "f").deletes,
167
+ edgeTypes: edgeTypes.size,
168
+ edgeLoad: `${Math.round(__classPrivateFieldGet(this, _AdjacencyList_edges, "f").load * 100)}%`,
169
+ edgeLoadWithDeletes: `${Math.round(__classPrivateFieldGet(this, _AdjacencyList_edges, "f").getLoad(__classPrivateFieldGet(this, _AdjacencyList_edges, "f").count + __classPrivateFieldGet(this, _AdjacencyList_edges, "f").deletes) * 100)}%`,
170
+ edgeBufferSize: __classPrivateFieldGet(this, _AdjacencyList_edges, "f").bufferSize,
171
+ collisions,
172
+ maxCollisions,
173
+ avgCollisions: Math.round((collisions / __classPrivateFieldGet(this, _AdjacencyList_edges, "f").count) * 100) / 100 || 0,
174
+ uniformity: Math.round((distribution / uniformDistribution) * 100) / 100 || 0,
175
+ };
176
+ }
177
+ /**
178
+ * Resize the internal nodes array.
179
+ *
180
+ * This is used in `addNode` and in `addEdge` when
181
+ * the `nodes` array is at capacity,
182
+ */
183
+ resizeNodes(size) {
184
+ let nodes = __classPrivateFieldGet(this, _AdjacencyList_nodes, "f");
185
+ // Allocate the required space for a `nodes` map of the given `size`.
186
+ __classPrivateFieldSet(this, _AdjacencyList_nodes, new NodeTypeMap(size), "f");
187
+ // Copy the existing nodes into the new array.
188
+ __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").set(nodes.data);
189
+ }
190
+ /**
191
+ * Resize the internal edges array.
192
+ *
193
+ * This is used in `addEdge` when the `edges` array is at capacity.
194
+ */
195
+ resizeEdges(size) {
196
+ // Allocate the required space for new `nodes` and `edges` maps.
197
+ let edges = new EdgeTypeMap(size);
198
+ let nodes = new NodeTypeMap(__classPrivateFieldGet(this, _AdjacencyList_nodes, "f").capacity);
199
+ // Copy the existing edges into the new array.
200
+ nodes.nextId = __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").nextId;
201
+ __classPrivateFieldGet(this, _AdjacencyList_edges, "f").forEach((edge) => void link(__classPrivateFieldGet(this, _AdjacencyList_edges, "f").from(edge), __classPrivateFieldGet(this, _AdjacencyList_edges, "f").to(edge), __classPrivateFieldGet(this, _AdjacencyList_edges, "f").typeOf(edge),
202
+ // @ts-expect-error TS2345
203
+ edges, nodes, __classPrivateFieldGet(this, _AdjacencyList_params, "f").unloadFactor));
204
+ // We expect to preserve the same number of edges.
205
+ (0, assert_1.default)(__classPrivateFieldGet(this, _AdjacencyList_edges, "f").count === edges.count, `Edge mismatch! ${__classPrivateFieldGet(this, _AdjacencyList_edges, "f").count} does not match ${edges.count}.`);
206
+ // Finally, copy the new data arrays over to this graph.
207
+ // @ts-expect-error TS2322
208
+ __classPrivateFieldSet(this, _AdjacencyList_nodes, nodes, "f");
209
+ // @ts-expect-error TS2322
210
+ __classPrivateFieldSet(this, _AdjacencyList_edges, edges, "f");
211
+ }
212
+ /**
213
+ * Adds a node to the graph.
214
+ *
215
+ * Note that this method does not increment the node count
216
+ * (that only happens in `addEdge`), it _may_ preemptively resize
217
+ * the nodes array if it is at capacity, under the assumption that
218
+ * at least 1 edge to or from this new node will be added.
219
+ *
220
+ * Returns the id of the added node.
221
+ */
222
+ addNode() {
223
+ let id = __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").getId();
224
+ if (__classPrivateFieldGet(this, _AdjacencyList_nodes, "f").getLoad() >= 1) {
225
+ this.resizeNodes(increaseNodeCapacity(__classPrivateFieldGet(this, _AdjacencyList_nodes, "f").capacity, __classPrivateFieldGet(this, _AdjacencyList_params, "f")));
226
+ }
227
+ return id;
228
+ }
229
+ /**
230
+ * Adds an edge to the graph.
231
+ *
232
+ * This method will increment the edge count, and it _may_
233
+ * also increment the node count, if the originating or
234
+ * terminating node does not yet have any edges of the given type.
235
+ *
236
+ * If either the `nodes` or `edges` arrays are at capacity,
237
+ * this method will resize them before adding.
238
+ *
239
+ * Furthermore, if the `edges` array has a high number of
240
+ * deleted edges, it may reclaim the space before adding.
241
+ *
242
+ * Returns `true` if the edge was added,
243
+ * or `false` if the edge already exists.
244
+ */
245
+ addEdge(from, to, type = Graph_1.NULL_EDGE_TYPE) {
246
+ (0, assert_1.default)(from < __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").nextId, `Node ${from} does not exist.`);
247
+ (0, assert_1.default)(to < __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").nextId, `Node ${to} does not exist.`);
248
+ (0, assert_1.default)(type > 0, `Unsupported edge type ${type}`);
249
+ let result;
250
+ let tries = 0;
251
+ do {
252
+ (0, assert_1.default)(tries++ < MAX_LINK_TRIES, 'Failed to addEdge too many times!');
253
+ result = link(from, to, type, __classPrivateFieldGet(this, _AdjacencyList_edges, "f"), __classPrivateFieldGet(this, _AdjacencyList_nodes, "f"), __classPrivateFieldGet(this, _AdjacencyList_params, "f").unloadFactor);
254
+ // Sometimes we need to resize before we can add.
255
+ switch (result) {
256
+ case LinkResult.NodesOverloaded: {
257
+ this.resizeNodes(increaseNodeCapacity(__classPrivateFieldGet(this, _AdjacencyList_nodes, "f").capacity, __classPrivateFieldGet(this, _AdjacencyList_params, "f")));
258
+ break;
259
+ }
260
+ case LinkResult.EdgesOverloaded: {
261
+ this.resizeEdges(increaseEdgeCapacity(__classPrivateFieldGet(this, _AdjacencyList_edges, "f").capacity, __classPrivateFieldGet(this, _AdjacencyList_params, "f")));
262
+ break;
263
+ }
264
+ case LinkResult.TooManyDeletes: {
265
+ this.resizeEdges(decreaseEdgeCapacity(__classPrivateFieldGet(this, _AdjacencyList_edges, "f").capacity, __classPrivateFieldGet(this, _AdjacencyList_params, "f")));
266
+ break;
267
+ }
268
+ }
269
+ } while (result > LinkResult.EdgeExists);
270
+ return result === LinkResult.EdgeAdded;
271
+ }
272
+ /**
273
+ * Iterate over all edges in insertion order.
274
+ */
275
+ *getAllEdges() {
276
+ for (let edge of __classPrivateFieldGet(this, _AdjacencyList_edges, "f")) {
277
+ yield {
278
+ from: __classPrivateFieldGet(this, _AdjacencyList_edges, "f").from(edge),
279
+ to: __classPrivateFieldGet(this, _AdjacencyList_edges, "f").to(edge),
280
+ type: __classPrivateFieldGet(this, _AdjacencyList_edges, "f").typeOf(edge),
281
+ };
282
+ }
283
+ }
284
+ /**
285
+ * Check if the graph has an edge connecting the `from` and `to` nodes.
286
+ */
287
+ hasEdge(from, to, type = Graph_1.NULL_EDGE_TYPE) {
288
+ let hasEdge = (type) => {
289
+ let hash = __classPrivateFieldGet(this, _AdjacencyList_edges, "f").hash(from, to, type);
290
+ return __classPrivateFieldGet(this, _AdjacencyList_edges, "f").addressOf(hash, from, to, type) !== null;
291
+ };
292
+ if (Array.isArray(type)) {
293
+ return type.some(hasEdge);
294
+ }
295
+ return hasEdge(type);
296
+ }
297
+ /**
298
+ * Remove an edge connecting the `from` and `to` nodes.
299
+ *
300
+ * Note that space for the deleted edge is not reclaimed
301
+ * until the `edges` array is resized.
302
+ *
303
+ * This method will increment the edge delete count.
304
+ */
305
+ removeEdge(from, to, type = Graph_1.NULL_EDGE_TYPE) {
306
+ let hash = __classPrivateFieldGet(this, _AdjacencyList_edges, "f").hash(from, to, type);
307
+ let edge = __classPrivateFieldGet(this, _AdjacencyList_edges, "f").addressOf(hash, from, to, type);
308
+ // The edge is not in the graph; do nothing.
309
+ if (edge === null)
310
+ return;
311
+ let toNode = (0, nullthrows_1.default)(__classPrivateFieldGet(this, _AdjacencyList_nodes, "f").addressOf(to, type));
312
+ let fromNode = (0, nullthrows_1.default)(__classPrivateFieldGet(this, _AdjacencyList_nodes, "f").addressOf(from, type));
313
+ // Update the terminating node's first and last incoming edges.
314
+ __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").unlinkIn(toNode, edge, __classPrivateFieldGet(this, _AdjacencyList_edges, "f").prevIn(edge), __classPrivateFieldGet(this, _AdjacencyList_edges, "f").nextIn(edge));
315
+ // Update the originating node's first and last outgoing edges.
316
+ __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").unlinkOut(fromNode, edge, __classPrivateFieldGet(this, _AdjacencyList_edges, "f").prevOut(edge), __classPrivateFieldGet(this, _AdjacencyList_edges, "f").nextOut(edge));
317
+ // Splice the removed edge out of the linked list of edges in the bucket.
318
+ __classPrivateFieldGet(this, _AdjacencyList_edges, "f").unlink(hash, edge);
319
+ // Splice the removed edge out of the linked list of incoming edges.
320
+ __classPrivateFieldGet(this, _AdjacencyList_edges, "f").unlinkIn(edge);
321
+ // Splice the removed edge out of the linked list of outgoing edges.
322
+ __classPrivateFieldGet(this, _AdjacencyList_edges, "f").unlinkOut(edge);
323
+ // Finally, delete the edge.
324
+ __classPrivateFieldGet(this, _AdjacencyList_edges, "f").delete(edge);
325
+ }
326
+ /**
327
+ * Check if the given node has any edges incoming from other nodes.
328
+ *
329
+ * Essentially, this is an orphan check. If a node has no incoming edges,
330
+ * it (and its entire subgraph) is completely disconnected from the
331
+ * rest of the graph.
332
+ */
333
+ hasInboundEdges(to) {
334
+ let node = __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").head(to);
335
+ while (node !== null) {
336
+ if (__classPrivateFieldGet(this, _AdjacencyList_nodes, "f").firstIn(node) !== null)
337
+ return true;
338
+ node = __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").next(node);
339
+ }
340
+ return false;
341
+ }
342
+ /**
343
+ * Get a list of every node (labeled `from`) connecting _to_
344
+ * the given `to` node, along with the edge `type` connecting them.
345
+ */
346
+ getInboundEdgesByType(to) {
347
+ let edges = [];
348
+ let node = __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").head(to);
349
+ while (node !== null) {
350
+ let type = __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").typeOf(node);
351
+ let edge = __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").firstIn(node);
352
+ while (edge !== null) {
353
+ let from = __classPrivateFieldGet(this, _AdjacencyList_edges, "f").from(edge);
354
+ edges.push({ from, type });
355
+ edge = __classPrivateFieldGet(this, _AdjacencyList_edges, "f").nextIn(edge);
356
+ }
357
+ node = __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").next(node);
358
+ }
359
+ return edges;
360
+ }
361
+ /**
362
+ * Get a list of every node (labeled `to`) connected _from_
363
+ * the given `from` node, along with the edge `type` connecting them.
364
+ */
365
+ getOutboundEdgesByType(from) {
366
+ let edges = [];
367
+ let node = __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").head(from);
368
+ while (node !== null) {
369
+ let type = __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").typeOf(node);
370
+ let edge = __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").firstOut(node);
371
+ while (edge !== null) {
372
+ let to = __classPrivateFieldGet(this, _AdjacencyList_edges, "f").to(edge);
373
+ edges.push({ to, type });
374
+ edge = __classPrivateFieldGet(this, _AdjacencyList_edges, "f").nextOut(edge);
375
+ }
376
+ node = __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").next(node);
377
+ }
378
+ return edges;
379
+ }
380
+ /**
381
+ * Get the list of node ids connected from this node.
382
+ *
383
+ * If `type` is specified, only return nodes connected by edges of that type.
384
+ * If `type` is an array, return nodes connected by edges of any of those types.
385
+ * If `type` is `AllEdgeTypes` (`-1`), return nodes connected by edges of any type.
386
+ */
387
+ getNodeIdsConnectedFrom(from, type = Graph_1.NULL_EDGE_TYPE) {
388
+ let matches = (node) => type === Graph_1.ALL_EDGE_TYPES ||
389
+ (Array.isArray(type)
390
+ ? type.includes(__classPrivateFieldGet(this, _AdjacencyList_nodes, "f").typeOf(node))
391
+ : type === __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").typeOf(node));
392
+ let nodes = [];
393
+ let seen = new Set();
394
+ let node = __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").head(from);
395
+ while (node !== null) {
396
+ if (matches(node)) {
397
+ let edge = __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").firstOut(node);
398
+ while (edge !== null) {
399
+ let to = __classPrivateFieldGet(this, _AdjacencyList_edges, "f").to(edge);
400
+ if (!seen.has(to)) {
401
+ nodes.push(to);
402
+ seen.add(to);
403
+ }
404
+ edge = __classPrivateFieldGet(this, _AdjacencyList_edges, "f").nextOut(edge);
405
+ }
406
+ }
407
+ node = __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").next(node);
408
+ }
409
+ return nodes;
410
+ }
411
+ forEachNodeIdConnectedFromReverse(from, fn, type = Graph_1.ALL_EDGE_TYPES) {
412
+ const matches = (node) => type === Graph_1.ALL_EDGE_TYPES || type === __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").typeOf(node);
413
+ let node = __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").head(from);
414
+ while (node !== null) {
415
+ if (matches(node)) {
416
+ let edge = __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").lastOut(node);
417
+ while (edge !== null) {
418
+ let to = __classPrivateFieldGet(this, _AdjacencyList_edges, "f").to(edge);
419
+ if (fn(to)) {
420
+ return;
421
+ }
422
+ edge = __classPrivateFieldGet(this, _AdjacencyList_edges, "f").prevOut(edge);
423
+ }
424
+ }
425
+ node = __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").next(node);
426
+ }
427
+ }
428
+ forEachNodeIdConnectedTo(to, fn, type = Graph_1.NULL_EDGE_TYPE) {
429
+ const matches = (node) => type === Graph_1.ALL_EDGE_TYPES || type === __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").typeOf(node);
430
+ let node = __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").head(to);
431
+ while (node !== null) {
432
+ if (matches(node)) {
433
+ let edge = __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").firstIn(node);
434
+ while (edge !== null) {
435
+ let from = __classPrivateFieldGet(this, _AdjacencyList_edges, "f").from(edge);
436
+ if (fn(from)) {
437
+ return;
438
+ }
439
+ edge = __classPrivateFieldGet(this, _AdjacencyList_edges, "f").nextIn(edge);
440
+ }
441
+ }
442
+ node = __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").next(node);
443
+ }
444
+ }
445
+ /**
446
+ * Get the list of node ids connected to this node.
447
+ *
448
+ * If `type` is specified, only return nodes connected by edges of that type.
449
+ * If `type` is an array, return nodes connected by edges of any of those types.
450
+ * If `type` is `AllEdgeTypes` (`-1`), return nodes connected by edges of any type.
451
+ */
452
+ getNodeIdsConnectedTo(to, type = Graph_1.NULL_EDGE_TYPE) {
453
+ let matches = (node) => type === Graph_1.ALL_EDGE_TYPES ||
454
+ (Array.isArray(type)
455
+ ? type.includes(__classPrivateFieldGet(this, _AdjacencyList_nodes, "f").typeOf(node))
456
+ : type === __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").typeOf(node));
457
+ let nodes = [];
458
+ let seen = new Set();
459
+ let node = __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").head(to);
460
+ while (node !== null) {
461
+ if (matches(node)) {
462
+ let edge = __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").firstIn(node);
463
+ while (edge !== null) {
464
+ let from = __classPrivateFieldGet(this, _AdjacencyList_edges, "f").from(edge);
465
+ if (!seen.has(from)) {
466
+ nodes.push(from);
467
+ seen.add(from);
468
+ }
469
+ edge = __classPrivateFieldGet(this, _AdjacencyList_edges, "f").nextIn(edge);
470
+ }
471
+ }
472
+ node = __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").next(node);
473
+ }
474
+ return nodes;
475
+ }
476
+ inspect() {
477
+ return {
478
+ nodes: __classPrivateFieldGet(this, _AdjacencyList_nodes, "f").inspect(),
479
+ edges: __classPrivateFieldGet(this, _AdjacencyList_edges, "f").inspect(),
480
+ };
481
+ }
482
+ }
483
+ _AdjacencyList_nodes = new WeakMap(), _AdjacencyList_edges = new WeakMap(), _AdjacencyList_params = new WeakMap();
484
+ exports.default = AdjacencyList;
485
+ /**
486
+ * `SharedTypeMap` is a hashmap of items,
487
+ * where each item has its own 'type' field.
488
+ *
489
+ * The `SharedTypeMap` is backed by a shared array buffer of fixed length.
490
+ * The buffer is partitioned into:
491
+ * - a header, which stores the capacity and number of items in the map,
492
+ * - a hash table, which is an array of pointers to linked lists of items
493
+ * with the same hash,
494
+ * - an items array, which is where the linked items are stored.
495
+ *
496
+ * hash table item
497
+ * (capacity) (ITEM_SIZE)
498
+ * ┌──────┴──────┐ ┌──┴──┐
499
+ * ┌──┬──┬──┬───────┬──┬──┬──┬───────┬──┬──┐
500
+ * │ │ │ │ ... │ │ │ │ ... │ │ │
501
+ * └──┴──┴──┴───────┴──┴──┴──┴───────┴──┴──┘
502
+ * └──┬──┘ └─────────┬─────────┘
503
+ * header items
504
+ * (HEADER_SIZE) (capacity * ITEM_SIZE)
505
+ *
506
+ *
507
+ * An item is added with a hash key that fits within the range of the hash
508
+ * table capacity. The item is stored at the next available address after the
509
+ * hash table, and a pointer to the address is stored in the hash table at
510
+ * the index matching the hash. If the hash is already pointing at an item,
511
+ * the pointer is stored in the `next` field of the existing item instead.
512
+ *
513
+ * hash table items
514
+ * ┌─────────┴────────┐┌───────────────────────┴────────────────────────┐
515
+ * 0 1 2 11 17 23 29 35
516
+ * ┌───┐┌───┐┌───┐┌───┐┌───┬───┐┌───┬───┐┌───┬───┐┌───┬───┐┌───┬───┐┌───┐
517
+ * │17 ││11 ││35 ││...││23 │ 1 ││29 │ 1 ││ 0 │ 2 ││ 0 │ 2 ││ 0 │ 1 ││...│
518
+ * └───┘└───┘└───┘└───┘└───┴───┘└───┴───┘└───┴───┘└───┴───┘└───┴───┘└───┘
519
+ * │ │ │ ▲ ▲ ▲ ▲ ▲
520
+ * └────┼────┼─────────┼────────┴────────┼────────┘ │
521
+ * └────┼─────────┴─────────────────┘ │
522
+ * └─────────────────────────────────────────────┘
523
+ */
524
+ class SharedTypeMap {
525
+ /** The largest possible capacity. */
526
+ // @ts-expect-error TS1094
527
+ static get MAX_CAPACITY<TItemType, THash, TAddress extends number>() {
528
+ return Math.floor(
529
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Invalid_array_length#what_went_wrong
530
+ (2 ** 31 - 1 - this.HEADER_SIZE) / this.ITEM_SIZE);
531
+ }
532
+ /** Assert that the given `capacity` does not exceed `MAX_CAPACITY`. */
533
+ static assertMaxCapacity(capacity) {
534
+ (0, assert_1.default)(capacity <= this.MAX_CAPACITY, `${this.name} capacity overflow!`);
535
+ }
536
+ /** The total number of items that can fit in the map. */
537
+ get capacity() {
538
+ return this.data[__classPrivateFieldGet(_a, _a, "f", _SharedTypeMap_CAPACITY)];
539
+ }
540
+ /** The number of items in the map. */
541
+ get count() {
542
+ return this.data[__classPrivateFieldGet(_a, _a, "f", _SharedTypeMap_COUNT)];
543
+ }
544
+ /** The ratio of the count to the capacity. */
545
+ get load() {
546
+ return this.getLoad();
547
+ }
548
+ /** The total length of the map, in bytes. */
549
+ get length() {
550
+ return this.getLength();
551
+ }
552
+ /** The address of the first item in the map. */
553
+ get addressableLimit() {
554
+ // @ts-expect-error TS2339
555
+ return this.constructor.HEADER_SIZE + this.capacity;
556
+ }
557
+ /** The size of the map in mb, as a localized string. */
558
+ get bufferSize() {
559
+ return `${(this.data.byteLength / 1024 / 1024).toLocaleString(undefined, {
560
+ minimumFractionDigits: 2,
561
+ maximumFractionDigits: 2,
562
+ })} mb`;
563
+ }
564
+ /**
565
+ * Create a new `SharedTypeMap` in one of two ways:
566
+ * - with a capacity of `capacityOrData` if it is a number,
567
+ * - or with `capacityOrData` as its data, if it is a `Uint32Array`.
568
+ */
569
+ constructor(capacityOrData) {
570
+ if (typeof capacityOrData === 'number') {
571
+ let { BYTES_PER_ELEMENT } = Uint32Array;
572
+ let CAPACITY = __classPrivateFieldGet(_a, _a, "f", _SharedTypeMap_CAPACITY);
573
+ this.data = new Uint32Array(new shared_buffer_1.SharedBuffer(this.getLength(capacityOrData) * BYTES_PER_ELEMENT));
574
+ this.data[CAPACITY] = capacityOrData;
575
+ }
576
+ else {
577
+ this.data = capacityOrData;
578
+ (0, assert_1.default)(this.getLength() === this.data.length, 'Data appears corrupt.');
579
+ }
580
+ }
581
+ /**
582
+ * Overwrite the data in this map with the given `data`.
583
+ *
584
+ * The `data` is expected to conform to the same
585
+ * partitioning and schema as the data in this map,
586
+ * and is expected to be of equal or smaller capacity to this map.
587
+ */
588
+ set(data) {
589
+ // @ts-expect-error TS2339
590
+ let { HEADER_SIZE, ITEM_SIZE } = this.constructor;
591
+ let NEXT = __classPrivateFieldGet(_a, _a, "f", _SharedTypeMap_NEXT);
592
+ let COUNT = __classPrivateFieldGet(_a, _a, "f", _SharedTypeMap_COUNT);
593
+ let CAPACITY = __classPrivateFieldGet(_a, _a, "f", _SharedTypeMap_CAPACITY);
594
+ let delta = this.capacity - data[CAPACITY];
595
+ (0, assert_1.default)(delta >= 0, 'Cannot copy to a map with smaller capacity.');
596
+ // Copy the header.
597
+ this.data.set(data.subarray(COUNT, HEADER_SIZE), COUNT);
598
+ // Copy the hash table.
599
+ let toTable = this.data.subarray(HEADER_SIZE, HEADER_SIZE + this.capacity);
600
+ toTable.set(data.subarray(HEADER_SIZE, HEADER_SIZE + data[CAPACITY]));
601
+ // Offset first links to account for the change in table capacity.
602
+ let max = toTable.length;
603
+ for (let i = 0; i < max; i++) {
604
+ if (toTable[i])
605
+ toTable[i] += delta;
606
+ }
607
+ // Copy the items.
608
+ let toItems = this.data.subarray(HEADER_SIZE + this.capacity);
609
+ toItems.set(data.subarray(HEADER_SIZE + data[CAPACITY]));
610
+ // Offset next links to account for the change in table capacity.
611
+ max = toItems.length;
612
+ for (let i = 0; i < max; i += ITEM_SIZE) {
613
+ if (toItems[i + NEXT])
614
+ toItems[i + NEXT] += delta;
615
+ }
616
+ }
617
+ /**
618
+ * Given a `count` (defaulting to `this.count`),
619
+ * get the load on the map.
620
+ *
621
+ * The load is the ratio of the `count` the capacity of the map.
622
+ *
623
+ * If the load is `1`, it means the map is at capacity, and needs
624
+ * to be resized before adding more items.
625
+ */
626
+ getLoad(count = this.count) {
627
+ return count / this.capacity;
628
+ }
629
+ /**
630
+ * Given a `capacity` (defaulting to `this.capacity`),
631
+ * get the length of the map, in bytes.
632
+ */
633
+ getLength(capacity = this.capacity) {
634
+ // @ts-expect-error TS2339
635
+ let { HEADER_SIZE, ITEM_SIZE } = this.constructor;
636
+ return capacity + HEADER_SIZE + ITEM_SIZE * capacity;
637
+ }
638
+ /** Get the next available address in the map. */
639
+ getNextAddress() {
640
+ // @ts-expect-error TS2339
641
+ let { HEADER_SIZE, ITEM_SIZE } = this.constructor;
642
+ return (HEADER_SIZE + this.capacity + this.count * ITEM_SIZE);
643
+ }
644
+ /** Get the address of the first item with the given hash. */
645
+ head(hash) {
646
+ // @ts-expect-error TS2339
647
+ let { HEADER_SIZE } = this.constructor;
648
+ return this.data[HEADER_SIZE + hash] || null;
649
+ }
650
+ /** Get the address of the next item with the same hash as the given item. */
651
+ next(item) {
652
+ let NEXT = __classPrivateFieldGet(_a, _a, "f", _SharedTypeMap_NEXT);
653
+ return this.data[item + NEXT] || null;
654
+ }
655
+ /** Get the type of the item at the given `item` address. */
656
+ typeOf(item) {
657
+ return this.data[item + __classPrivateFieldGet(_a, _a, "f", _SharedTypeMap_TYPE)];
658
+ }
659
+ /**
660
+ * Store an item of `type` at the `item` address and
661
+ * link the address to the `hash` bucket.
662
+ */
663
+ link(hash, item, type) {
664
+ let COUNT = __classPrivateFieldGet(_a, _a, "f", _SharedTypeMap_COUNT);
665
+ let NEXT = __classPrivateFieldGet(_a, _a, "f", _SharedTypeMap_NEXT);
666
+ let TYPE = __classPrivateFieldGet(_a, _a, "f", _SharedTypeMap_TYPE);
667
+ // @ts-expect-error TS2339
668
+ let { HEADER_SIZE } = this.constructor;
669
+ this.data[item + TYPE] = type;
670
+ let prev = this.head(hash);
671
+ if (prev !== null) {
672
+ let next = this.next(prev);
673
+ while (next !== null) {
674
+ prev = next;
675
+ next = this.next(next);
676
+ }
677
+ this.data[prev + NEXT] = item;
678
+ }
679
+ else {
680
+ // This is the first item in the bucket!
681
+ this.data[HEADER_SIZE + hash] = item;
682
+ }
683
+ this.data[COUNT]++;
684
+ }
685
+ /**
686
+ * Remove the link to the `item` address from the `hash` bucket.
687
+ */
688
+ unlink(hash, item) {
689
+ let COUNT = __classPrivateFieldGet(_a, _a, "f", _SharedTypeMap_COUNT);
690
+ let NEXT = __classPrivateFieldGet(_a, _a, "f", _SharedTypeMap_NEXT);
691
+ let TYPE = __classPrivateFieldGet(_a, _a, "f", _SharedTypeMap_TYPE);
692
+ // @ts-expect-error TS2339
693
+ let { HEADER_SIZE } = this.constructor;
694
+ this.data[item + TYPE] = 0;
695
+ let head = this.head(hash);
696
+ // No bucket to unlink from.
697
+ if (head === null)
698
+ return;
699
+ let next = this.next(item);
700
+ let prev = null;
701
+ let candidate = head;
702
+ while (candidate !== null && candidate !== item) {
703
+ prev = candidate;
704
+ // @ts-expect-error TS2322
705
+ candidate = this.next(candidate);
706
+ }
707
+ if (prev !== null && next !== null) {
708
+ this.data[prev + NEXT] = next;
709
+ }
710
+ else if (prev !== null) {
711
+ this.data[prev + NEXT] = 0;
712
+ }
713
+ else if (next !== null) {
714
+ this.data[HEADER_SIZE + hash] = next;
715
+ }
716
+ else {
717
+ this.data[HEADER_SIZE + hash] = 0;
718
+ }
719
+ this.data[item + NEXT] = 0;
720
+ this.data[COUNT]--;
721
+ }
722
+ forEach(cb) {
723
+ let max = this.count;
724
+ let len = this.length;
725
+ // @ts-expect-error TS2339
726
+ let { ITEM_SIZE } = this.constructor;
727
+ for (let i = this.addressableLimit, count = 0; i < len && count < max; i += ITEM_SIZE) {
728
+ // Skip items that don't have a type.
729
+ if (this.typeOf(i)) {
730
+ cb(i);
731
+ count++;
732
+ }
733
+ }
734
+ }
735
+ // Trick Flow into believing in `Symbol.iterator`.
736
+ // See https://github.com/facebook/flow/issues/1163#issuecomment-353523840
737
+ /*:: @@iterator(): Iterator<TAddress> { return ({}: any); } */
738
+ *[Symbol.iterator]() {
739
+ let max = this.count;
740
+ let len = this.length;
741
+ // @ts-expect-error TS2339
742
+ let { ITEM_SIZE } = this.constructor;
743
+ for (let i = this.addressableLimit, count = 0; i < len && count < max; i += ITEM_SIZE) {
744
+ if (this.data.subarray(i, i + ITEM_SIZE).some(Boolean)) {
745
+ yield i;
746
+ count++;
747
+ }
748
+ }
749
+ }
750
+ inspect() {
751
+ // @ts-expect-error TS2339
752
+ const { HEADER_SIZE } = this.constructor;
753
+ let min = this.addressableLimit;
754
+ return {
755
+ header: this.data.subarray(0, HEADER_SIZE),
756
+ table: this.data.subarray(HEADER_SIZE, min),
757
+ data: this.data.subarray(min),
758
+ };
759
+ }
760
+ }
761
+ exports.SharedTypeMap = SharedTypeMap;
762
+ _a = SharedTypeMap;
763
+ /**
764
+ * The header for the `SharedTypeMap` comprises 2 4-byte chunks:
765
+ *
766
+ * struct SharedTypeMapHeader {
767
+ * int capacity;
768
+ * int count;
769
+ * }
770
+ *
771
+ * ┌──────────┬───────┐
772
+ * │ CAPACITY │ COUNT │
773
+ * └──────────┴───────┘
774
+ */
775
+ SharedTypeMap.HEADER_SIZE = 2;
776
+ /** The offset from the header where the capacity is stored. */
777
+ _SharedTypeMap_CAPACITY = { value: 0 };
778
+ /** The offset from the header where the count is stored. */
779
+ _SharedTypeMap_COUNT = { value: 1 };
780
+ /**
781
+ * Each item in `SharedTypeMap` comprises 2 4-byte chunks:
782
+ *
783
+ * struct Node {
784
+ * int next;
785
+ * int type;
786
+ * }
787
+ *
788
+ * ┌──────┬──────┐
789
+ * │ NEXT │ TYPE │
790
+ * └──────┴──────┘
791
+ */
792
+ SharedTypeMap.ITEM_SIZE = 2;
793
+ /** The offset at which a link to the next item in the same bucket is stored. */
794
+ _SharedTypeMap_NEXT = { value: 0 };
795
+ /** The offset at which an item's type is stored. */
796
+ _SharedTypeMap_TYPE = { value: 1 };
797
+ /**
798
+ * Nodes are stored in a `SharedTypeMap`, keyed on node id plus an edge type.
799
+ * This means that for any given unique node id, there may be `e` nodes in the
800
+ * map, where `e` is the number of unique edge types in the graph.
801
+ *
802
+ * The _hash_ for a node is simply the node id (as issued by `getId`),
803
+ * and forms the head of linked list of unique _edge types_ connected
804
+ * to or from the same node id.
805
+ *
806
+ * In addition to a unique edge type, each Node contains the heads and tails
807
+ * of doubly linked lists of incoming and outgoing edges of the same type.
808
+ *
809
+ * Note that the links in the doubly linked lists are Edges (not Nodes),
810
+ * which are stored in a corresponding `EdgeTypeMap`.
811
+ */
812
+ class NodeTypeMap extends SharedTypeMap {
813
+ get nextId() {
814
+ return (0, types_1.toNodeId)(this.data[__classPrivateFieldGet(_b, _b, "f", _NodeTypeMap_NEXT_ID)]);
815
+ }
816
+ set nextId(nextId) {
817
+ this.data[__classPrivateFieldGet(_b, _b, "f", _NodeTypeMap_NEXT_ID)] = (0, types_1.fromNodeId)(nextId);
818
+ }
819
+ /**
820
+ * Get the load on the node map.
821
+ *
822
+ * The load is the greater of either:
823
+ * - the ratio of the number of node ids to the capacity of the map,
824
+ * - or the ratio of the `count` to the capacity of the map.
825
+ *
826
+ * if `count` is not provided, the default is the number of items
827
+ * currently added to the map.
828
+ */
829
+ getLoad(count) {
830
+ return Math.max((0, types_1.fromNodeId)(this.nextId) / this.capacity, super.getLoad(count));
831
+ }
832
+ /** Increment the node counter to get a unique node id. */
833
+ getId() {
834
+ return (0, types_1.toNodeId)(this.data[__classPrivateFieldGet(_b, _b, "f", _NodeTypeMap_NEXT_ID)]++);
835
+ }
836
+ /**
837
+ * Add new lists of edges of the given `type` to and from the given `node`.
838
+ */
839
+ add(node, type) {
840
+ let index = (0, types_1.fromNodeId)(node);
841
+ (0, assert_1.default)(index >= 0 && index < this.data[__classPrivateFieldGet(_b, _b, "f", _NodeTypeMap_NEXT_ID)], `Invalid node id ${String(node)} (${this.data[__classPrivateFieldGet(_b, _b, "f", _NodeTypeMap_NEXT_ID)]})`);
842
+ let address = this.getNextAddress();
843
+ this.link(node, address, type);
844
+ return address;
845
+ }
846
+ /**
847
+ * Get the address of the lists edges of the given `type`
848
+ * to and from the given `node`.
849
+ */
850
+ addressOf(node, type) {
851
+ let address = this.head(node);
852
+ while (address !== null) {
853
+ if (this.typeOf(address) === type) {
854
+ return address;
855
+ }
856
+ address = this.next(address);
857
+ }
858
+ return null;
859
+ }
860
+ /**
861
+ * Given a `node` address, get the _head_ of the linked list
862
+ * of incoming edges of the same type to the same node.
863
+ */
864
+ firstIn(node) {
865
+ return this.data[node + __classPrivateFieldGet(_b, _b, "f", _NodeTypeMap_FIRST_IN)] || null;
866
+ }
867
+ /**
868
+ * Given a `node` address, get the _head_ of the linked list
869
+ * of outgoing edges of the same type from the same node.
870
+ */
871
+ firstOut(node) {
872
+ return this.data[node + __classPrivateFieldGet(_b, _b, "f", _NodeTypeMap_FIRST_OUT)] || null;
873
+ }
874
+ /**
875
+ * Given a `node` address, get the _tail_ of the linked list
876
+ * of incoming edges of the same type to the same node.
877
+ */
878
+ lastIn(node) {
879
+ return this.data[node + __classPrivateFieldGet(_b, _b, "f", _NodeTypeMap_LAST_IN)] || null;
880
+ }
881
+ /**
882
+ * Given a `node` address, get the _tail_ of the linked list
883
+ * of outgoing edges of the same type from the same node.
884
+ */
885
+ lastOut(node) {
886
+ return this.data[node + __classPrivateFieldGet(_b, _b, "f", _NodeTypeMap_LAST_OUT)] || null;
887
+ }
888
+ /**
889
+ * Set `edge` as the last incoming edge to `node`.
890
+ * If `node` has no incoming edges, set `edge`
891
+ * as the first incoming edge, as well.
892
+ *
893
+ * Returns the address of the old last incoming edge, if any.
894
+ */
895
+ linkIn(node, edge) {
896
+ let first = this.firstIn(node);
897
+ let last = this.lastIn(node);
898
+ if (first === null)
899
+ this.data[node + __classPrivateFieldGet(_b, _b, "f", _NodeTypeMap_FIRST_IN)] = edge;
900
+ this.data[node + __classPrivateFieldGet(_b, _b, "f", _NodeTypeMap_LAST_IN)] = edge;
901
+ return last;
902
+ }
903
+ /**
904
+ * If `edge` is the last incoming edge to `node`,
905
+ * update the node's last incoming edge to `prev`.
906
+ *
907
+ * If `edge` is the first incoming edge to `node`,
908
+ * update the node's first incoming edge to `next`.
909
+ */
910
+ unlinkIn(node, edge, prev, next) {
911
+ let first = this.firstIn(node);
912
+ let last = this.lastIn(node);
913
+ if (last === edge) {
914
+ this.data[node + __classPrivateFieldGet(_b, _b, "f", _NodeTypeMap_LAST_IN)] = prev === null ? 0 : prev;
915
+ }
916
+ if (first === edge) {
917
+ this.data[node + __classPrivateFieldGet(_b, _b, "f", _NodeTypeMap_FIRST_IN)] = next === null ? 0 : next;
918
+ }
919
+ }
920
+ /**
921
+ * Set `edge` as the last outgoing edge from `node`.
922
+ * If `node` has no outgoing edges, set `edge`
923
+ * as the first outgoing edge, as well.
924
+ *
925
+ * Returns the address of the old last outgoing edge, if any.
926
+ */
927
+ linkOut(node, edge) {
928
+ let first = this.firstOut(node);
929
+ let last = this.lastOut(node);
930
+ if (first === null)
931
+ this.data[node + __classPrivateFieldGet(_b, _b, "f", _NodeTypeMap_FIRST_OUT)] = edge;
932
+ this.data[node + __classPrivateFieldGet(_b, _b, "f", _NodeTypeMap_LAST_OUT)] = edge;
933
+ return last;
934
+ }
935
+ /**
936
+ * If `edge` is the last outgoing edge from `node`,
937
+ * update the node's last outgoing edge to `prev`.
938
+ *
939
+ * If `edge` is the first outgoing edge from `node`,
940
+ * update the node's first outgoing edge to `next`.
941
+ */
942
+ unlinkOut(node, edge, prev, next) {
943
+ let first = this.firstOut(node);
944
+ let last = this.lastOut(node);
945
+ if (last === edge) {
946
+ this.data[node + __classPrivateFieldGet(_b, _b, "f", _NodeTypeMap_LAST_OUT)] = prev === null ? 0 : prev;
947
+ }
948
+ if (first === edge) {
949
+ this.data[node + __classPrivateFieldGet(_b, _b, "f", _NodeTypeMap_FIRST_OUT)] = next === null ? 0 : next;
950
+ }
951
+ }
952
+ }
953
+ exports.NodeTypeMap = NodeTypeMap;
954
+ _b = NodeTypeMap;
955
+ /**
956
+ * In addition to the header defined by `SharedTypeMap`, the header for
957
+ * the node map includes a 4-byte `nextId` chunk:
958
+ *
959
+ * struct NodeTypeMapHeader {
960
+ * int capacity; // from `SharedTypeMap`
961
+ * int count; // from `SharedTypeMap`
962
+ * int nextId;
963
+ * }
964
+ *
965
+ * ┌──────────┬───────┬─────────┐
966
+ * │ CAPACITY │ COUNT │ NEXT_ID │
967
+ * └──────────┴───────┴─────────┘
968
+ *
969
+ * The `nextId` is a count of the number of times `getId` has been called.
970
+ * This is distinct concept from the `count`, which tracks the number of times
971
+ * `add` has been called.
972
+ *
973
+ * The reason for this distinction is that `getId` is called once per node
974
+ * (to issue a _unique_ id) and will _always increment_ the `nextId` counter,
975
+ * whereas `add` is called once per edge, and will only increment the `count`
976
+ * if the _type_ of edge is new for the given node.
977
+ */
978
+ NodeTypeMap.HEADER_SIZE = 3;
979
+ /** The offset from the header where the next available node id is stored. */
980
+ _NodeTypeMap_NEXT_ID = { value: 2 };
981
+ /**
982
+ * In addition to the item fields defined by `SharedTypeMap`,
983
+ * each node includes another 4 4-byte chunks:
984
+ *
985
+ * struct Node {
986
+ * int next; // from `SharedTypeMap`
987
+ * int type; // from `SharedTypeMap`
988
+ * int firstIn;
989
+ * int firstOut;
990
+ * int lastIn;
991
+ * int lastOut;
992
+ * }
993
+ *
994
+ * ┌──────┬──────┬──────────┬───────────┬─────────┬──────────┐
995
+ * │ NEXT │ TYPE │ FIRST_IN │ FIRST_OUT │ LAST_IN │ LAST_OUT │
996
+ * └──────┴──────┴──────────┴───────────┴─────────┴──────────┘
997
+ *
998
+ * The `Node` implicitly maps a node id (the hash the node was added with)
999
+ * to the first and last incoming and outgoing edges of the same _edge type_.
1000
+ */
1001
+ NodeTypeMap.ITEM_SIZE = 6;
1002
+ /** The offset at which a node's first incoming edge of this type is stored. */
1003
+ _NodeTypeMap_FIRST_IN = { value: 2 };
1004
+ /** The offset at which a node's first outgoing edge of this type is stored. */
1005
+ _NodeTypeMap_FIRST_OUT = { value: 3 };
1006
+ /** The offset at which a node's last incoming edge of this type is stored. */
1007
+ _NodeTypeMap_LAST_IN = { value: 4 };
1008
+ /** The offset at which a node's last outgoing edge of this type is stored. */
1009
+ _NodeTypeMap_LAST_OUT = { value: 5 };
1010
+ /**
1011
+ * Edges are stored in a `SharedTypeMap`,
1012
+ * keyed on the 'from' and 'to' node ids, and the edge type.
1013
+ *
1014
+ * The _hash_ for an edge is a hash of the edge's `from`, `to`, and `type` values,
1015
+ * and forms the head of linked list of edges with the same hash.
1016
+ *
1017
+ * In addition to the `from`, `to` and `type` values, each Edge contains
1018
+ * the next and previous links of doubly linked lists of the _adjacent_ edges
1019
+ * of the same type, both incoming to the `to` node, and outgoing from
1020
+ * the `from` node.
1021
+ */
1022
+ class EdgeTypeMap extends SharedTypeMap {
1023
+ /** The number of deleted edges currently occupying space in the map. */
1024
+ get deletes() {
1025
+ return this.data[__classPrivateFieldGet(_c, _c, "f", _EdgeTypeMap_DELETES)];
1026
+ }
1027
+ /** Get the next available address in the map. */
1028
+ getNextAddress() {
1029
+ // @ts-expect-error TS2339
1030
+ let { ITEM_SIZE } = this.constructor;
1031
+ return this.addressableLimit + (this.count + this.deletes) * ITEM_SIZE;
1032
+ }
1033
+ /**
1034
+ * Add an edge of the given `type` between the `to` and `from` nodes
1035
+ * and link the address to the `hash` bucket.
1036
+ */
1037
+ add(hash, from, to, type) {
1038
+ (0, assert_1.default)(hash >= 0 && hash < this.capacity, `Invalid edge hash ${String(hash)}`);
1039
+ // Use the next available edge address.
1040
+ let edge = this.getNextAddress();
1041
+ // Add our new edge to its hash bucket.
1042
+ this.link(hash, edge, type);
1043
+ this.data[edge + __classPrivateFieldGet(_c, _c, "f", _EdgeTypeMap_FROM)] = (0, types_1.fromNodeId)(from);
1044
+ this.data[edge + __classPrivateFieldGet(_c, _c, "f", _EdgeTypeMap_TO)] = (0, types_1.fromNodeId)(to);
1045
+ return edge;
1046
+ }
1047
+ /**
1048
+ * Remove the `to` and `from` nodes for the given `edge` address
1049
+ * and increment the `deletes` counter.
1050
+ */
1051
+ delete(edge) {
1052
+ this.data[edge + __classPrivateFieldGet(_c, _c, "f", _EdgeTypeMap_FROM)] = 0;
1053
+ this.data[edge + __classPrivateFieldGet(_c, _c, "f", _EdgeTypeMap_TO)] = 0;
1054
+ this.data[__classPrivateFieldGet(_c, _c, "f", _EdgeTypeMap_DELETES)]++;
1055
+ }
1056
+ /**
1057
+ * Get the address of the edge with the given `hash`, `from` and `to` nodes,
1058
+ * and edge `type`.
1059
+ */
1060
+ addressOf(hash, from, to, type) {
1061
+ let address = this.head(hash);
1062
+ while (address !== null) {
1063
+ if (this.typeOf(address) === type &&
1064
+ this.from(address) === from &&
1065
+ this.to(address) === to) {
1066
+ return address;
1067
+ }
1068
+ address = this.next(address);
1069
+ }
1070
+ return null;
1071
+ }
1072
+ /** Get the id of the 'from' node for the given `edge` address. */
1073
+ from(edge) {
1074
+ return (0, types_1.toNodeId)(this.data[edge + __classPrivateFieldGet(_c, _c, "f", _EdgeTypeMap_FROM)]);
1075
+ }
1076
+ /** Get the id of the 'to' node for the given `edge` address. */
1077
+ to(edge) {
1078
+ return (0, types_1.toNodeId)(this.data[edge + __classPrivateFieldGet(_c, _c, "f", _EdgeTypeMap_TO)]);
1079
+ }
1080
+ /**
1081
+ * Get the address of the next edge _of the same type_
1082
+ * incoming _to the same node_ as the edge at the given address.
1083
+ */
1084
+ nextIn(edge) {
1085
+ return this.data[edge + __classPrivateFieldGet(_c, _c, "f", _EdgeTypeMap_NEXT_IN)] || null;
1086
+ }
1087
+ /**
1088
+ * Get the address of the previous edge _of the same type_
1089
+ * incoming _to the same node_ as the edge at the given address.
1090
+ */
1091
+ prevIn(edge) {
1092
+ return this.data[edge + __classPrivateFieldGet(_c, _c, "f", _EdgeTypeMap_PREV_IN)] || null;
1093
+ }
1094
+ /** Link two adjacent edges of the same type incoming to the same node. */
1095
+ linkIn(edge, next) {
1096
+ (0, assert_1.default)(this.typeOf(edge) === this.typeOf(next), 'Edge types must match.');
1097
+ (0, assert_1.default)(this.to(edge) === this.to(next), 'To nodes must match.');
1098
+ this.data[edge + __classPrivateFieldGet(_c, _c, "f", _EdgeTypeMap_NEXT_IN)] = next;
1099
+ this.data[next + __classPrivateFieldGet(_c, _c, "f", _EdgeTypeMap_PREV_IN)] = edge;
1100
+ }
1101
+ /**
1102
+ * Unlink an edge from the doubly linked list of incoming edges
1103
+ * to the same node.
1104
+ */
1105
+ unlinkIn(edge) {
1106
+ let next = this.nextIn(edge);
1107
+ let prev = this.prevIn(edge);
1108
+ this.data[edge + __classPrivateFieldGet(_c, _c, "f", _EdgeTypeMap_NEXT_IN)] = 0;
1109
+ this.data[edge + __classPrivateFieldGet(_c, _c, "f", _EdgeTypeMap_PREV_IN)] = 0;
1110
+ if (next !== null && prev !== null) {
1111
+ this.data[prev + __classPrivateFieldGet(_c, _c, "f", _EdgeTypeMap_NEXT_IN)] = next;
1112
+ this.data[next + __classPrivateFieldGet(_c, _c, "f", _EdgeTypeMap_PREV_IN)] = prev;
1113
+ }
1114
+ else if (next !== null) {
1115
+ this.data[next + __classPrivateFieldGet(_c, _c, "f", _EdgeTypeMap_PREV_IN)] = 0;
1116
+ }
1117
+ else if (prev !== null) {
1118
+ this.data[prev + __classPrivateFieldGet(_c, _c, "f", _EdgeTypeMap_NEXT_IN)] = 0;
1119
+ }
1120
+ }
1121
+ /**
1122
+ * Get the address of the next edge _of the same type_
1123
+ * outgoing _from the same node_ as the edge at the given address.
1124
+ */
1125
+ nextOut(edge) {
1126
+ return this.data[edge + __classPrivateFieldGet(_c, _c, "f", _EdgeTypeMap_NEXT_OUT)] || null;
1127
+ }
1128
+ /**
1129
+ * Get the address of the previous edge _of the same type_
1130
+ * outgoing _from the same node_ as the edge at the given address.
1131
+ */
1132
+ prevOut(edge) {
1133
+ return this.data[edge + __classPrivateFieldGet(_c, _c, "f", _EdgeTypeMap_PREV_OUT)] || null;
1134
+ }
1135
+ /** Link two adjacent edges of the same type outgoing from the same node. */
1136
+ linkOut(edge, next) {
1137
+ (0, assert_1.default)(this.typeOf(edge) === this.typeOf(next), 'Edge types must match.');
1138
+ (0, assert_1.default)(this.from(edge) === this.from(next), 'From nodes must match.');
1139
+ this.data[edge + __classPrivateFieldGet(_c, _c, "f", _EdgeTypeMap_NEXT_OUT)] = next;
1140
+ this.data[next + __classPrivateFieldGet(_c, _c, "f", _EdgeTypeMap_PREV_OUT)] = edge;
1141
+ }
1142
+ /**
1143
+ * Unlink an edge from the doubly linked list of outgoing edges
1144
+ * of the same type from the same node.
1145
+ */
1146
+ unlinkOut(edge) {
1147
+ let next = this.nextOut(edge);
1148
+ let prev = this.prevOut(edge);
1149
+ this.data[edge + __classPrivateFieldGet(_c, _c, "f", _EdgeTypeMap_NEXT_OUT)] = 0;
1150
+ this.data[edge + __classPrivateFieldGet(_c, _c, "f", _EdgeTypeMap_PREV_OUT)] = 0;
1151
+ if (next !== null && prev !== null) {
1152
+ this.data[prev + __classPrivateFieldGet(_c, _c, "f", _EdgeTypeMap_NEXT_OUT)] = next;
1153
+ this.data[next + __classPrivateFieldGet(_c, _c, "f", _EdgeTypeMap_PREV_OUT)] = prev;
1154
+ }
1155
+ else if (next !== null) {
1156
+ this.data[next + __classPrivateFieldGet(_c, _c, "f", _EdgeTypeMap_PREV_OUT)] = 0;
1157
+ }
1158
+ else if (prev !== null) {
1159
+ this.data[prev + __classPrivateFieldGet(_c, _c, "f", _EdgeTypeMap_NEXT_OUT)] = 0;
1160
+ }
1161
+ }
1162
+ /** Create a hash of the edge connecting the `from` and `to` nodes. */
1163
+ hash(from, to, type) {
1164
+ // Each parameter is hashed by mixing its upper bits into its lower bits to
1165
+ // increase the likelihood that a change to any bit of the input will vary
1166
+ // the output widely. Then we do a series of prime multiplications and
1167
+ // additions to combine the hashes into one value.
1168
+ let hash = 17;
1169
+ hash = hash * 37 + hash32shift(from);
1170
+ hash = hash * 37 + hash32shift(to);
1171
+ hash = hash * 37 + hash32shift(type);
1172
+ // Finally, we map the hash to a value modulo the edge capacity.
1173
+ hash %= this.capacity;
1174
+ return hash;
1175
+ }
1176
+ }
1177
+ exports.EdgeTypeMap = EdgeTypeMap;
1178
+ _c = EdgeTypeMap;
1179
+ /**
1180
+ * In addition to the header defined by `SharedTypeMap`, the header for
1181
+ * the edge map includes a 4-byte `deletes` chunk:
1182
+ *
1183
+ * struct EdgeTypeMapHeader {
1184
+ * int capacity; // from `SharedTypeMap`
1185
+ * int count; // from `SharedTypeMap`
1186
+ * int deletes;
1187
+ * }
1188
+ *
1189
+ * ┌──────────┬───────┬─────────┐
1190
+ * │ CAPACITY │ COUNT │ DELETES │
1191
+ * └──────────┴───────┴─────────┘
1192
+ *
1193
+ * Since new edges are always appended, the space for deleted edges
1194
+ * is not reused. Instead, the `deletes` count is incremented when an
1195
+ * edge is deleted. The next available address is calculated by
1196
+ * adding the `count` and `deletes` values to the header size.
1197
+ *
1198
+ * The only way to reclaim the space used by deleted edges is to resize the map.
1199
+ */
1200
+ EdgeTypeMap.HEADER_SIZE = 3;
1201
+ /** The offset from the header where the delete count is stored. */
1202
+ _EdgeTypeMap_DELETES = { value: 2 };
1203
+ /**
1204
+ * In addition to the item fields defined by `SharedTypeMap`,
1205
+ * each edge includes another 6 4-byte chunks:
1206
+ *
1207
+ * struct Edge {
1208
+ * int next; // from `SharedTypeMap`
1209
+ * int type; // from `SharedTypeMap`
1210
+ * int from;
1211
+ * int to;
1212
+ * int nextIn;
1213
+ * int prevIn;
1214
+ * int nextOut;
1215
+ * int prevOut;
1216
+ * }
1217
+ *
1218
+ * ┌──────┬──────┬──────┬────┬─────────┬─────────┬──────────┬──────────┐
1219
+ * │ NEXT │ TYPE │ FROM │ TO │ NEXT_IN │ PREV_IN │ NEXT_OUT │ PREV_OUT │
1220
+ * └──────┴──────┴──────┴────┴─────────┴─────────┴──────────┴──────────┘
1221
+ *
1222
+ * The `Edge` implicitly maps an edge hash (the hash of the edge's `FROM`,
1223
+ * `TO`, and `TYPE` values) to the next and previous adjacent edges of the
1224
+ * same _edge type_.
1225
+ */
1226
+ EdgeTypeMap.ITEM_SIZE = 8;
1227
+ /** The offset at which an edge's 'from' node id is stored. */
1228
+ _EdgeTypeMap_FROM = { value: 2 };
1229
+ /** The offset at which an edge's 'to' node id is stored. */
1230
+ _EdgeTypeMap_TO = { value: 3 };
1231
+ /** The offset at which the 'to' node's next incoming edge is stored. */
1232
+ _EdgeTypeMap_NEXT_IN = { value: 4 };
1233
+ /** The offset at which the 'to' node's previous incoming edge is stored. */
1234
+ _EdgeTypeMap_PREV_IN = { value: 5 };
1235
+ /** The offset at which the 'from' node's next outgoing edge is stored. */
1236
+ _EdgeTypeMap_NEXT_OUT = { value: 6 };
1237
+ /** The offset at which the 'from' node's previous outgoing edge is stored. */
1238
+ _EdgeTypeMap_PREV_OUT = { value: 7 };
1239
+ /**
1240
+ * Links a node to another node with an edge of the given type.
1241
+ *
1242
+ * Returns one of the following numeric status codes:
1243
+ * - `0` EdgeAdded: the edge was added
1244
+ * - `1` EdgeExists: the edge already exists
1245
+ * - `2` EdgesOverloaded: the edge map is overloaded
1246
+ * - `3` TooManyDeletes: the edge map has too many deleted edges
1247
+ * - `4` NodesOverloaded: the node map is overloaded
1248
+ */
1249
+ function link(from, to, type, edges, nodes, unloadFactor = DEFAULT_PARAMS.unloadFactor) {
1250
+ let hash = edges.hash(from, to, type);
1251
+ let edge = edges.addressOf(hash, from, to, type);
1252
+ // The edge is already in the graph; do nothing.
1253
+ if (edge !== null)
1254
+ return LinkResult.EdgeExists;
1255
+ let toNode = nodes.addressOf(to, type);
1256
+ let fromNode = nodes.addressOf(from, type);
1257
+ let nodeCount = nodes.count;
1258
+ // add one for each node we must add.
1259
+ if (toNode === null)
1260
+ nodeCount++;
1261
+ if (fromNode === null)
1262
+ nodeCount++;
1263
+ // If we're in danger of overflowing the `nodes` array, resize it.
1264
+ if (nodes.getLoad(nodeCount) >= 1) {
1265
+ return LinkResult.NodesOverloaded;
1266
+ }
1267
+ // We add 1 to account for the edge we are adding.
1268
+ let count = edges.count + 1;
1269
+ // Since the space occupied by deleted edges isn't reclaimed,
1270
+ // we include them in our count to avoid overflowing the `edges` array.
1271
+ let deletes = edges.deletes;
1272
+ let total = count + deletes;
1273
+ if (edges.getLoad(total) >= 1) {
1274
+ if (edges.getLoad(deletes) >= unloadFactor &&
1275
+ edges.getLoad(count) < unloadFactor) {
1276
+ // If we have a significant number of deletes, reclaim the space.
1277
+ return LinkResult.TooManyDeletes;
1278
+ }
1279
+ else {
1280
+ return LinkResult.EdgesOverloaded;
1281
+ }
1282
+ }
1283
+ if (toNode === null)
1284
+ toNode = nodes.add(to, type);
1285
+ if (fromNode === null)
1286
+ fromNode = nodes.add(from, type);
1287
+ // Add our new edge to its hash bucket.
1288
+ edge = edges.add(hash, from, to, type);
1289
+ // Link this edge to the node's list of incoming edges.
1290
+ let prevIn = nodes.linkIn(toNode, edge);
1291
+ if (prevIn !== null)
1292
+ edges.linkIn(prevIn, edge);
1293
+ // Link this edge to the node's list of outgoing edges.
1294
+ let prevOut = nodes.linkOut(fromNode, edge);
1295
+ if (prevOut !== null)
1296
+ edges.linkOut(prevOut, edge);
1297
+ return LinkResult.EdgeAdded;
1298
+ }
1299
+ // From https://gist.github.com/badboy/6267743#32-bit-mix-functions
1300
+ function hash32shift(key) {
1301
+ key = ~key + (key << 15); // key = (key << 15) - key - 1;
1302
+ key = key ^ (key >> 12);
1303
+ key = key + (key << 2);
1304
+ key = key ^ (key >> 4);
1305
+ key = key * 2057; // key = (key + (key << 3)) + (key << 11);
1306
+ key = key ^ (key >> 16);
1307
+ return key;
1308
+ }
1309
+ function interpolate(x, y, t) {
1310
+ return x + (y - x) * Math.min(1, Math.max(0, t));
1311
+ }
1312
+ function increaseNodeCapacity(currentCapacity, params) {
1313
+ let newCapacity = Math.max(
1314
+ // Make sure we have room for at least 2 more nodes.
1315
+ currentCapacity + 2, Math.ceil(currentCapacity * params.minGrowFactor));
1316
+ if (newCapacity >= NodeTypeMap.MAX_CAPACITY) {
1317
+ if (currentCapacity > NodeTypeMap.MAX_CAPACITY - 2) {
1318
+ throw new Error('Node capacity overflow!');
1319
+ }
1320
+ return NodeTypeMap.MAX_CAPACITY;
1321
+ }
1322
+ return newCapacity;
1323
+ }
1324
+ function increaseEdgeCapacity(currentCapacity, params) {
1325
+ // This is intended to strike a balance between growing the edge capacity
1326
+ // in too small increments, which causes a lot of resizing, and growing
1327
+ // the edge capacity in too large increments, which results in a lot of
1328
+ // wasted memory.
1329
+ let pct = currentCapacity / params.peakCapacity;
1330
+ let growFactor = interpolate(params.maxGrowFactor, params.minGrowFactor, pct);
1331
+ let newCapacity = Math.max(
1332
+ // Make sure we have room for at least one more edge.
1333
+ currentCapacity + 1, Math.ceil(currentCapacity * growFactor));
1334
+ if (newCapacity >= EdgeTypeMap.MAX_CAPACITY) {
1335
+ if (currentCapacity > EdgeTypeMap.MAX_CAPACITY - 1) {
1336
+ throw new Error('Edge capacity overflow!');
1337
+ }
1338
+ return EdgeTypeMap.MAX_CAPACITY;
1339
+ }
1340
+ return newCapacity;
1341
+ }
1342
+ function decreaseEdgeCapacity(currentCapacity, params) {
1343
+ return Math.max(
1344
+ // Make sure we don't shrink the capacity _below_ 2.
1345
+ 2, Math.min(
1346
+ // Make sure we shrink the capacity by at least 1.
1347
+ currentCapacity - 1, Math.ceil(currentCapacity * params.shrinkFactor)));
1348
+ }