@graphty/graph-format 0.0.0 → 0.2.0

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.
Files changed (224) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +216 -43
  3. package/dist/graph-format.d.ts +1 -0
  4. package/dist/graph-format.d.ts.map +1 -0
  5. package/dist/graph-format.js +15798 -0
  6. package/dist/graph-format.js.map +1 -0
  7. package/dist/src/builder/arena.d.ts +85 -0
  8. package/dist/src/builder/arena.d.ts.map +1 -0
  9. package/dist/src/builder/arena.js +154 -0
  10. package/dist/src/builder/arena.js.map +1 -0
  11. package/dist/src/builder/compact.d.ts +515 -0
  12. package/dist/src/builder/compact.d.ts.map +1 -0
  13. package/dist/src/builder/compact.js +1553 -0
  14. package/dist/src/builder/compact.js.map +1 -0
  15. package/dist/src/builder/counting-sort.d.ts +96 -0
  16. package/dist/src/builder/counting-sort.d.ts.map +1 -0
  17. package/dist/src/builder/counting-sort.js +430 -0
  18. package/dist/src/builder/counting-sort.js.map +1 -0
  19. package/dist/src/builder/freeze.d.ts +72 -0
  20. package/dist/src/builder/freeze.d.ts.map +1 -0
  21. package/dist/src/builder/freeze.js +548 -0
  22. package/dist/src/builder/freeze.js.map +1 -0
  23. package/dist/src/builder/graph-builder.d.ts +602 -0
  24. package/dist/src/builder/graph-builder.d.ts.map +1 -0
  25. package/dist/src/builder/graph-builder.js +1940 -0
  26. package/dist/src/builder/graph-builder.js.map +1 -0
  27. package/dist/src/builder/options.d.ts +16 -0
  28. package/dist/src/builder/options.d.ts.map +1 -0
  29. package/dist/src/builder/options.js +21 -0
  30. package/dist/src/builder/options.js.map +1 -0
  31. package/dist/src/columns/bitmap.d.ts +96 -0
  32. package/dist/src/columns/bitmap.d.ts.map +1 -0
  33. package/dist/src/columns/bitmap.js +184 -0
  34. package/dist/src/columns/bitmap.js.map +1 -0
  35. package/dist/src/columns/column.d.ts +220 -0
  36. package/dist/src/columns/column.d.ts.map +1 -0
  37. package/dist/src/columns/column.js +2109 -0
  38. package/dist/src/columns/column.js.map +1 -0
  39. package/dist/src/columns/dictionary.d.ts +60 -0
  40. package/dist/src/columns/dictionary.d.ts.map +1 -0
  41. package/dist/src/columns/dictionary.js +102 -0
  42. package/dist/src/columns/dictionary.js.map +1 -0
  43. package/dist/src/columns/growable.d.ts +198 -0
  44. package/dist/src/columns/growable.d.ts.map +1 -0
  45. package/dist/src/columns/growable.js +296 -0
  46. package/dist/src/columns/growable.js.map +1 -0
  47. package/dist/src/columns/infer.d.ts +121 -0
  48. package/dist/src/columns/infer.d.ts.map +1 -0
  49. package/dist/src/columns/infer.js +268 -0
  50. package/dist/src/columns/infer.js.map +1 -0
  51. package/dist/src/columns/remap.d.ts +143 -0
  52. package/dist/src/columns/remap.d.ts.map +1 -0
  53. package/dist/src/columns/remap.js +588 -0
  54. package/dist/src/columns/remap.js.map +1 -0
  55. package/dist/src/columns/table.d.ts +184 -0
  56. package/dist/src/columns/table.d.ts.map +1 -0
  57. package/dist/src/columns/table.js +485 -0
  58. package/dist/src/columns/table.js.map +1 -0
  59. package/dist/src/constants.d.ts +34 -0
  60. package/dist/src/constants.d.ts.map +1 -0
  61. package/dist/src/constants.js +79 -0
  62. package/dist/src/constants.js.map +1 -0
  63. package/dist/src/errors.d.ts +76 -0
  64. package/dist/src/errors.d.ts.map +1 -0
  65. package/dist/src/errors.js +32 -0
  66. package/dist/src/errors.js.map +1 -0
  67. package/dist/src/ids/edge-id-index.d.ts +77 -0
  68. package/dist/src/ids/edge-id-index.d.ts.map +1 -0
  69. package/dist/src/ids/edge-id-index.js +155 -0
  70. package/dist/src/ids/edge-id-index.js.map +1 -0
  71. package/dist/src/ids/node-id-map.d.ts +280 -0
  72. package/dist/src/ids/node-id-map.d.ts.map +1 -0
  73. package/dist/src/ids/node-id-map.js +1139 -0
  74. package/dist/src/ids/node-id-map.js.map +1 -0
  75. package/dist/src/ids/string-store.d.ts +219 -0
  76. package/dist/src/ids/string-store.d.ts.map +1 -0
  77. package/dist/src/ids/string-store.js +526 -0
  78. package/dist/src/ids/string-store.js.map +1 -0
  79. package/dist/src/index.d.ts +30 -0
  80. package/dist/src/index.d.ts.map +1 -0
  81. package/dist/src/index.js +29 -0
  82. package/dist/src/index.js.map +1 -0
  83. package/dist/src/populate/from-csr.d.ts +61 -0
  84. package/dist/src/populate/from-csr.d.ts.map +1 -0
  85. package/dist/src/populate/from-csr.js +706 -0
  86. package/dist/src/populate/from-csr.js.map +1 -0
  87. package/dist/src/populate/from-edge-arrays.d.ts +51 -0
  88. package/dist/src/populate/from-edge-arrays.d.ts.map +1 -0
  89. package/dist/src/populate/from-edge-arrays.js +217 -0
  90. package/dist/src/populate/from-edge-arrays.js.map +1 -0
  91. package/dist/src/populate/from-records.d.ts +51 -0
  92. package/dist/src/populate/from-records.d.ts.map +1 -0
  93. package/dist/src/populate/from-records.js +447 -0
  94. package/dist/src/populate/from-records.js.map +1 -0
  95. package/dist/src/snapshot/derived.d.ts +211 -0
  96. package/dist/src/snapshot/derived.d.ts.map +1 -0
  97. package/dist/src/snapshot/derived.js +1254 -0
  98. package/dist/src/snapshot/derived.js.map +1 -0
  99. package/dist/src/snapshot/graph-meta.d.ts +23 -0
  100. package/dist/src/snapshot/graph-meta.d.ts.map +1 -0
  101. package/dist/src/snapshot/graph-meta.js +159 -0
  102. package/dist/src/snapshot/graph-meta.js.map +1 -0
  103. package/dist/src/snapshot/graph-snapshot.d.ts +509 -0
  104. package/dist/src/snapshot/graph-snapshot.d.ts.map +1 -0
  105. package/dist/src/snapshot/graph-snapshot.js +1247 -0
  106. package/dist/src/snapshot/graph-snapshot.js.map +1 -0
  107. package/dist/src/snapshot/hash.d.ts +90 -0
  108. package/dist/src/snapshot/hash.d.ts.map +1 -0
  109. package/dist/src/snapshot/hash.js +228 -0
  110. package/dist/src/snapshot/hash.js.map +1 -0
  111. package/dist/src/snapshot/queries.d.ts +74 -0
  112. package/dist/src/snapshot/queries.d.ts.map +1 -0
  113. package/dist/src/snapshot/queries.js +131 -0
  114. package/dist/src/snapshot/queries.js.map +1 -0
  115. package/dist/src/snapshot/validate.d.ts +192 -0
  116. package/dist/src/snapshot/validate.d.ts.map +1 -0
  117. package/dist/src/snapshot/validate.js +990 -0
  118. package/dist/src/snapshot/validate.js.map +1 -0
  119. package/dist/src/snapshot/views.d.ts +274 -0
  120. package/dist/src/snapshot/views.d.ts.map +1 -0
  121. package/dist/src/snapshot/views.js +856 -0
  122. package/dist/src/snapshot/views.js.map +1 -0
  123. package/dist/src/types/builder.d.ts +456 -0
  124. package/dist/src/types/builder.d.ts.map +1 -0
  125. package/dist/src/types/builder.js +11 -0
  126. package/dist/src/types/builder.js.map +1 -0
  127. package/dist/src/types/columns.d.ts +615 -0
  128. package/dist/src/types/columns.d.ts.map +1 -0
  129. package/dist/src/types/columns.js +14 -0
  130. package/dist/src/types/columns.js.map +1 -0
  131. package/dist/src/types/index.d.ts +14 -0
  132. package/dist/src/types/index.d.ts.map +1 -0
  133. package/dist/src/types/index.js +11 -0
  134. package/dist/src/types/index.js.map +1 -0
  135. package/dist/src/types/internal.d.ts +172 -0
  136. package/dist/src/types/internal.d.ts.map +1 -0
  137. package/dist/src/types/internal.js +13 -0
  138. package/dist/src/types/internal.js.map +1 -0
  139. package/dist/src/types/snapshot.d.ts +801 -0
  140. package/dist/src/types/snapshot.d.ts.map +1 -0
  141. package/dist/src/types/snapshot.js +14 -0
  142. package/dist/src/types/snapshot.js.map +1 -0
  143. package/dist/src/types/wire.d.ts +196 -0
  144. package/dist/src/types/wire.d.ts.map +1 -0
  145. package/dist/src/types/wire.js +8 -0
  146. package/dist/src/types/wire.js.map +1 -0
  147. package/dist/src/util/mask.d.ts +55 -0
  148. package/dist/src/util/mask.d.ts.map +1 -0
  149. package/dist/src/util/mask.js +71 -0
  150. package/dist/src/util/mask.js.map +1 -0
  151. package/dist/src/util/options.d.ts +22 -0
  152. package/dist/src/util/options.d.ts.map +1 -0
  153. package/dist/src/util/options.js +49 -0
  154. package/dist/src/util/options.js.map +1 -0
  155. package/dist/src/util/shared-buffers.d.ts +42 -0
  156. package/dist/src/util/shared-buffers.d.ts.map +1 -0
  157. package/dist/src/util/shared-buffers.js +52 -0
  158. package/dist/src/util/shared-buffers.js.map +1 -0
  159. package/dist/src/util/typed-array.d.ts +205 -0
  160. package/dist/src/util/typed-array.d.ts.map +1 -0
  161. package/dist/src/util/typed-array.js +289 -0
  162. package/dist/src/util/typed-array.js.map +1 -0
  163. package/dist/src/wire/bytes.d.ts +69 -0
  164. package/dist/src/wire/bytes.d.ts.map +1 -0
  165. package/dist/src/wire/bytes.js +361 -0
  166. package/dist/src/wire/bytes.js.map +1 -0
  167. package/dist/src/wire/carried-views.d.ts +111 -0
  168. package/dist/src/wire/carried-views.d.ts.map +1 -0
  169. package/dist/src/wire/carried-views.js +286 -0
  170. package/dist/src/wire/carried-views.js.map +1 -0
  171. package/dist/src/wire/from-wire.d.ts +144 -0
  172. package/dist/src/wire/from-wire.d.ts.map +1 -0
  173. package/dist/src/wire/from-wire.js +1425 -0
  174. package/dist/src/wire/from-wire.js.map +1 -0
  175. package/dist/src/wire/to-wire.d.ts +171 -0
  176. package/dist/src/wire/to-wire.d.ts.map +1 -0
  177. package/dist/src/wire/to-wire.js +652 -0
  178. package/dist/src/wire/to-wire.js.map +1 -0
  179. package/dist/tsconfig.build.tsbuildinfo +1 -0
  180. package/package.json +72 -7
  181. package/src/builder/arena.ts +192 -0
  182. package/src/builder/compact.ts +1811 -0
  183. package/src/builder/counting-sort.ts +506 -0
  184. package/src/builder/freeze.ts +689 -0
  185. package/src/builder/graph-builder.ts +2264 -0
  186. package/src/builder/options.ts +29 -0
  187. package/src/columns/bitmap.ts +196 -0
  188. package/src/columns/column.ts +2574 -0
  189. package/src/columns/dictionary.ts +114 -0
  190. package/src/columns/growable.ts +350 -0
  191. package/src/columns/infer.ts +285 -0
  192. package/src/columns/remap.ts +663 -0
  193. package/src/columns/table.ts +568 -0
  194. package/src/constants.ts +89 -0
  195. package/src/errors.ts +115 -0
  196. package/src/ids/edge-id-index.ts +179 -0
  197. package/src/ids/node-id-map.ts +1340 -0
  198. package/src/ids/string-store.ts +589 -0
  199. package/src/index.ts +139 -0
  200. package/src/lib-resizable-array-buffer.d.ts +34 -0
  201. package/src/populate/from-csr.ts +802 -0
  202. package/src/populate/from-edge-arrays.ts +257 -0
  203. package/src/populate/from-records.ts +536 -0
  204. package/src/snapshot/derived.ts +1486 -0
  205. package/src/snapshot/graph-meta.ts +167 -0
  206. package/src/snapshot/graph-snapshot.ts +1503 -0
  207. package/src/snapshot/hash.ts +241 -0
  208. package/src/snapshot/queries.ts +136 -0
  209. package/src/snapshot/validate.ts +1108 -0
  210. package/src/snapshot/views.ts +943 -0
  211. package/src/types/builder.ts +480 -0
  212. package/src/types/columns.ts +727 -0
  213. package/src/types/index.ts +14 -0
  214. package/src/types/internal.ts +195 -0
  215. package/src/types/snapshot.ts +886 -0
  216. package/src/types/wire.ts +207 -0
  217. package/src/util/mask.ts +89 -0
  218. package/src/util/options.ts +57 -0
  219. package/src/util/shared-buffers.ts +56 -0
  220. package/src/util/typed-array.ts +371 -0
  221. package/src/wire/bytes.ts +440 -0
  222. package/src/wire/carried-views.ts +327 -0
  223. package/src/wire/from-wire.ts +1690 -0
  224. package/src/wire/to-wire.ts +755 -0
@@ -0,0 +1,207 @@
1
+ /**
2
+ * The wire form of a snapshot (design sections 9.1, 9.2 and 12.2): a JSON-serialisable manifest
3
+ * plus a list of ArrayBuffers. The same object is what postMessage, structuredClone, IndexedDB and
4
+ * the GSNP byte container carry; `buffers` is literally the postMessage transfer list. Absent
5
+ * members are null, never optional (design section 12.1).
6
+ */
7
+
8
+ import { type ColumnMeta, type GraphMeta, type ValidationLevel } from "./columns.js";
9
+ import { type NodeIdMapKind, type SnapshotFlags, type ViewName } from "./snapshot.js";
10
+
11
+ /** Element type of a wire buffer reference: the five typed-array dtypes plus "utf8" for byte stores. */
12
+ export type WireDtype = "u32" | "i32" | "f32" | "f64" | "u8" | "utf8";
13
+
14
+ /**
15
+ * One typed array inside WireSnapshot.buffers (design section 9.1). Validation at level "structure"
16
+ * checks byteOffset % elementSize === 0, byteLength === length * elementSize and that the range lies
17
+ * inside the buffer (E_BAD_SERIALIZATION with details.ref otherwise).
18
+ */
19
+ export interface WireBufferRef {
20
+ /** Index into WireSnapshot.buffers (always 0 inside a byte container). */
21
+ readonly buffer: number;
22
+ /** Byte offset inside the buffer (relative to the buffer region inside a container). */
23
+ readonly byteOffset: number;
24
+ /** Byte length of the array. */
25
+ readonly byteLength: number;
26
+ /** Element type. */
27
+ readonly dtype: WireDtype;
28
+ /** Element count. */
29
+ readonly length: number;
30
+ }
31
+
32
+ /**
33
+ * An Arrow Utf8 store on the wire: u32 offsets plus UTF-8 bytes (string ids, string columns, dictionaries, JSON text).
34
+ */
35
+ export interface WireUtf8 {
36
+ /** rows + 1 offsets. */
37
+ readonly offsets: WireBufferRef;
38
+ /** The concatenated UTF-8 bytes. */
39
+ readonly utf8: WireBufferRef;
40
+ }
41
+
42
+ /**
43
+ * One column on the wire (design section 9.1): the resolved metadata plus the buffers its dtype
44
+ * uses, each null when not applicable. meta.default, options and extra are JSON values with the
45
+ * tagged encoding of design section 5.9 for non-finite numbers.
46
+ */
47
+ export interface WireColumn {
48
+ /** Resolved metadata. */
49
+ readonly meta: ColumnMeta;
50
+ /** Values (numeric dtypes), packed words (bool) or codes (dict); null for string / list / json. */
51
+ readonly data: WireBufferRef | null;
52
+ /** Validity bitmap words; null when every row is set. */
53
+ readonly validity: WireBufferRef | null;
54
+ /** Number of unset rows (recomputed from the bitmap by validation). */
55
+ readonly nullCount: number;
56
+ /** dict only: the dictionary strings. */
57
+ readonly dictionary: WireUtf8 | null;
58
+ /** string only: the Utf8 store. */
59
+ readonly strings: WireUtf8 | null;
60
+ /** list only: rows + 1 offsets into the child. */
61
+ readonly offsets: WireBufferRef | null;
62
+ /** list only: the child column. */
63
+ readonly child: WireColumn | null;
64
+ /** json only: the JSON text of every row as a Utf8 store. */
65
+ readonly jsonText: WireUtf8 | null;
66
+ }
67
+
68
+ /** The arena region inside one wire buffer, so a receiver keeps the one-writeBuffer path (design section 9.1). */
69
+ export interface WireArena {
70
+ /** Index into WireSnapshot.buffers. */
71
+ readonly buffer: number;
72
+ /** Start of the arena inside the buffer. */
73
+ readonly byteOffset: number;
74
+ /** Total padded length of the arena. */
75
+ readonly byteLength: number;
76
+ /** Hot prefix length (design section 10.3). */
77
+ readonly hotByteLength: number;
78
+ }
79
+
80
+ /**
81
+ * The id map on the wire (design section 4.5), one shape for every kind: the members a kind does not
82
+ * use are null. The reverse Map is never serialised; a receiver rebuilds it lazily.
83
+ */
84
+ export interface WireIdMap {
85
+ /** The storage kind. */
86
+ readonly kind: NodeIdMapKind;
87
+ /** Number of ids. */
88
+ readonly size: number;
89
+ /** identity only: id === index + offset; 0 otherwise. */
90
+ readonly offset: number;
91
+ /** dense: u32 ids per index; numeric: f64 ids per index. */
92
+ readonly values: WireBufferRef | null;
93
+ /** mixed: u8 tag per index (0 number, 1 string). */
94
+ readonly tags: WireBufferRef | null;
95
+ /** mixed: f64 per index (0 where string). */
96
+ readonly numbers: WireBufferRef | null;
97
+ /** string / mixed: u32 offsets of the Utf8 store. */
98
+ readonly offsets: WireBufferRef | null;
99
+ /** string / mixed: the UTF-8 bytes. */
100
+ readonly utf8: WireBufferRef | null;
101
+ }
102
+
103
+ /**
104
+ * The JSON-serialisable manifest of a wire snapshot (design section 9.1). Readers refuse a
105
+ * formatVersion or wire major they do not know (E_UNSUPPORTED_VERSION), ignore unknown manifest
106
+ * fields of a newer minor, refuse an unknown column dtype unless unknownColumns is "skip", refuse an
107
+ * unknown id-map kind, and ignore unknown view entries.
108
+ */
109
+ export interface WireManifest {
110
+ /** Discriminator. */
111
+ readonly format: "graphty-snapshot";
112
+ /** Wire [major, minor]. */
113
+ readonly wire: readonly [major: number, minor: number];
114
+ /** The producing package version (masked when golden fixtures are compared). */
115
+ readonly producer: string;
116
+ /** The data-model major. */
117
+ readonly formatVersion: 1;
118
+ /** Whether the graph is directed. */
119
+ readonly directed: boolean;
120
+ /** The four counts. */
121
+ readonly counts: {
122
+ readonly nodes: number;
123
+ readonly edges: number;
124
+ readonly arcs: number;
125
+ readonly selfLoops: number;
126
+ };
127
+ /** The flags (invariant I9). */
128
+ readonly flags: SnapshotFlags;
129
+ /**
130
+ * The core arrays; null for an identity permutation (always, whether or not a getter materialised it), an absent
131
+ * weights array or a zero-length array.
132
+ */
133
+ readonly core: {
134
+ readonly rowPtr: WireBufferRef;
135
+ readonly colIdx: WireBufferRef | null;
136
+ readonly weights: WireBufferRef | null;
137
+ readonly arcToEdge: WireBufferRef | null;
138
+ readonly edgeToArc: WireBufferRef | null;
139
+ };
140
+ /** The arena region when the core lives in one buffer; null otherwise. */
141
+ readonly arena: WireArena | null;
142
+ /** The id map. */
143
+ readonly ids: WireIdMap;
144
+ /** Node columns in declaration order. */
145
+ readonly nodeColumns: readonly WireColumn[];
146
+ /** Edge columns in declaration order. */
147
+ readonly edgeColumns: readonly WireColumn[];
148
+ /** Graph columns in declaration order. */
149
+ readonly graphColumns: readonly WireColumn[];
150
+ /** Extension tables with their own row counts (design section 5.10). */
151
+ readonly extensions: readonly {
152
+ readonly name: string;
153
+ readonly rowCount: number;
154
+ readonly columns: readonly WireColumn[];
155
+ }[];
156
+ /** Graph metadata. */
157
+ readonly meta: GraphMeta;
158
+ /** Cached views included on request: view name -> member name -> buffer; null unless includeViews named some. */
159
+ readonly views: Readonly<Record<string, Readonly<Record<string, WireBufferRef>>>> | null;
160
+ /** Buffer indices that were copied rather than transferred (shared storage, design section 9.1). */
161
+ readonly copied: readonly number[];
162
+ /** The snapshot label. */
163
+ readonly label: string | null;
164
+ }
165
+
166
+ /**
167
+ * The plain-object, transferable, versioned representation of a snapshot: the only cloneable shape (design section
168
+ * 9.1).
169
+ */
170
+ export interface WireSnapshot {
171
+ /** The manifest. */
172
+ readonly manifest: WireManifest;
173
+ /** The buffers the manifest's references index; the postMessage transfer list when produced with transfer: true. */
174
+ readonly buffers: readonly ArrayBuffer[];
175
+ }
176
+
177
+ /** Options of toWire() (design section 9.1). */
178
+ export interface ToWireOptions {
179
+ /**
180
+ * Put only exclusively owned buffers into `buffers` as transferables and copy every shared one (listed in
181
+ * manifest.copied); default false (nothing is transferable).
182
+ */
183
+ readonly transfer?: boolean | undefined;
184
+ /** Cached views to carry; the receiver recomputes the rest. Scalar views are ignored. */
185
+ readonly includeViews?: readonly ViewName[] | undefined;
186
+ /** Whether attribute columns are carried; default true. */
187
+ readonly includeColumns?: boolean | undefined;
188
+ }
189
+
190
+ /** Options of toBytes() and toByteChunks() (design section 9.2). */
191
+ export interface ToBytesOptions {
192
+ /** Cached views to carry. */
193
+ readonly includeViews?: readonly ViewName[] | undefined;
194
+ }
195
+
196
+ /** Options of fromWire(), fromBytes() and fromByteChunks() (design sections 9.1 and 9.2). */
197
+ export interface FromWireOptions {
198
+ /** Validation level; default "structure" for fromWire, "full" for fromBytes. */
199
+ readonly validate?: ValidationLevel | undefined;
200
+ /** Copy the buffers instead of adopting them; default false. */
201
+ readonly copy?: boolean | undefined;
202
+ /**
203
+ * What to do with a column whose dtype the reader does not know; default "error" (E_UNSUPPORTED); "skip" drops it
204
+ * and records the name in meta.extra["graphty.skippedColumns"].
205
+ */
206
+ readonly unknownColumns?: "error" | "skip" | undefined;
207
+ }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * The public packed-mask helpers of design section 7.4 (makeMask, maskTest, maskSet, maskCount,
3
+ * maskToIndices) plus the E_MASK_LENGTH check that filterEdges() and inducedSubgraph({ mask }) apply
4
+ * to a caller's mask. A NodeMask / EdgeMask is the same layout as a validity bitmap and a bool column
5
+ * (decision C13): ceil(length / 32) Uint32Array words, LSB-first, bit i set means index i is included.
6
+ * Masks are not part of the snapshot contract; no kernel is required to honour one.
7
+ */
8
+
9
+ import {
10
+ bitmapCount,
11
+ bitmapGet,
12
+ bitmapToIndices,
13
+ bitmapWordCount,
14
+ bitmapWrite,
15
+ makeBitmap,
16
+ } from "../columns/bitmap.js";
17
+ import { GraphFormatError } from "../errors.js";
18
+ import { type U32 } from "../types/index.js";
19
+
20
+ /**
21
+ * Allocate a packed mask over `length` indices: ceil(length / 32) words, every bit clear, or every bit
22
+ * below `length` set when `fill` is true (design section 7.4).
23
+ * @param length - the number of indices the mask covers (nodeCount, edgeCount or arcCount)
24
+ * @param fill - the initial value of every bit; defaults to false
25
+ * @returns the mask words
26
+ */
27
+ export function makeMask(length: number, fill?: boolean): U32 {
28
+ return makeBitmap(length, fill === true);
29
+ }
30
+
31
+ /**
32
+ * Whether index i is in the mask.
33
+ * @param mask - the mask words
34
+ * @param i - the index, below the mask's length
35
+ * @returns true when bit i is set
36
+ */
37
+ export function maskTest(mask: U32, i: number): boolean {
38
+ return bitmapGet(mask, i);
39
+ }
40
+
41
+ /**
42
+ * Include or exclude index i.
43
+ * @param mask - the mask words
44
+ * @param i - the index, below the mask's length
45
+ * @param value - true to include, false to exclude
46
+ */
47
+ export function maskSet(mask: U32, i: number, value: boolean): void {
48
+ bitmapWrite(mask, i, value);
49
+ }
50
+
51
+ /**
52
+ * The number of included indices below `length` (the loop guard of an algorithm-owned alive mask,
53
+ * design section 7.4).
54
+ * @param mask - the mask words, at least ceil(length / 32) of them
55
+ * @param length - the number of indices the mask covers
56
+ * @returns the number of set bits in [0, length)
57
+ */
58
+ export function maskCount(mask: U32, length: number): number {
59
+ return bitmapCount(mask, length);
60
+ }
61
+
62
+ /**
63
+ * The included indices below `length` in ascending order, as a fresh U32.
64
+ * @param mask - the mask words, at least ceil(length / 32) of them
65
+ * @param length - the number of indices the mask covers
66
+ * @returns the set bit indices
67
+ */
68
+ export function maskToIndices(mask: U32, length: number): U32 {
69
+ return bitmapToIndices(mask, length);
70
+ }
71
+
72
+ /**
73
+ * Check that a caller-supplied mask has enough words for `length` indices; filterEdges() and
74
+ * inducedSubgraph({ mask }) call it before reading the mask (design section 11.2). Throws
75
+ * E_MASK_LENGTH when mask.length < ceil(length / 32).
76
+ * @param mask - the mask words
77
+ * @param length - the number of indices the mask must cover
78
+ * @param what - what the mask is over, for the message ("edges", "nodes")
79
+ */
80
+ export function checkMaskLength(mask: U32, length: number, what: string): void {
81
+ const required = bitmapWordCount(length);
82
+ if (mask.length < required) {
83
+ throw new GraphFormatError(
84
+ "E_MASK_LENGTH",
85
+ `mask over ${what} has ${mask.length} words; ${required} needed for ${length} ${what}`,
86
+ { found: mask.length, required, length },
87
+ );
88
+ }
89
+ }
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Enum-valued option checking (design section 11.1): a value outside its documented set is refused
3
+ * with E_UNSUPPORTED (`details.field`, `details.found`, `details.reason` "unsupported option") at
4
+ * the call, never taken as a default. Every public entry point that reads an enum option -- the
5
+ * builder constructor and freeze overrides, the derived graphs, `degreeOrder`, `validate`,
6
+ * `set`, `indicesOf`, `fromRecords`, `foldArcs` -- goes through here, so typed callers see no change
7
+ * and an untyped caller's typo is an error rather than a silently different result.
8
+ */
9
+
10
+ import { GraphFormatError } from "../errors.js";
11
+
12
+ /**
13
+ * Check that an option value is one of the allowed literals (undefined is accepted and returned so
14
+ * the caller applies its default).
15
+ * @param field - the option name for the error
16
+ * @param value - the value
17
+ * @param allowed - the documented literals
18
+ * @returns the value, narrowed
19
+ */
20
+ export function assertOneOf<T extends string>(field: string, value: unknown, allowed: readonly T[]): T | undefined {
21
+ if (value === undefined) {
22
+ return undefined;
23
+ }
24
+ if (typeof value !== "string" || !(allowed as readonly string[]).includes(value)) {
25
+ throw new GraphFormatError(
26
+ "E_UNSUPPORTED",
27
+ `option ${field} has an unsupported value ${describeOption(value)}`,
28
+ {
29
+ field,
30
+ found: value,
31
+ reason: "unsupported option",
32
+ },
33
+ );
34
+ }
35
+ return value as T;
36
+ }
37
+
38
+ /**
39
+ * A plain-ASCII rendering of an option value for an error message.
40
+ * @param value - the value
41
+ * @returns the rendering
42
+ */
43
+ function describeOption(value: unknown): string {
44
+ if (typeof value === "string") {
45
+ return JSON.stringify(value.length > 40 ? `${value.slice(0, 37)}...` : value);
46
+ }
47
+ if (typeof value === "number" || typeof value === "boolean" || value === null) {
48
+ return String(value);
49
+ }
50
+ return `a ${typeof value}`;
51
+ }
52
+
53
+ /** The WeightReducer literals (design section 7.3). */
54
+ export const WEIGHT_REDUCERS = ["first", "last", "sum", "min", "max"] as const;
55
+
56
+ /** The ColumnReducer literals (design section 7.3). */
57
+ export const COLUMN_REDUCERS = [...WEIGHT_REDUCERS, "mean", "count", "drop"] as const;
@@ -0,0 +1,56 @@
1
+ /**
2
+ * The conservative owner count of design section 9.1. The format shares storage deliberately:
3
+ * `withColumns()` shares the core, same-node-space derived graphs share the node table and the id
4
+ * map, `clone()` and `set(name, column)` share Column objects between tables, `transpose()` adopts
5
+ * the cached reverse arrays as its core. Every holder of a buffer, column, table or id map claims it
6
+ * once (the snapshot and table constructors do so); a target claimed by more than one holder is
7
+ * SHARED, and `toWire({ transfer: true })` / `transferables()` copy its buffers instead of
8
+ * transferring them, so no sibling snapshot is ever silently emptied. The count is never decremented
9
+ * (conservative: a holder that is garbage-collected still counts, which only ever causes a copy).
10
+ *
11
+ * Holders are tracked at three granularities because a shared holder materialises buffers lazily
12
+ * (the Utf8 store of a string column or a string id map, the Float64Array of a numeric id map): a
13
+ * buffer, a Column (or a NodeIdMap) and an AttributeTable. The wire module treats a buffer as shared
14
+ * when the buffer itself, the column that holds it or the table that holds the column is shared.
15
+ * This module is a leaf (it imports nothing) so every module may use it without a cycle.
16
+ */
17
+
18
+ /** Target (ArrayBuffer, Column, AttributeTable or NodeIdMap) -> number of holders recorded. */
19
+ const HOLDERS = new WeakMap<object, number>();
20
+
21
+ /**
22
+ * Record one holder of a buffer, column, table or id map. Called by every constructor that keeps a
23
+ * reference to storage it did not allocate itself; the second claim of the same target marks it
24
+ * shared.
25
+ * @param target - the buffer, Column, AttributeTable or NodeIdMap now held
26
+ */
27
+ export function claimHolder(target: object): void {
28
+ HOLDERS.set(target, (HOLDERS.get(target) ?? 0) + 1);
29
+ }
30
+
31
+ /**
32
+ * Record that a target has gained another holder (design section 9.1), so it is treated as shared
33
+ * from now on whatever its previous count.
34
+ * @param target - the buffer, Column, AttributeTable or NodeIdMap that is now held by more than one holder
35
+ */
36
+ export function noteShared(target: object): void {
37
+ HOLDERS.set(target, Math.max(HOLDERS.get(target) ?? 0, 1) + 1);
38
+ }
39
+
40
+ /**
41
+ * The number of holders recorded for a target.
42
+ * @param target - the buffer, Column, AttributeTable or NodeIdMap
43
+ * @returns the count, 0 when never claimed
44
+ */
45
+ export function holderCount(target: object): number {
46
+ return HOLDERS.get(target) ?? 0;
47
+ }
48
+
49
+ /**
50
+ * Whether a target has been recorded as held by more than one holder.
51
+ * @param target - the buffer, Column, AttributeTable or NodeIdMap
52
+ * @returns true when at least two holders were recorded
53
+ */
54
+ export function isShared(target: object): boolean {
55
+ return (HOLDERS.get(target) ?? 0) > 1;
56
+ }