@bradensbay/globals-core 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.
- package/README.md +69 -0
- package/dist/src/allocator.d.ts +78 -0
- package/dist/src/allocator.d.ts.map +1 -0
- package/dist/src/allocator.js +211 -0
- package/dist/src/allocator.js.map +1 -0
- package/dist/src/arena.d.ts +81 -0
- package/dist/src/arena.d.ts.map +1 -0
- package/dist/src/arena.js +224 -0
- package/dist/src/arena.js.map +1 -0
- package/dist/src/checksum.d.ts +5 -0
- package/dist/src/checksum.d.ts.map +1 -0
- package/dist/src/checksum.js +35 -0
- package/dist/src/checksum.js.map +1 -0
- package/dist/src/draft.d.ts +48 -0
- package/dist/src/draft.d.ts.map +1 -0
- package/dist/src/draft.js +427 -0
- package/dist/src/draft.js.map +1 -0
- package/dist/src/errors.d.ts +56 -0
- package/dist/src/errors.d.ts.map +1 -0
- package/dist/src/errors.js +69 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/external.d.ts +52 -0
- package/dist/src/external.d.ts.map +1 -0
- package/dist/src/external.js +68 -0
- package/dist/src/external.js.map +1 -0
- package/dist/src/hamt.d.ts +87 -0
- package/dist/src/hamt.d.ts.map +1 -0
- package/dist/src/hamt.js +643 -0
- package/dist/src/hamt.js.map +1 -0
- package/dist/src/history.d.ts +45 -0
- package/dist/src/history.d.ts.map +1 -0
- package/dist/src/history.js +49 -0
- package/dist/src/history.js.map +1 -0
- package/dist/src/index.d.ts +55 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +38 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/inspect.d.ts +74 -0
- package/dist/src/inspect.d.ts.map +1 -0
- package/dist/src/inspect.js +127 -0
- package/dist/src/inspect.js.map +1 -0
- package/dist/src/layout.d.ts +130 -0
- package/dist/src/layout.d.ts.map +1 -0
- package/dist/src/layout.js +149 -0
- package/dist/src/layout.js.map +1 -0
- package/dist/src/liveness.d.ts +48 -0
- package/dist/src/liveness.d.ts.map +1 -0
- package/dist/src/liveness.js +92 -0
- package/dist/src/liveness.js.map +1 -0
- package/dist/src/owner.d.ts +130 -0
- package/dist/src/owner.d.ts.map +1 -0
- package/dist/src/owner.js +368 -0
- package/dist/src/owner.js.map +1 -0
- package/dist/src/reader.d.ts +122 -0
- package/dist/src/reader.d.ts.map +1 -0
- package/dist/src/reader.js +325 -0
- package/dist/src/reader.js.map +1 -0
- package/dist/src/readers.d.ts +60 -0
- package/dist/src/readers.d.ts.map +1 -0
- package/dist/src/readers.js +122 -0
- package/dist/src/readers.js.map +1 -0
- package/dist/src/retained.d.ts +39 -0
- package/dist/src/retained.d.ts.map +1 -0
- package/dist/src/retained.js +99 -0
- package/dist/src/retained.js.map +1 -0
- package/dist/src/schema.d.ts +82 -0
- package/dist/src/schema.d.ts.map +1 -0
- package/dist/src/schema.js +18 -0
- package/dist/src/schema.js.map +1 -0
- package/dist/src/store.d.ts +83 -0
- package/dist/src/store.d.ts.map +1 -0
- package/dist/src/store.js +127 -0
- package/dist/src/store.js.map +1 -0
- package/dist/src/strings.d.ts +37 -0
- package/dist/src/strings.d.ts.map +1 -0
- package/dist/src/strings.js +144 -0
- package/dist/src/strings.js.map +1 -0
- package/dist/src/tags.d.ts +47 -0
- package/dist/src/tags.d.ts.map +1 -0
- package/dist/src/tags.js +53 -0
- package/dist/src/tags.js.map +1 -0
- package/dist/src/values.d.ts +90 -0
- package/dist/src/values.d.ts.map +1 -0
- package/dist/src/values.js +458 -0
- package/dist/src/values.js.map +1 -0
- package/dist/src/vector.d.ts +64 -0
- package/dist/src/vector.d.ts.map +1 -0
- package/dist/src/vector.js +387 -0
- package/dist/src/vector.js.map +1 -0
- package/dist/src/verify.d.ts +38 -0
- package/dist/src/verify.d.ts.map +1 -0
- package/dist/src/verify.js +179 -0
- package/dist/src/verify.js.map +1 -0
- package/dist/src/view.d.ts +66 -0
- package/dist/src/view.d.ts.map +1 -0
- package/dist/src/view.js +278 -0
- package/dist/src/view.js.map +1 -0
- package/package.json +28 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { ArenaCorruptError } from "./errors.js";
|
|
2
|
+
import { ALIGNMENT, BLOCK_CLASS_MASK, BLOCK_HEADER_BYTES, BLOCK_MAGIC, BLOCK_MAGIC_SHIFT, Block, CONFIG_WORDS, Header, LAYOUT_VERSION, MAGIC, WORD, computeGeometry, } from "./layout.js";
|
|
3
|
+
import { hashWords } from "./checksum.js";
|
|
4
|
+
/**
|
|
5
|
+
* A typed view over one shared buffer, plus the bounds checks that make every dereference
|
|
6
|
+
* provably in range.
|
|
7
|
+
*
|
|
8
|
+
* Both the owner and every reader hold one of these. It carries no writer state, so it is
|
|
9
|
+
* safe to construct in a process that must never mutate the arena.
|
|
10
|
+
*/
|
|
11
|
+
export class SharedArena {
|
|
12
|
+
buffer;
|
|
13
|
+
geometry;
|
|
14
|
+
#i32;
|
|
15
|
+
#f64;
|
|
16
|
+
#u16;
|
|
17
|
+
#u8;
|
|
18
|
+
#byteLength;
|
|
19
|
+
constructor(buffer, geometry) {
|
|
20
|
+
this.buffer = buffer;
|
|
21
|
+
this.geometry = geometry;
|
|
22
|
+
this.#i32 = new Int32Array(buffer);
|
|
23
|
+
this.#f64 = new Float64Array(buffer);
|
|
24
|
+
this.#u16 = new Uint16Array(buffer);
|
|
25
|
+
this.#u8 = new Uint8Array(buffer);
|
|
26
|
+
this.#byteLength = buffer.byteLength;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Attach to a buffer an owner has already formatted. Validates the magic, the layout
|
|
30
|
+
* version, and the configuration checksum, so a reader never starts decoding a buffer it
|
|
31
|
+
* does not understand.
|
|
32
|
+
*/
|
|
33
|
+
static attach(buffer) {
|
|
34
|
+
if (buffer.byteLength < 128) {
|
|
35
|
+
throw new ArenaCorruptError("buffer is too small to contain a header", {
|
|
36
|
+
actual: buffer.byteLength,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
const words = new Int32Array(buffer);
|
|
40
|
+
const magic = Atomics.load(words, Header.Magic);
|
|
41
|
+
if (magic !== MAGIC) {
|
|
42
|
+
throw new ArenaCorruptError("buffer does not carry the arena magic", {
|
|
43
|
+
expected: MAGIC,
|
|
44
|
+
actual: magic,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
const version = Atomics.load(words, Header.LayoutVersion);
|
|
48
|
+
if (version !== LAYOUT_VERSION) {
|
|
49
|
+
throw new ArenaCorruptError(`layout version ${version} cannot be read by a build expecting ${LAYOUT_VERSION}`, { expected: LAYOUT_VERSION, actual: version });
|
|
50
|
+
}
|
|
51
|
+
const geometry = computeGeometry(Atomics.load(words, Header.MaxReaders), Atomics.load(words, Header.RetainedCapacity));
|
|
52
|
+
const arena = new SharedArena(buffer, geometry);
|
|
53
|
+
arena.verifyConfigChecksum();
|
|
54
|
+
return arena;
|
|
55
|
+
}
|
|
56
|
+
/** Format a fresh buffer. Only the owner calls this. */
|
|
57
|
+
static format(buffer, options) {
|
|
58
|
+
const geometry = computeGeometry(options.maxReaders, options.retainedCapacity);
|
|
59
|
+
if (buffer.byteLength <= geometry.arenaOffset) {
|
|
60
|
+
throw new ArenaCorruptError(`a buffer of ${buffer.byteLength} bytes cannot hold a header, a table for ` +
|
|
61
|
+
`${options.maxReaders} readers, and a ring of ${options.retainedCapacity} versions`);
|
|
62
|
+
}
|
|
63
|
+
const words = new Int32Array(buffer);
|
|
64
|
+
words.fill(0);
|
|
65
|
+
words[Header.Magic] = MAGIC;
|
|
66
|
+
words[Header.LayoutVersion] = LAYOUT_VERSION;
|
|
67
|
+
words[Header.CapacityBytes] = buffer.byteLength;
|
|
68
|
+
words[Header.MaxReaders] = options.maxReaders;
|
|
69
|
+
words[Header.ReaderTableOffset] = geometry.readerTableOffset;
|
|
70
|
+
words[Header.RetainedRingOffset] = geometry.retainedRingOffset;
|
|
71
|
+
words[Header.RetainedCapacity] = options.retainedCapacity;
|
|
72
|
+
words[Header.ArenaOffset] = geometry.arenaOffset;
|
|
73
|
+
words[Header.BumpPointer] = geometry.arenaOffset;
|
|
74
|
+
words[Header.Flags] = options.flags;
|
|
75
|
+
words[Header.OwnerGeneration] = 1;
|
|
76
|
+
const arena = new SharedArena(buffer, geometry);
|
|
77
|
+
arena.writeConfigChecksum();
|
|
78
|
+
return arena;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The cached views.
|
|
82
|
+
*
|
|
83
|
+
* These do not probe the buffer for growth. Probing here was measurably the most
|
|
84
|
+
* expensive thing on the read path: reading `byteLength` from a growable
|
|
85
|
+
* SharedArrayBuffer is not an inlined field load, and a single bounds checked decode
|
|
86
|
+
* touches these accessors half a dozen times.
|
|
87
|
+
*
|
|
88
|
+
* Growth is picked up by `refresh()` instead, which callers invoke at the one point
|
|
89
|
+
* where a longer view can matter: acquiring a version newer than the one they last saw.
|
|
90
|
+
* Anything a reader decodes through a pinned version was allocated before that version
|
|
91
|
+
* was published, so it is inside the view the reader had when it acquired.
|
|
92
|
+
*/
|
|
93
|
+
get words() {
|
|
94
|
+
return this.#i32;
|
|
95
|
+
}
|
|
96
|
+
get floats() {
|
|
97
|
+
return this.#f64;
|
|
98
|
+
}
|
|
99
|
+
get units() {
|
|
100
|
+
return this.#u16;
|
|
101
|
+
}
|
|
102
|
+
get bytes() {
|
|
103
|
+
return this.#u8;
|
|
104
|
+
}
|
|
105
|
+
get byteLength() {
|
|
106
|
+
return this.#byteLength;
|
|
107
|
+
}
|
|
108
|
+
#refreshIfGrown() {
|
|
109
|
+
if (this.buffer.byteLength === this.#byteLength)
|
|
110
|
+
return;
|
|
111
|
+
this.#byteLength = this.buffer.byteLength;
|
|
112
|
+
this.#i32 = new Int32Array(this.buffer);
|
|
113
|
+
this.#f64 = new Float64Array(this.buffer);
|
|
114
|
+
this.#u16 = new Uint16Array(this.buffer);
|
|
115
|
+
this.#u8 = new Uint8Array(this.buffer);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Header accessors read the cached view directly rather than going through the growth
|
|
119
|
+
* check in `words`.
|
|
120
|
+
*
|
|
121
|
+
* That is safe because the header sits at offset zero and its size is fixed, so it is
|
|
122
|
+
* inside every view this arena has ever had, including one made before a grow(). It is
|
|
123
|
+
* also worth doing: a read touches the header eight times, and routing each of those
|
|
124
|
+
* through a SharedArrayBuffer byteLength getter on a growable buffer cost more than the
|
|
125
|
+
* rest of the read path put together.
|
|
126
|
+
*/
|
|
127
|
+
loadHeader(field) {
|
|
128
|
+
return Atomics.load(this.#i32, field);
|
|
129
|
+
}
|
|
130
|
+
storeHeader(field, value) {
|
|
131
|
+
Atomics.store(this.#i32, field, value);
|
|
132
|
+
}
|
|
133
|
+
addHeader(field, delta) {
|
|
134
|
+
return Atomics.add(this.#i32, field, delta);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Pick up a growth that another process performed. Callers that are about to read arena
|
|
138
|
+
* payload, rather than only the header, call this once rather than paying for the check
|
|
139
|
+
* on every access.
|
|
140
|
+
*/
|
|
141
|
+
refresh() {
|
|
142
|
+
this.#refreshIfGrown();
|
|
143
|
+
}
|
|
144
|
+
/** Bumped when a new owner adopts the buffer. A reader uses it to fail closed. */
|
|
145
|
+
get ownerGeneration() {
|
|
146
|
+
return Atomics.load(this.#i32, Header.OwnerGeneration);
|
|
147
|
+
}
|
|
148
|
+
writeConfigChecksum() {
|
|
149
|
+
const words = this.words;
|
|
150
|
+
words[Header.ConfigChecksum] = this.#configChecksum(words);
|
|
151
|
+
}
|
|
152
|
+
verifyConfigChecksum() {
|
|
153
|
+
const words = this.words;
|
|
154
|
+
const expected = this.#configChecksum(words);
|
|
155
|
+
const actual = words[Header.ConfigChecksum];
|
|
156
|
+
if (expected !== actual) {
|
|
157
|
+
throw new ArenaCorruptError("arena configuration checksum does not match", {
|
|
158
|
+
expected,
|
|
159
|
+
actual,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
#configChecksum(words) {
|
|
164
|
+
const scratch = new Int32Array(CONFIG_WORDS.length);
|
|
165
|
+
CONFIG_WORDS.forEach((field, index) => {
|
|
166
|
+
scratch[index] = words[field];
|
|
167
|
+
});
|
|
168
|
+
const hash = hashWords(scratch, 0, scratch.length);
|
|
169
|
+
return hash === 0 ? 1 : hash;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Prove that `byteCount` bytes at `offset` lie inside the arena region and are aligned.
|
|
173
|
+
* Called before every dereference. A failure means the arena was written by something
|
|
174
|
+
* that is not a correct writer.
|
|
175
|
+
*/
|
|
176
|
+
checkRange(offset, byteCount, what) {
|
|
177
|
+
if (!Number.isInteger(offset) || offset < this.geometry.arenaOffset) {
|
|
178
|
+
throw new ArenaCorruptError(`${what}: offset ${offset} is before the arena region`, {
|
|
179
|
+
offset,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
if (offset % ALIGNMENT !== 0) {
|
|
183
|
+
throw new ArenaCorruptError(`${what}: offset ${offset} is not eight byte aligned`, {
|
|
184
|
+
offset,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
if (byteCount < 0 || offset + byteCount > this.byteLength) {
|
|
188
|
+
throw new ArenaCorruptError(`${what}: ${byteCount} bytes at ${offset} run past the end of the buffer`, { offset, actual: this.byteLength });
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Validate the two word header preceding every allocation and return its payload size.
|
|
193
|
+
* This is the check that turns a wild offset into a typed error rather than a plausible
|
|
194
|
+
* looking value.
|
|
195
|
+
*/
|
|
196
|
+
checkBlock(offset, what) {
|
|
197
|
+
if (!Number.isInteger(offset) || offset - BLOCK_HEADER_BYTES < this.geometry.arenaOffset) {
|
|
198
|
+
throw new ArenaCorruptError(`${what}: no room for a block header at ${offset}`, { offset });
|
|
199
|
+
}
|
|
200
|
+
if (offset % ALIGNMENT !== 0) {
|
|
201
|
+
throw new ArenaCorruptError(`${what}: offset ${offset} is not eight byte aligned`, {
|
|
202
|
+
offset,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
const words = this.words;
|
|
206
|
+
const base = offset / WORD;
|
|
207
|
+
const headerWord = words[base + Block.Header];
|
|
208
|
+
if (headerWord >>> BLOCK_MAGIC_SHIFT !== BLOCK_MAGIC) {
|
|
209
|
+
throw new ArenaCorruptError(`${what}: no block header at ${offset}`, {
|
|
210
|
+
offset,
|
|
211
|
+
expected: BLOCK_MAGIC,
|
|
212
|
+
actual: headerWord >>> BLOCK_MAGIC_SHIFT,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
const byteSize = words[base + Block.ByteSize];
|
|
216
|
+
this.checkRange(offset, byteSize, what);
|
|
217
|
+
return byteSize;
|
|
218
|
+
}
|
|
219
|
+
blockSizeClass(offset) {
|
|
220
|
+
const headerWord = this.words[offset / WORD + Block.Header];
|
|
221
|
+
return headerWord & BLOCK_CLASS_MASK;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=arena.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"arena.js","sourceRoot":"","sources":["../../src/arena.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EACL,SAAS,EACT,gBAAgB,EAChB,kBAAkB,EAClB,WAAW,EACX,iBAAiB,EACjB,KAAK,EACL,YAAY,EACZ,MAAM,EACN,cAAc,EACd,KAAK,EACL,IAAI,EACJ,eAAe,GAEhB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C;;;;;;GAMG;AACH,MAAM,OAAO,WAAW;IACb,MAAM,CAAoB;IAC1B,QAAQ,CAAgB;IAEjC,IAAI,CAAa;IACjB,IAAI,CAAe;IACnB,IAAI,CAAc;IAClB,GAAG,CAAa;IAChB,WAAW,CAAS;IAEpB,YAAoB,MAAyB,EAAE,QAAuB;QACpE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;QACrC,IAAI,CAAC,IAAI,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;QACpC,IAAI,CAAC,GAAG,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;QAClC,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,UAAU,CAAC;IACvC,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,MAAM,CAAC,MAAyB;QACrC,IAAI,MAAM,CAAC,UAAU,GAAG,GAAG,EAAE,CAAC;YAC5B,MAAM,IAAI,iBAAiB,CAAC,yCAAyC,EAAE;gBACrE,MAAM,EAAE,MAAM,CAAC,UAAU;aAC1B,CAAC,CAAC;QACL,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;QACrC,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;QAChD,IAAI,KAAK,KAAK,KAAK,EAAE,CAAC;YACpB,MAAM,IAAI,iBAAiB,CAAC,uCAAuC,EAAE;gBACnE,QAAQ,EAAE,KAAK;gBACf,MAAM,EAAE,KAAK;aACd,CAAC,CAAC;QACL,CAAC;QACD,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC;QAC1D,IAAI,OAAO,KAAK,cAAc,EAAE,CAAC;YAC/B,MAAM,IAAI,iBAAiB,CACzB,kBAAkB,OAAO,wCAAwC,cAAc,EAAE,EACjF,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,CAC9C,CAAC;QACJ,CAAC;QACD,MAAM,QAAQ,GAAG,eAAe,CAC9B,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,UAAU,CAAC,EACtC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,gBAAgB,CAAC,CAC7C,CAAC;QACF,MAAM,KAAK,GAAG,IAAI,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAChD,KAAK,CAAC,oBAAoB,EAAE,CAAC;QAC7B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,wDAAwD;IACxD,MAAM,CAAC,MAAM,CACX,MAAyB,EACzB,OAAwE;QAExE,MAAM,QAAQ,GAAG,eAAe,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAC/E,IAAI,MAAM,CAAC,UAAU,IAAI,QAAQ,CAAC,WAAW,EAAE,CAAC;YAC9C,MAAM,IAAI,iBAAiB,CACzB,eAAe,MAAM,CAAC,UAAU,2CAA2C;gBACzE,GAAG,OAAO,CAAC,UAAU,2BAA2B,OAAO,CAAC,gBAAgB,WAAW,CACtF,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;QACrC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACd,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;QAC5B,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,cAAc,CAAC;QAC7C,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC;QAChD,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC;QAC9C,KAAK,CAAC,MAAM,CAAC,iBAAiB,CAAC,GAAG,QAAQ,CAAC,iBAAiB,CAAC;QAC7D,KAAK,CAAC,MAAM,CAAC,kBAAkB,CAAC,GAAG,QAAQ,CAAC,kBAAkB,CAAC;QAC/D,KAAK,CAAC,MAAM,CAAC,gBAAgB,CAAC,GAAG,OAAO,CAAC,gBAAgB,CAAC;QAC1D,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,QAAQ,CAAC,WAAW,CAAC;QACjD,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,QAAQ,CAAC,WAAW,CAAC;QACjD,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC;QACpC,KAAK,CAAC,MAAM,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;QAElC,MAAM,KAAK,GAAG,IAAI,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAChD,KAAK,CAAC,mBAAmB,EAAE,CAAC;QAC5B,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,GAAG,CAAC;IAClB,CAAC;IAED,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAED,eAAe;QACb,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,KAAK,IAAI,CAAC,WAAW;YAAE,OAAO;QACxD,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC;QAC1C,IAAI,CAAC,IAAI,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACxC,IAAI,CAAC,IAAI,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1C,IAAI,CAAC,IAAI,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACzC,IAAI,CAAC,GAAG,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACzC,CAAC;IAED;;;;;;;;;OASG;IACH,UAAU,CAAC,KAAa;QACtB,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACxC,CAAC;IAED,WAAW,CAAC,KAAa,EAAE,KAAa;QACtC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IACzC,CAAC;IAED,SAAS,CAAC,KAAa,EAAE,KAAa;QACpC,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IAC9C,CAAC;IAED;;;;OAIG;IACH,OAAO;QACL,IAAI,CAAC,eAAe,EAAE,CAAC;IACzB,CAAC;IAED,kFAAkF;IAClF,IAAI,eAAe;QACjB,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,eAAe,CAAC,CAAC;IACzD,CAAC;IAED,mBAAmB;QACjB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACzB,KAAK,CAAC,MAAM,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IAC7D,CAAC;IAED,oBAAoB;QAClB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,cAAc,CAAW,CAAC;QACtD,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;YACxB,MAAM,IAAI,iBAAiB,CAAC,6CAA6C,EAAE;gBACzE,QAAQ;gBACR,MAAM;aACP,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,eAAe,CAAC,KAAiB;QAC/B,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QACpD,YAAY,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YACpC,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,KAAK,CAAW,CAAC;QAC1C,CAAC,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QACnD,OAAO,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/B,CAAC;IAED;;;;OAIG;IACH,UAAU,CAAC,MAAc,EAAE,SAAiB,EAAE,IAAY;QACxD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;YACpE,MAAM,IAAI,iBAAiB,CAAC,GAAG,IAAI,YAAY,MAAM,6BAA6B,EAAE;gBAClF,MAAM;aACP,CAAC,CAAC;QACL,CAAC;QACD,IAAI,MAAM,GAAG,SAAS,KAAK,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,iBAAiB,CAAC,GAAG,IAAI,YAAY,MAAM,4BAA4B,EAAE;gBACjF,MAAM;aACP,CAAC,CAAC;QACL,CAAC;QACD,IAAI,SAAS,GAAG,CAAC,IAAI,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;YAC1D,MAAM,IAAI,iBAAiB,CACzB,GAAG,IAAI,KAAK,SAAS,aAAa,MAAM,iCAAiC,EACzE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,CACpC,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,UAAU,CAAC,MAAc,EAAE,IAAY;QACrC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;YACzF,MAAM,IAAI,iBAAiB,CAAC,GAAG,IAAI,mCAAmC,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;QAC9F,CAAC;QACD,IAAI,MAAM,GAAG,SAAS,KAAK,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,iBAAiB,CAAC,GAAG,IAAI,YAAY,MAAM,4BAA4B,EAAE;gBACjF,MAAM;aACP,CAAC,CAAC;QACL,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACzB,MAAM,IAAI,GAAG,MAAM,GAAG,IAAI,CAAC;QAC3B,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,MAAM,CAAW,CAAC;QACxD,IAAI,UAAU,KAAK,iBAAiB,KAAK,WAAW,EAAE,CAAC;YACrD,MAAM,IAAI,iBAAiB,CAAC,GAAG,IAAI,wBAAwB,MAAM,EAAE,EAAE;gBACnE,MAAM;gBACN,QAAQ,EAAE,WAAW;gBACrB,MAAM,EAAE,UAAU,KAAK,iBAAiB;aACzC,CAAC,CAAC;QACL,CAAC;QACD,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAW,CAAC;QACxD,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;QACxC,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,cAAc,CAAC,MAAc;QAC3B,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,GAAG,KAAK,CAAC,MAAM,CAAW,CAAC;QACtE,OAAO,UAAU,GAAG,gBAAgB,CAAC;IACvC,CAAC;CACF"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function mixWord(hash: number, word: number): number;
|
|
2
|
+
export declare function hashWords(words: Int32Array, start: number, count: number): number;
|
|
3
|
+
export declare function hashString(text: string): number;
|
|
4
|
+
export declare const HASH_SEED = 2166136261;
|
|
5
|
+
//# sourceMappingURL=checksum.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checksum.d.ts","sourceRoot":"","sources":["../../src/checksum.ts"],"names":[],"mappings":"AAWA,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAM1D;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAMjF;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQ/C;AAED,eAAO,MAAM,SAAS,aAAe,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FNV-1a over 32 bit words.
|
|
3
|
+
*
|
|
4
|
+
* Chosen because it is a few instructions per word, needs no table, and is computed once
|
|
5
|
+
* per commit rather than once per read. It detects accidental corruption and buggy writers.
|
|
6
|
+
* It is not a message authentication code, and the trust model says so plainly: a window
|
|
7
|
+
* that can write the arena can also write a matching checksum.
|
|
8
|
+
*/
|
|
9
|
+
const OFFSET_BASIS = 0x811c9dc5;
|
|
10
|
+
const PRIME = 0x01000193;
|
|
11
|
+
export function mixWord(hash, word) {
|
|
12
|
+
let next = Math.imul(hash ^ (word & 0xff), PRIME);
|
|
13
|
+
next = Math.imul(next ^ ((word >>> 8) & 0xff), PRIME);
|
|
14
|
+
next = Math.imul(next ^ ((word >>> 16) & 0xff), PRIME);
|
|
15
|
+
next = Math.imul(next ^ ((word >>> 24) & 0xff), PRIME);
|
|
16
|
+
return next | 0;
|
|
17
|
+
}
|
|
18
|
+
export function hashWords(words, start, count) {
|
|
19
|
+
let hash = OFFSET_BASIS;
|
|
20
|
+
for (let i = 0; i < count; i += 1) {
|
|
21
|
+
hash = mixWord(hash, words[start + i]);
|
|
22
|
+
}
|
|
23
|
+
return hash | 0;
|
|
24
|
+
}
|
|
25
|
+
export function hashString(text) {
|
|
26
|
+
let hash = OFFSET_BASIS;
|
|
27
|
+
for (let i = 0; i < text.length; i += 1) {
|
|
28
|
+
const unit = text.charCodeAt(i);
|
|
29
|
+
hash = Math.imul(hash ^ (unit & 0xff), PRIME);
|
|
30
|
+
hash = Math.imul(hash ^ (unit >>> 8), PRIME);
|
|
31
|
+
}
|
|
32
|
+
return hash | 0;
|
|
33
|
+
}
|
|
34
|
+
export const HASH_SEED = OFFSET_BASIS;
|
|
35
|
+
//# sourceMappingURL=checksum.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checksum.js","sourceRoot":"","sources":["../../src/checksum.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,YAAY,GAAG,UAAU,CAAC;AAChC,MAAM,KAAK,GAAG,UAAU,CAAC;AAEzB,MAAM,UAAU,OAAO,CAAC,IAAY,EAAE,IAAY;IAChD,IAAI,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;IAClD,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;IACtD,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;IACvD,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;IACvD,OAAO,IAAI,GAAG,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAiB,EAAE,KAAa,EAAE,KAAa;IACvE,IAAI,IAAI,GAAG,YAAY,CAAC;IACxB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAClC,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,GAAG,CAAC,CAAW,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,IAAI,GAAG,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,IAAI,IAAI,GAAG,YAAY,CAAC;IACxB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAChC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;QAC9C,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,IAAI,GAAG,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,YAAY,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { SharedArena } from "./arena.js";
|
|
2
|
+
import { type EncodeContext, type Slot } from "./values.js";
|
|
3
|
+
/**
|
|
4
|
+
* A draft, in the style of immer.
|
|
5
|
+
*
|
|
6
|
+
* You mutate it and nothing published moves. On finalisation only the paths you touched are
|
|
7
|
+
* rebuilt: a HAMT assoc copies at most seven nodes, a vector assoc copies one path, and every
|
|
8
|
+
* subtree you did not touch keeps its existing arena offset. That is what makes retaining
|
|
9
|
+
* several versions affordable, and it is the phase 2 exit criterion.
|
|
10
|
+
*
|
|
11
|
+
* What a draft deliberately does not do is alias. Assigning a value you read out of the store
|
|
12
|
+
* into a second position encodes a copy rather than sharing nodes, because sharing would need
|
|
13
|
+
* reference counting to reclaim correctly and every write would pay for a case almost no
|
|
14
|
+
* application has.
|
|
15
|
+
*/
|
|
16
|
+
declare const DELETED: unique symbol;
|
|
17
|
+
declare const STATE: unique symbol;
|
|
18
|
+
type Modification = unknown;
|
|
19
|
+
interface DraftState {
|
|
20
|
+
readonly base: Slot;
|
|
21
|
+
readonly modifications: Map<string | number, Modification>;
|
|
22
|
+
readonly children: Map<string | number, DraftNode>;
|
|
23
|
+
dirty: boolean;
|
|
24
|
+
/** For arrays, the length after modification, when it changed. */
|
|
25
|
+
length: number | undefined;
|
|
26
|
+
}
|
|
27
|
+
export interface DraftNode {
|
|
28
|
+
readonly state: DraftState;
|
|
29
|
+
readonly proxy: unknown;
|
|
30
|
+
}
|
|
31
|
+
export interface DraftContext extends EncodeContext {
|
|
32
|
+
readonly arena: SharedArena;
|
|
33
|
+
}
|
|
34
|
+
export declare function createDraft(context: DraftContext, base: Slot): DraftNode;
|
|
35
|
+
export declare function draftStateOf(value: unknown): DraftState | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Turn a draft back into a slot.
|
|
38
|
+
*
|
|
39
|
+
* A clean draft returns its base slot unchanged, which is how untouched subtrees keep their
|
|
40
|
+
* arena nodes. A dirty one applies its modifications through assoc, so only the copied path
|
|
41
|
+
* is new and every replaced node lands on the retire list.
|
|
42
|
+
*/
|
|
43
|
+
export declare function finalizeState(context: DraftContext, state: DraftState): Slot;
|
|
44
|
+
export declare function emptyObjectSlot(context: DraftContext): Slot;
|
|
45
|
+
export declare function emptyArraySlot(context: DraftContext): Slot;
|
|
46
|
+
export { STATE as DRAFT_STATE, DELETED as DRAFT_DELETED };
|
|
47
|
+
export type { DraftState };
|
|
48
|
+
//# sourceMappingURL=draft.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"draft.d.ts","sourceRoot":"","sources":["../../src/draft.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAoB9C,OAAO,EAKL,KAAK,aAAa,EAClB,KAAK,IAAI,EACV,MAAM,aAAa,CAAC;AAErB;;;;;;;;;;;;GAYG;AAEH,QAAA,MAAM,OAAO,eAA4B,CAAC;AAC1C,QAAA,MAAM,KAAK,eAA+B,CAAC;AAE3C,KAAK,YAAY,GAAG,OAAO,CAAC;AAE5B,UAAU,UAAU;IAClB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,aAAa,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,EAAE,YAAY,CAAC,CAAC;IAC3D,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,EAAE,SAAS,CAAC,CAAC;IACnD,KAAK,EAAE,OAAO,CAAC;IACf,kEAAkE;IAClE,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,YAAa,SAAQ,aAAa;IACjD,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;CAC7B;AAMD,wBAAgB,WAAW,CAAC,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,GAAG,SAAS,CAWxE;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,CAInE;AAwRD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI,CAK5E;AAoHD,wBAAgB,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAE3D;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAE1D;AAED,OAAO,EAAE,KAAK,IAAI,WAAW,EAAE,OAAO,IAAI,aAAa,EAAE,CAAC;AAC1D,YAAY,EAAE,UAAU,EAAE,CAAC"}
|